I'm designing an interface using java swing. There is a canvas for the user to draw shapes (circle, triangle, square, etc.). When the user draws a shape, I want to name each point in the shape alphabetically. I know how to get the coordinates but how do I name the points?
Here is one way to do it. You use Character.toString(char) and use 'A'+offset to get any char from the alphabet.
See in this small demo example, which draws polygons.
Single click creates vertices of your polygon
Double-click stores the current polygon and starts creating a new polygon
Right-click clears the current polygon and starts a new one.
Side-note: positioning of the text is not smart, so it overlaps lines of the polygon sometimes.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestNaming {
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 600;
public static class Drawing extends JPanel {
private static final Font FONT = new Font("Arial", Font.PLAIN, 12);
private List<Polygon> polygons = new ArrayList<Polygon>();
private Polygon currentPolygon = new Polygon();
private MouseAdapter mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
if (e.getClickCount() == 1) {
addPoint(e.getX(), e.getY());
} else if (e.getClickCount() == 2) {
createPolygon();
}
} else if (SwingUtilities.isRightMouseButton(e)) {
clearCurrentPolygon();
}
}
};
public Drawing() {
addMouseListener(mouseListener);
}
protected void addPoint(int x, int y) {
currentPolygon.addPoint(x, y);
repaint();
}
protected void clearCurrentPolygon() {
currentPolygon = new Polygon();
repaint();
}
protected void createPolygon() {
if (currentPolygon.npoints > 2) {
polygons.add(currentPolygon);
}
clearCurrentPolygon();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.setFont(FONT);
for (Polygon polygon : polygons) {
drawPolygon(g, polygon);
}
g.setColor(Color.GREEN);
drawPolygon(g, currentPolygon);
}
private void drawPolygon(Graphics g, Polygon polygon) {
if (polygon.npoints < 3) {
if (polygon.npoints == 1) {
g.fillOval(polygon.xpoints[0] - 2, polygon.ypoints[0] - 2, 4, 4);
drawNthPoint(g, polygon, 0);
} else if (polygon.npoints == 2) {
g.drawLine(polygon.xpoints[0], polygon.ypoints[0], polygon.xpoints[1], polygon.ypoints[1]);
drawNthPoint(g, polygon, 0);
drawNthPoint(g, polygon, 1);
}
} else {
g.drawPolygon(polygon);
for (int i = 0; i < polygon.npoints; i++) {
drawNthPoint(g, polygon, i);
}
}
}
private void drawNthPoint(Graphics g, Polygon polygon, int nth) {
// Only works 26 times!
String name = Character.toString((char) ('A' + nth));
int x = polygon.xpoints[nth];
int height = g.getFontMetrics().getHeight();
int y = polygon.ypoints[nth] < height ? polygon.ypoints[nth] + height : polygon.ypoints[nth];
g.drawString(name, x, y);
}
}
protected static void initUI() {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Drawing());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
If I'm understanding you correctly, you want to label the coordinates alphabetically (like A, B, C, D)
Since you said you know the coordinates already...use a JLabel:
JLabel A_label = new JLabel("A");
JLabel B_label = new JLabel("B");
A_label.setLocation(shape1_x, shape1_y);
B_label.setLocation(shape2_x, shape2_y);
Related
I have a JFrame with a subclass, Paint_Panel. Paint_Panel extends JPanel and implements a MouseListener.
I need to place three circles with mouse clicks. No problem. I have a button (Draw) that should draw lines from each circle's center to the other (thus - a triangle). I can maintain the coordinates within an ArrayList - no problem. However, when I try to reference the ArrayList by clicking the button, the list is returned empty. The Array isn't in memory at the time it is needed to draw the lines. Thoughts?
Note- Circles are hard-coded at 40.
Code:
public class Paint_Panel extends JPanel implements MouseListener {
public static int flag = 0;
boolean drawCircles = false;
boolean drawLines = false;
private final ArrayList<Point> points = new ArrayList<>();
public Paint_Panel() {
addMouseListener(this);
}
//Method to draw lines from point to point
public void drawLines() {
Graphics g = getGraphics();
drawLines = true;
paintComponent(g);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawCircles) {
for (int i = 0; i < points.size(); i++) {
//Circle number 1
g.setColor(Color.RED);
g.fillOval(points.get(0).x - 20, points.get(0).y - 20, 40, 40);
//Circle number 2
if (points.size() >= 2) {
g.setColor(Color.GREEN);
g.fillOval(points.get(1).x - 20, points.get(1).y - 20, 40, 40);
}
//Circle number 3
if (points.size() >= 3) {
g.setColor(Color.BLUE);
g.fillOval(points.get(2).x - 20, points.get(2).y - 20, 40, 40);
}
}
} else if (drawLines) {
g.setColor(Color.BLACK); //Set line color
g.drawLine(points.get(0).x, points.get(0).y, points.get(1).x, points.get(1).y);
g.drawLine(points.get(1).x, points.get(1).y, points.get(2).x, points.get(2).y);
g.drawLine(points.get(2).x, points.get(2).y, points.get(0).x, points.get(0).y);
}
}
public void mouseClicked(MouseEvent evt) { //Place circles for click event
Graphics g = getGraphics();
if (!drawCircles) {
prevX = evt.getX() - 20; //Allows placement at center. Size - radius
prevY = evt.getY() - 20;
points.add(evt.getPoint()); //Add point to ArrayList
if (flag < 3) { //Keep track of how many circles are placed
flag += 1;
drawCircles = true;
paintComponent(g);
} else if (flag == 3) { //If additional circles attempted, inform user
flag = 4;
System.out.println("Only 3 circles allowed."); //Debug
drawCircles = false;
}
}
drawCircles = false;
}
#Override
public void mousePressed(MouseEvent evt) { //Unused
}
#Override
public void mouseReleased(MouseEvent evt) { //Unused
}
#Override
public void mouseEntered(MouseEvent evt) { //Unused
}
#Override
public void mouseExited(MouseEvent evt) { //Unused
}
}
Here's one way to draw 3 circles and 3 lines. Edited to draw the circles first, then the lines. Edited again to check for an invalid button press.
I separated the view and controller logic.
Here's the runnable code.
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CirclePaintTest implements Runnable {
private JFrame frame;
private PaintPanel paintPanel;
#Override
public void run() {
frame = new JFrame("Circle Paint Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
paintPanel = new PaintPanel();
mainPanel.add(paintPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
JButton lineButton = new JButton("Draw Lines");
lineButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if (paintPanel.isComplete()) {
paintPanel.setDrawLines(true);
paintPanel.repaint();
}
}
});
buttonPanel.add(lineButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new CirclePaintTest());
}
public class PaintPanel extends JPanel {
private static final long serialVersionUID = 6481890334304291711L;
private final Color[] colors = { Color.RED, Color.GREEN, Color.BLUE,
Color.ORANGE, Color.CYAN, Color.YELLOW };
private boolean drawLines;
private final int pointLimit;
private final List<Point> points;
public PaintPanel() {
this.points = new ArrayList<Point>();
this.pointLimit = 3;
this.drawLines = false;
this.addMouseListener(new CircleMouseListener());
this.setPreferredSize(new Dimension(400, 400));
}
public void setDrawLines(boolean drawLines) {
this.drawLines = drawLines;
}
public boolean isComplete() {
return points.size() >= pointLimit;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Point pp = null;
Point p0 = null;
for (int i = 0; i < points.size(); i++) {
g.setColor(colors[i]);
Point p = points.get(i);
g.fillOval(p.x - 20, p.y - 20, 40, 40);
pp = p;
}
if (drawLines && (points.size() > 1)) {
p0 = points.get(0);
pp = p0;
g.setColor(Color.BLACK);
for (int i = 1; i < points.size(); i++) {
Point p = points.get(i);
g.drawLine(pp.x, pp.y, p.x, p.y);
pp = p;
}
g.drawLine(pp.x, pp.y, p0.x, p0.y);
}
}
public class CircleMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent event) {
if (points.size() < pointLimit) {
points.add(event.getPoint());
PaintPanel.this.repaint();
}
}
}
}
}
You don't call repaint when flag equals 3, so there is no call to the paintComponent method with the right condition (drawCircles false and drawLines true).
I suggest you to call repaint either when flag equals to 3 or and the end of mouseClicked.
I'm doing a program involving the Pythagorean theorem, and wanted to leave a triangle in the middle, with three JTextField around three sides of it. I did it, but the problem is that when I create the JTextField and add it to the desired container, it is immense. It is a very large white rectangle that when I click to enter, get a small letter. So, my question is: How can I change the size of this JTextField to decrease it and avoid unnecessary sizes?
P.S:.'m Using Swing and AWT library for free!
Example of code:
Container content = window.getContentPane();
Contaiiner grid = new JPanel();
grid.setLayout(new GridLayout(3,3));
grid.add(new JTextField());
Well, this simple code, gives to you one example of the JTextField, when i executes than (with main method and more...) the JTextField is very very big, so, i want to decrease it.
Admittedly, it involves some guesses about your intention, but here is an example of what I think that you want to achieve:
It's a program that contains a panel with some points, and between each pair of points, it places a text field. The text fields are arranged so that their upper left corner remains at the center of the respective edge. When the points are dragged with the mouse, the locations of the text fields are updated accordingly. (In this example, the text fields contain the distance between the points - that is, the edge lengths - but this is just for illustration).
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TriangleTextFieldsTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new TriangleTextFieldsTest();
}
});
}
public TriangleTextFieldsTest()
{
JFrame frame = new JFrame();
frame.getContentPane().add(new TriangleTextFieldsPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,800);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class TriangleTextFieldsPanel extends JPanel
implements MouseListener, MouseMotionListener
{
private final List<Point2D> points;
private final List<JTextField> textFields;
private Point2D draggedPoint = null;
TriangleTextFieldsPanel()
{
super(null);
points = new ArrayList<Point2D>();
points.add(new Point2D.Double(250,250));
points.add(new Point2D.Double(750,250));
points.add(new Point2D.Double(500,500));
textFields = new ArrayList<JTextField>();
for (int i=0; i<points.size(); i++)
{
JTextField t = new JTextField(10);
textFields.add(t);
add(t);
}
updateTextFieldPositions();
updateTextFieldContents();
addMouseListener(this);
addMouseMotionListener(this);
}
private void updateTextFieldPositions()
{
for (int i=0; i<points.size(); i++)
{
Point2D p0 = points.get(i);
Point2D p1 = points.get((i+1)%points.size());
JTextField textField = textFields.get(i);
int cx = (int)(0.5 * (p1.getX() + p0.getX()));
int cy = (int)(0.5 * (p1.getY() + p0.getY()));
Dimension d = textField.getPreferredSize();
textField.setBounds(cx, cy, d.width, d.height);
}
}
private void updateTextFieldContents()
{
for (int i=0; i<points.size(); i++)
{
Point2D p0 = points.get(i);
Point2D p1 = points.get((i+1)%points.size());
JTextField textField = textFields.get(i);
double d = p0.distance(p1);
textField.setText(String.format("%.2f", d));
}
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLUE);
drawPoints(g, points);
g.setColor(Color.BLACK);
for (int i=0; i<points.size(); i++)
{
Point2D p0 = points.get(i);
Point2D p1 = points.get((i+1)%points.size());
g.draw(new Line2D.Double(p0,p1));
}
}
static void drawPoints(Graphics2D g, List<Point2D> points)
{
double r = 3;
for (Point2D point : points)
{
double x = point.getX();
double y = point.getY();
g.fill(new Ellipse2D.Double(
x-r, y-r, r+r, r+r));
}
}
#Override
public void mouseDragged(MouseEvent e)
{
if (draggedPoint != null)
{
draggedPoint.setLocation(e.getPoint());
updateTextFieldPositions();
updateTextFieldContents();
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e)
{
}
#Override
public void mouseClicked(MouseEvent e)
{
}
#Override
public void mousePressed(MouseEvent e)
{
draggedPoint = null;
double thresholdSquared = 10*10;
double minDs = Double.MAX_VALUE;
for (Point2D point : points)
{
double ds = point.distanceSq(e.getPoint());
if (ds < thresholdSquared && ds < minDs)
{
minDs = ds;
draggedPoint = point;
}
}
}
#Override
public void mouseReleased(MouseEvent e)
{
draggedPoint = null;
}
#Override
public void mouseEntered(MouseEvent e)
{
}
#Override
public void mouseExited(MouseEvent e)
{
}
}
I'm not sure how I would fix the errors in my program and how I would highlight the option the user is hovering on. I want it to highlight the code for each position, i.e position 1 would be highlighted(as a different color) to start game,etc. and up/down would change position and I would change the position with up ,down, left, right. This is what I have so far. At the moment its bugged and when compiled with my window it comes out as:
Which works for the main game and altered for this titleboard, what am I doing wrong and how do I fix it?
TitleBoard class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
//sound + file opening
import java.io.*;
import javax.sound.sampled.*;
public class TitleBoard extends JPanel implements ActionListener{
private ArrayList<String> OptionList;
private Image background;
private ImageIcon bgImageIcon;
private String cheatString;
private int position;
private Timer timer;
public TitleBoard(){
setFocusable(true);
addKeyListener(new TAdapter());
bgImageIcon = new ImageIcon("");
background = bgImageIcon.getImage();
String[] options = {"Start Game","Options","Quit"};
OptionList = new ArrayList<String>();
optionSetup(options);
position = 1;
timer = new Timer(8, this);
timer.start();
/*
1 mod 3 =>1 highlight on start
2 mod 3 =>2 highlight on options
3 mod 3 =>0 highlight on quit
*/
try{
Font numFont = Font.createFont(Font.TRUETYPE_FONT,new File("TwistedStallions.ttf"));
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(numFont);
setFont(numFont.deriveFont(24f)); //adjusthislater
}catch(IOException|FontFormatException e){
e.printStackTrace();
}
}
private void optionSetup(String[] s){
for(int i=0; i<s.length;i++) {
OptionList.add(s[i]);
}
}
public void paint(Graphics g){
super.paint(g);
Graphics g2d = (Graphics2D)g;
g2d.drawImage(background,0,0,this);
for (int i=0;i<OptionList.size();i++){
g2d.drawString(OptionList.get(i),200,120+120*i);
}/*
g2d.drawString(OptionList.get(1),400,240);
g2d.drawString(OptionList.get(2),400,360);
//instructions on start screen maybe??
//800x500
//highlighting*/
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e){
repaint();
}
public class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP||
e.getKeyCode() == KeyEvent.VK_RIGHT){
position++;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN||
e.getKeyCode() == KeyEvent.VK_LEFT){
position--;
}
}
}
}
Window Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window extends JFrame{
public Window(){
int width = 800, height = 600;
//TO DO: make a panel in TITLE MODE
///////////////////////////////////
//panel in GAME MODE.
add(new TitleBoard());
//set default close
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
//centers window
setLocationRelativeTo(null);
setTitle("Title");
setResizable(false);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
}
There are any number of ways you might achieve this, for example, you could use some kind of delegation model.
That is, rather then trying to mange of each element in a single method (or methods), you could devise a delegate which provide a simple interface method that the paint method would call and it would know how to do the rest.
For example, Swing uses this type of concept with it's cell renderers for JList, JTable and JTree.
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyAwesomeMenu {
public static void main(String[] args) {
new MyAwesomeMenu();
}
public MyAwesomeMenu() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<String> menuItems;
private String selectMenuItem;
private String focusedItem;
private MenuItemPainter painter;
private Map<String, Rectangle> menuBounds;
public TestPane() {
setBackground(Color.BLACK);
painter = new SimpleMenuItemPainter();
menuItems = new ArrayList<>(25);
menuItems.add("Start Game");
menuItems.add("Options");
menuItems.add("Exit");
selectMenuItem = menuItems.get(0);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
String newItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
newItem = text;
break;
}
}
if (newItem != null && !newItem.equals(selectMenuItem)) {
selectMenuItem = newItem;
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e) {
focusedItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
focusedItem = text;
repaint();
break;
}
}
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "arrowDown");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "arrowUp");
am.put("arrowDown", new MenuAction(1));
am.put("arrowUp", new MenuAction(-1));
}
#Override
public void invalidate() {
menuBounds = null;
super.invalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (menuBounds == null) {
menuBounds = new HashMap<>(menuItems.size());
int width = 0;
int height = 0;
for (String text : menuItems) {
Dimension dim = painter.getPreferredSize(g2d, text);
width = Math.max(width, dim.width);
height = Math.max(height, dim.height);
}
int x = (getWidth() - (width + 10)) / 2;
int totalHeight = (height + 10) * menuItems.size();
totalHeight += 5 * (menuItems.size() - 1);
int y = (getHeight() - totalHeight) / 2;
for (String text : menuItems) {
menuBounds.put(text, new Rectangle(x, y, width + 10, height + 10));
y += height + 10 + 5;
}
}
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
boolean isSelected = text.equals(selectMenuItem);
boolean isFocused = text.equals(focusedItem);
painter.paint(g2d, text, bounds, isSelected, isFocused);
}
g2d.dispose();
}
public class MenuAction extends AbstractAction {
private final int delta;
public MenuAction(int delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
int index = menuItems.indexOf(selectMenuItem);
if (index < 0) {
selectMenuItem = menuItems.get(0);
}
index += delta;
if (index < 0) {
selectMenuItem = menuItems.get(menuItems.size() - 1);
} else if (index >= menuItems.size()) {
selectMenuItem = menuItems.get(0);
} else {
selectMenuItem = menuItems.get(index);
}
repaint();
}
}
}
public interface MenuItemPainter {
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused);
public Dimension getPreferredSize(Graphics2D g2d, String text);
}
public class SimpleMenuItemPainter implements MenuItemPainter {
public Dimension getPreferredSize(Graphics2D g2d, String text) {
return g2d.getFontMetrics().getStringBounds(text, g2d).getBounds().getSize();
}
#Override
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused) {
FontMetrics fm = g2d.getFontMetrics();
if (isSelected) {
paintBackground(g2d, bounds, Color.BLUE, Color.WHITE);
} else if (isFocused) {
paintBackground(g2d, bounds, Color.MAGENTA, Color.BLACK);
} else {
paintBackground(g2d, bounds, Color.DARK_GRAY, Color.LIGHT_GRAY);
}
int x = bounds.x + ((bounds.width - fm.stringWidth(text)) / 2);
int y = bounds.y + ((bounds.height - fm.getHeight()) / 2) + fm.getAscent();
g2d.setColor(isSelected ? Color.WHITE : Color.LIGHT_GRAY);
g2d.drawString(text, x, y);
}
protected void paintBackground(Graphics2D g2d, Rectangle bounds, Color background, Color foreground) {
g2d.setColor(background);
g2d.fill(bounds);
g2d.setColor(foreground);
g2d.draw(bounds);
}
}
}
For here, you could add ActionListener
When a GUI needs a button, use a JButton! The JButton API allows the possibility to add icons for many different circumstances. This example shows different icons for the standard icon, the hover icon, and the pressed icon. Your GUI would obviously use icons with text on them for the required effect.
The icons are pulled directly (hot-linked) from Example images for code and mark-up Q&As.
Standard
Hover over triangle
Press triangle
Code
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;
public class IconHoverFocusIndication {
// the GUI as seen by the user (without frame)
// swap the 1 and 0 for single column
JPanel gui = new JPanel(new GridLayout(1,0,50,50));
public static final int GREEN = 0, YELLOW = 1, RED = 2;
String[][] urls = {
{
"http://i.stack.imgur.com/T5uTa.png",
"http://i.stack.imgur.com/IHARa.png",
"http://i.stack.imgur.com/wCF8S.png"
},
{
"http://i.stack.imgur.com/gYxHm.png",
"http://i.stack.imgur.com/8BGfi.png",
"http://i.stack.imgur.com/5v2TX.png"
},
{
"http://i.stack.imgur.com/1lgtq.png",
"http://i.stack.imgur.com/6ZXhi.png",
"http://i.stack.imgur.com/F0JHK.png"
}
};
IconHoverFocusIndication() throws Exception {
// adjust to requirement..
gui.setBorder(new EmptyBorder(15, 30, 15, 30));
gui.setBackground(Color.BLACK);
Insets zeroMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < 3; ii++) {
JButton b = new JButton();
b.setBorderPainted(false);
b.setMargin(zeroMargin);
b.setContentAreaFilled(false);
gui.add(b);
URL url1 = new URL(urls[ii][GREEN]);
BufferedImage bi1 = ImageIO.read(url1);
b.setIcon(new ImageIcon(bi1));
URL url2 = new URL(urls[ii][YELLOW]);
BufferedImage bi2 = ImageIO.read(url2);
b.setRolloverIcon(new ImageIcon(bi2));
URL url3 = new URL(urls[ii][RED]);
BufferedImage bi3 = ImageIO.read(url3);
b.setPressedIcon(new ImageIcon(bi3));
}
}
public JComponent getGUI() {
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
IconHoverFocusIndication ihfi =
new IconHoverFocusIndication();
JFrame f = new JFrame("Button Icons");
f.add(ihfi.getGUI());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
I am using JButton's Action listener to draw different shapes.To keep previously drawn shapes on panel all time, I've used an arraylist in which all drawn shapes has added and repaint whole list.How can I drag any shape while others display on Jpanel all the time?
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("====>>> " + s);
switch (s) {
case "Button1":
Activity act = new Activity();
act.setArcH(15);
act.setArcW(15);
act.setBreadth(40);
act.setLength(50);
act.setXpoint(x);
act.setYpoint(y);
//==========================================================
obj = new ShapePoints();
obj.setShapeId(ShapesID.ROUND_RECTANGLE_ID);
obj.setxPoint(act.getXpoint());
obj.setyPoint(act.getYpoint());
obj.setLength(act.getLength());
obj.setBreadth(act.getBreadth());
obj.setArcW(act.getArcW());
obj.setArcH(act.getArcH());
shapePoints.add(obj);
Iterator itr = shapePoints.iterator();
while (itr.hasNext()) {
ShapePoints sp = (ShapePoints) itr.next();
switch (sp.getShapeId()) {
case ShapesID.ARROW_ID:
break;
case ShapesID.CIRCLE_ID:
g.drawOval(obj.getxPoint(), obj.getyPoint(), obj.getLength(), obj.getBreadth());
break;
case ShapesID.CON_CIRCLE_ID:
g.drawOval(sp.getxPoint(), sp.getyPoint(), sp.getLength(), sp.getLength());
g.fillOval(sp.getxPoint() + 10, sp.getyPoint() + 10, sp.getBreadth() / 2, sp.getBreadth() / 2);
break;
case ShapesID.RECTANGLE_ID:
break;
case ShapesID.ROUND_RECTANGLE_ID:
g.drawRoundRect(obj.getxPoint(), obj.getyPoint(), obj.getLength(), obj.getBreadth(),
obj.getArcW(), obj.getArcH());
break;
}
}
break;
this is for 1 button
You need to add a mouselistener and a mousemotionlistener (usually you make a single instance for both) and check wheter your shape contains the mouse pressed event or not. If yes, you keep track of where the mouse is dragged to translate your shape and continuously call repaint(), like usual.
Single click creates a vertex of a polygon
Double click creates the current drawn polygon (if it has at least 3 vertices) and we create a new one
Right-click clears the current drawn polygon and creates a new one
Press/Drag/Release moves the polygon located under the mouse (if there are several, it takes the first one found. it would probably better to make a reverse for-loop)
Here is an example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestNaming {
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 600;
public static class Drawing extends JPanel {
private static final Font FONT = new Font("Arial", Font.PLAIN, 12);
private List<Polygon> polygons = new ArrayList<Polygon>();
private Polygon currentPolygon = new Polygon();
private MouseAdapter mouseListener = new MouseAdapter() {
private Polygon dragged;
private Point lastLocation;
#Override
public void mousePressed(java.awt.event.MouseEvent e) {
for (Polygon p : polygons) {
if (p.contains(e.getPoint())) {
dragged = p;
lastLocation = e.getPoint();
break;
}
}
}
#Override
public void mouseDragged(java.awt.event.MouseEvent e) {
if (dragged != null) {
dragged.translate(e.getX() - lastLocation.x, e.getY() - lastLocation.y);
lastLocation = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(java.awt.event.MouseEvent e) {
dragged = null;
lastLocation = null;
}
#Override
public void mouseClicked(java.awt.event.MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
if (e.getClickCount() == 1) {
addPoint(e.getX(), e.getY());
} else if (e.getClickCount() == 2) {
createPolygon();
}
} else if (SwingUtilities.isRightMouseButton(e)) {
clearCurrentPolygon();
}
}
};
public Drawing() {
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
}
protected void addPoint(int x, int y) {
currentPolygon.addPoint(x, y);
repaint();
}
protected void clearCurrentPolygon() {
currentPolygon = new Polygon();
repaint();
}
protected void createPolygon() {
if (currentPolygon.npoints > 2) {
polygons.add(currentPolygon);
}
clearCurrentPolygon();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.setFont(FONT);
for (Polygon polygon : polygons) {
drawPolygon(g, polygon);
}
g.setColor(Color.GREEN);
drawPolygon(g, currentPolygon);
}
private void drawPolygon(Graphics g, Polygon polygon) {
if (polygon.npoints < 3) {
if (polygon.npoints == 1) {
g.fillOval(polygon.xpoints[0] - 2, polygon.ypoints[0] - 2, 4, 4);
drawNthPoint(g, polygon, 0);
} else if (polygon.npoints == 2) {
g.drawLine(polygon.xpoints[0], polygon.ypoints[0], polygon.xpoints[1], polygon.ypoints[1]);
drawNthPoint(g, polygon, 0);
drawNthPoint(g, polygon, 1);
}
} else {
g.drawPolygon(polygon);
for (int i = 0; i < polygon.npoints; i++) {
drawNthPoint(g, polygon, i);
}
}
}
private void drawNthPoint(Graphics g, Polygon polygon, int nth) {
// Only works 26 times!
String name = Character.toString((char) ('A' + nth));
int x = polygon.xpoints[nth];
int height = g.getFontMetrics().getHeight();
int y = polygon.ypoints[nth] < height ? polygon.ypoints[nth] + height : polygon.ypoints[nth];
Rectangle2D stringBounds = g.getFontMetrics().getStringBounds(name, g);
g.drawString(name, x, y);
}
}
protected static void initUI() {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Drawing());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
I'm trying to build a custom triangle component that has the same features as a JComponent (like a JButton per say).
The porpoise of the program will be to add triangle on a mouse click exactly where the mouse is and to handle a mouseover event by highlighting the bg of the shape.
I let the default layouts(or null), because while using others, the applications just doesn't place the triangles where I want...
Right now my major issue is how to adjust the size of the triangles with direct proportionality relative to the form size? So that if I reduce the frame size 50% all the components are down that value as well.
One other issue is that the JComponent requires a rectangular area to handle events, for what I've seen there's no way countering this, so if I try to click on the affected area it will just ignore it instead of creating a new triangle there.
And yet another problem is that sometimes while moving out of the triangle from the bottom it is still green.
Thanks!
Here is the SSCCE:
// TriangleCustom.java
package TriangleCustom;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TriangleCustom {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Triangle");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1200, 800);
Panel p = new Panel();
f.add(p);
f.setVisible(true);
}
}
class Panel extends JPanel {
// the offsets are the area (rect border) to contain the triangle shape
private final int xOFFSET = 25;
private final int yOFFSET = 50;
ArrayList<TriangleShape> triangleAL = new ArrayList<TriangleShape>();
public Panel() {
setBounds(0, 0, 800, 400);
// setBorder(BorderFactory.createLineBorder(Color.black,2));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
addTriangle(new Point(e.getX(), e.getY()), new Point(e.getX()
- xOFFSET, e.getY() + yOFFSET), new Point(e.getX()
+ xOFFSET, e.getY() + yOFFSET));
}
});
}
private void addTriangle(Point topCorner, Point leftCorner,
Point rightCorner) {
final TriangleDTO tdto = new TriangleDTO(new Point(25, 0), new Point(0,
50), new Point(50, 50));
TriangleShape ts = new TriangleShape(tdto);
ts.setBorderColor(Color.BLACK);
ts.setFillColor(Color.RED);
ts.setBounds((int) (topCorner.getX() - 25), (int) topCorner.getY(), 51,
51);
triangleAL.add(ts);
this.add(ts);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.draw(new Rectangle2D.Double(0, 0, 799, 399));
}
}
// the custom component in a shape of a triangle
class TriangleShape extends JComponent {
private GeneralPath triangle = new GeneralPath();
private TriangleDTO tdto = new TriangleDTO();
private Color borderColor = new Color(0);
private Color fillColor = new Color(0);
// Constructor
public TriangleShape(TriangleDTO tdto) {
this.tdto = tdto;
triangle.moveTo(tdto.getTopCorner().getX(), tdto.getTopCorner().getY());
triangle.lineTo(tdto.getLeftCorner().getX(), tdto.getLeftCorner()
.getY());
triangle.lineTo(tdto.getRightCorner().getX(), tdto.getRightCorner()
.getY());
triangle.closePath();
addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
// there are some issues when going out of the triangle from
// bottom
if (triangle.contains((Point2D) e.getPoint())) {
setFillColor(Color.GREEN);
repaint();
} else {
setFillColor(Color.RED);
repaint();
}
}
});
}
public void setBorderColor(Color borderColor) {
this.borderColor = borderColor;
}
public void setFillColor(Color fillColor) {
this.fillColor = fillColor;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(fillColor);
g2d.fill(triangle);
g2d.setPaint(borderColor);
g2d.draw(triangle);
}
}
// just a plain DTO for the triangle points
class TriangleDTO {
private Point topCorner = new Point();
private Point leftCorner = new Point();
private Point rightCorner = new Point();
// Constructors
public TriangleDTO() {
}
public TriangleDTO(Point topCorner, Point leftCorner, Point rightCorner) {
super();
this.topCorner = topCorner;
this.leftCorner = leftCorner;
this.rightCorner = rightCorner;
}
// Getters and Setters
public Point getTopCorner() {
return topCorner;
}
public void setTopCorner(Point topCorner) {
this.topCorner = topCorner;
}
public Point getLeftCorner() {
return leftCorner;
}
public void setLeftCorner(Point leftCorner) {
this.leftCorner = leftCorner;
}
public Point getRightCorner() {
return rightCorner;
}
public void setRightCorner(Point rightCorner) {
this.rightCorner = rightCorner;
}
}