I have followed peeskillet and changed my codes according to his last idea. Here are the changed codes
CriclePanel class
public class CirclePanel extends JPanel {
int centerX, centerY, radius;
Color circle_color;
public void setCircle(int centerX, int centerY, int radius, Color c) {
this.centerX = centerX;
this.centerY = centerY;
this.radius = radius;
circle_color = c;
revalidate();
repaint();
}
protected void paintComponent(Graphics g) {
System.out.println("Trying to draw circle");
super.paintComponent(g);
g.fillOval(centerX, centerY, radius*2, radius*2);
}
}
Grid Panel (added from palette and custom constructed)
myGridPanel = new JPanel(new GridLayout(8,8));
panels = new CirclePanel[8][8];
for (int i = 0; i < panels.length; i++) {
for (int j = 0; j < panels[i].length; j++) {
CirclePanel panel = new CirclePanel();
panels[i][j] = panel;
myGridPanel.add(panel);
}
}
Trying to add draw circle:
if(dType==DiceType.blackDice){
System.err.println("black #"+i+","+j);
panels[i][j].setCircle(x, y, radius, Color.BLACK);
}else{
System.err.println("white #"+i+","+j);
panels[i][j].setCircle(x, y, radius, Color.WHITE);
}
But the circles are not drawn on the grid panel and there is no grid also on the mother panel "myGridPanel". I am seeing that the paintComponant() of CirclePanel is not being called.
Output: http://s25.postimg.org/v8u398dun/no_Gridnd_Circle.png
As I mentioned in the comments, you can Refine your Design by not making every Circle a panel. Here is an example
Another option that would fit for your current design, would be to have a setter in each circle panel, for which you can pass a circle model.
public class CirclePanel extends JPanel {
private Circle circle;
public void setCircle(Circle cirlce) {
this.circle = circle;
repaint();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (circle != null) {
// get the state from circle and paint
g.fillOval(circle.getX(), circle.getY(), getWidth(), getHeight());
}
}
}
Note: Circle in this case is not a panel
Then for the gridPanel give it a GridLayout and add all the CirclePanel to it.
JPanel gridPanel = new JPanel(new GridLayout(5, 5));
CirclePanel[][] panels = new CirclePanel[5][5];
for (int i = 0; i < panels.length; i++) {
for (int j = 0; j < panels[i].length; j++) {
CirclePanel panel = new CirclePanel();
panels[i][j] = panel;
gridPanels.add(panel);
}
}
Doing this, there will be empty CirclePanel in the gridPanel. Then when you want to paint a circle in one of the panels, you can do something like
Circle circle = new Circle(...);
panels[1][1].setCircle(circle);
UPDATE
Or now that I think about it, you don't even really need a Circle class, since you could just draw the circle a 0, 0, getWidth(), getHeight(). You could simple set a flag to draw. But if you want to add more state to the circle, then maybe you could keep a circle class. But if not, it might look something like
public class CirclePanel extends JPanel {
private boolean draw;
private Color color;
// setter for color
// setter for draw
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (draw) {
// get the state from circle and paint
g.fillOval(0, 0, getWidth(), getHeight());
}
}
}
Update with example
See the method setDraw. That's where I set the flag the draw or not draw. I call it in the mouse listener in the Circle class, but you can call it from anywhere.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CircleDemo {
private static final int GRID_SIZE = 5;
private Circle[][] circlePanels
= new Circle[GRID_SIZE][GRID_SIZE];
private JPanel gridPanel
= new JPanel(new GridLayout(GRID_SIZE, GRID_SIZE));
public CircleDemo() {
initCircles();
JFrame f = new JFrame();
f.add(gridPanel);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private void initCircles() {
for (int i = 0; i < circlePanels.length; i++) {
for (int j = 0; j < circlePanels[i].length; j++) {
Circle circle = new Circle();
circlePanels[i][j] = circle;
gridPanel.add(circle);
}
}
}
class Circle extends JPanel {
private boolean draw = false;
private Color color = Color.BLUE;
public Circle() {
setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e) {
if (isDraw()) {
setDraw(false);
} else {
setDraw(true);
}
}
});
}
public boolean isDraw() {
return draw;
}
public void setDraw(boolean draw) {
this.draw = draw;
repaint();
}
public void setColor(Color color) {
this.color = color;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(75, 75);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (draw) {
g.setColor(color);
g.fillOval(0, 0, getWidth(), getHeight());
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new CircleDemo();
}
});
}
}
Related
I am attempting to use jsliders to allow a user to pinpoint the origin of a circle to be drawn on a canvas. I am using a button to show and hide the circle. I am using paint on an inner jpanel so that paint will not write over components. However, the coordinates inside the jpanel are different than the coordinates for the entire frame. So, it is very difficult for me to get the coordinates of the jslider and then translate it to the jpanel to draw the circle. Is there an easy way to figure this out without a ton of guess and check? I am also using the custom layout miglayout. I have included the code for my GUI class as well as my custom JPanel I made so I could mess with the paint method.
public class CircleGUI extends JFrame implements ActionListener {
private MigLayout layout = new MigLayout();
private CustomPanel innerpanel;
private JSlider x,y;
private JColorChooser colorpick;
private JButton state;
private boolean bstate;
CircleGUI() {
initialize();
}
private void initialize() {
Border blackline = BorderFactory.createLineBorder(Color.black);
bstate = false;
x = new JSlider(JSlider.HORIZONTAL,650,325);
x.setPaintTicks(true);
x.setPaintLabels(true);
x.setPreferredSize(new Dimension(650,0));
y = new JSlider(JSlider.HORIZONTAL,650,325);
y.setPaintTicks(true);
y.setPaintLabels(true);
y.setInverted(true);
y.setOrientation(JSlider.VERTICAL);
y.setPreferredSize(new Dimension (0,600));
colorpick = new JColorChooser();
state = new JButton("Show");
state.addActionListener(e -> {
if(!bstate) {
int positionx = x.getValue() - 80;
int positiony = y.getValue();
Color c = colorpick.getColor();
innerpanel.setColor(c);
innerpanel.setX(positionx);
innerpanel.setY(positiony);
innerpanel.repaint();
state.setText("Hide");
bstate = true;
} else {
Color transparent = new Color(0,0,0,0);
innerpanel.setColor(transparent);
innerpanel.repaint();
state.setText("Show");
bstate = false;
}
});
JPanel outerpanel = new JPanel(layout);
innerpanel = new CustomPanel();
innerpanel.setPreferredSize(new Dimension(600,600));
innerpanel.setBorder(blackline);
outerpanel.add(x,"wrap");
outerpanel.add(y,"split 2");
outerpanel.add(innerpanel);
outerpanel.add(state,"wrap");
outerpanel.add(colorpick);
this.setSize(1000, 1000);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(outerpanel);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
public class CustomPanel extends JPanel implements ActionListener {
private Color c;
private int x;
private int y;
public CustomPanel() {
c = null;
}
#Override
public void actionPerformed (ActionEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(c);
g2.fill(new Ellipse2D.Double(x, y, 100, 100));
}
public void setColor(Color c) {
this.c = c;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
Your problem is you are trying to make a one-to-one mapping between the value of the JSlider and the coordinate in your CustomPanel. You should use the JSlider value as a percentage, i.e. minimum value zero and maximum value 100. If you want the circle to appear in the middle of the CustomPanel so you place both JSliders in their mid-points, i.e. both at 50%. Then you calculate 50% of the corresponding dimension to get the coordinate. If the width of CustomPanel is 600, then 50% of 600 is 300 so positionx needs to be 300.
The only thing I changed in your code is the calculation of positionx and positiony.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.border.Border;
import net.miginfocom.swing.MigLayout;
public class CircleGUI extends JFrame implements ActionListener {
private MigLayout layout = new MigLayout();
private CustomPanel innerpanel;
private JSlider x,y;
private JColorChooser colorpick;
private JButton state;
private boolean bstate;
CircleGUI() {
initialize();
}
private void initialize() {
Border blackline = BorderFactory.createLineBorder(Color.black);
bstate = false;
// x = new JSlider(JSlider.HORIZONTAL, 650, 325);
x = new JSlider(0, 100, 10);
x.setPaintTicks(true);
x.setPaintLabels(true);
x.setPreferredSize(new Dimension(650, 0));
// y = new JSlider(JSlider.HORIZONTAL, 650, 325);
y = new JSlider(0, 100, 10);
y.setPaintTicks(true);
y.setPaintLabels(true);
y.setInverted(true);
y.setOrientation(JSlider.VERTICAL);
y.setPreferredSize(new Dimension(0, 600));
colorpick = new JColorChooser();
state = new JButton("Show");
state.addActionListener(e -> {
if (!bstate) {
int positionx = Math.round(x.getValue() / 100.0f * innerpanel.getSize().width) - 50;
int positiony = Math.round(y.getValue() / 100.0f * innerpanel.getSize().height) - 50;
Color c = colorpick.getColor();
innerpanel.setColor(c);
innerpanel.setX(positionx);
innerpanel.setY(positiony);
innerpanel.repaint();
state.setText("Hide");
bstate = true;
}
else {
Color transparent = new Color(0, 0, 0, 0);
innerpanel.setColor(transparent);
innerpanel.repaint();
state.setText("Show");
bstate = false;
}
});
JPanel outerpanel = new JPanel(layout);
innerpanel = new CustomPanel();
innerpanel.setPreferredSize(new Dimension(600, 600));
innerpanel.setBorder(blackline);
outerpanel.add(x, "wrap");
outerpanel.add(y, "split 2");
outerpanel.add(innerpanel);
outerpanel.add(state, "wrap");
outerpanel.add(colorpick);
this.setSize(1000, 1000);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(outerpanel);
}
#Override
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
CircleGUI cg = new CircleGUI();
cg.setVisible(true);
});
}
}
class CustomPanel extends JPanel implements ActionListener {
private Color c;
private int x;
private int y;
public CustomPanel() {
c = null;
}
#Override
public void actionPerformed(ActionEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(c);
g2.fill(new Ellipse2D.Double(x, y, 100, 100));
}
public void setColor(Color c) {
this.c = c;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
I want to accomplish something very similar to the image a Rectangle whit a Selector Line.
Basically, I have a Rectangle and I want to have a selector line all around it.
For that, I wanted to create an additional JComponent.
At the moment I can only draw the Rectangle. How could I get the parentPanel JPanel inside the Rectangle class, so that I could add the selector?
public class TestPanel extends JFrame {
public class Rectangle extends JComponent {
public Rectangle(){
setBounds(x1, y1, x2, y2);
JPanel Selector = new JPanel();
//Adds Selector to parentPanel within Rectangle
//setBounds(x1-1, y1-1, x2+1, y2+1)
//!Problem parent is initially null! cant even a use property
//Life hacks?
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, getWidth(), getHeight());
}
}
public TestPanel() {
Rectangle Rectangle = new Rectangle();
JPanel parentFrame = new JPanel();
parentFrame.add(Rectangle);
setSize(200, 200);
setVisible(true);
}
public static void main(String[] args) {
new TestPanel();
}
}
If I try to add the selector inside the rectangle, it will get out of the drawing area. If I resize the drawing area, it won't be scalable for later development.
If possible I would avoid dual binding like:
public TestPanel() {
Rectangle Rectangle = new Rectangle();
JPanel parentPanel = new JPanel();
parentPanel.add(Rectangle);
Rectangle.addParent(parentPanel)
...
}
Again, I'm not 100% clear on what you're trying to achieve. If what you wish to create is a user-created dashed line, one that can change with mouse press/drag/release, then you don't need to create a new component but rather use a MouseAdapter as a MouseListener and MouseMotionListener, all to help you create the Rectangle, and then simply draw the Rectangle with a dashed line using an appropriate Stroke, as per this answer.
For example, something like would create a dashed line that is user-selectable:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class SelectorPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Stroke DASHED_STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 5 }, 0);
private static final Color DASHED_COLOR = Color.LIGHT_GRAY;
private Rectangle rectangle = null;
public SelectorPanel() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
private class MyMouse extends MouseAdapter {
private Point p1 = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
rectangle = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 != null) {
createRectangle(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p1 != null) {
createRectangle(e);
p1 = null;
}
}
private void createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int width = Math.abs(p1.x - p2.x);
int height = Math.abs(p1.y - p2.y);
rectangle = new Rectangle(x, y, width, height);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(DASHED_COLOR);
g2.setStroke(DASHED_STROKE);
g2.draw(rectangle);
g2.dispose();
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SelectorPanel mainPanel = new SelectorPanel();
JFrame frame = new JFrame("SelectorPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I'm writing minesweeper and I want to put ovals on mine cells after a mine is clicked. But for now, I just want to put ovals on all cells just to check. I have written the code below. But when I run the program there is no ovals on buttons. I can not see the reason. I would be grateful if I get some suggestions.
public class Cell extends JButton{
...
public void painComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.orange);
g.drawOval(0,0,25,25);
}
public void draw() {
repaint();
}
...
}
public class Grid extends JPanel implements MouseListener{
...
public Grid(){
this.setLayout(new GridLayout(20,20));
cells = new Cell[20][20];
for(int i=0; i<20; i++) {
for(int j=0; j<20; j++) {
cells[i][j] = new Cell(i,j);
cells[i][j].addMouseListener(this);
cells[i][j].draw();
this.add(cells[i][j]);
}
}
plantMines();
setVisible(true);
}
...
}
but when I run the program there is no ovals on buttons.
public void painComponent(Graphics g) {
You made a typo. You spelt "paint" wrong.
When you override a method you should use:
#Override
protected void paintComponent(Graphics g)
This way if you make a typo the compiler will tell you that you are not overriding a method of the class.
Also, don't attempt to draw the oval by using custom painting. Instead you should be adding an Icon to the button. Then you can just change the Icon as required.
You can easily create an simple Icon to use. Here is an example of creating a square Icon:
import java.awt.*;
import javax.swing.*;
public class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI()
{
JPanel panel = new JPanel( new GridLayout(2, 2) );
for (int i = 0; i < 4; i++)
{
Icon icon = new ColorIcon(Color.RED, 50, 50);
JLabel label = new JLabel( icon );
label.setText("" + i);
label.setHorizontalTextPosition(JLabel.CENTER);
label.setVerticalTextPosition(JLabel.CENTER);
panel.add(label);
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(panel);
f.setSize(200, 200);
f.setLocationRelativeTo( null );
f.setVisible(true);
}
}
I'm trying to draw multiple rectangles on a panel. I created an ArrayList<Shape> and initialized in my constructor. In my paintComponent method, I draw a rectangle and then add it to the ArrayList. But when I do that, the drawing outcome on my panel turns out weird. As I drag to draw my first rectangle, I get this:
Here's part of my code:
public class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(final MouseEvent theEvent) {
myStartPoint = theEvent.getPoint();
repaint();
}
#Override
public void mouseReleased(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
public class MyMouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
/**
* Paints some rectangles.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
// for better graphics display
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(51, 0, 111));
g2d.setStroke(new BasicStroke(3));
final double x = myStartPoint.getX();
final double y = myStartPoint.getY();
final double xEnd = myEndPoint.getX();
final double yEnd = myEndPoint.getY();
if (xEnd> x && yEnd > y) {
final Shape rectangle = new Rectangle2D.
Double(x, y, xEnd - x, yEnd - y);
g2d.draw(rectangle);
myDrawings.add(rectangle);
}
for (Shape s : myDrawings) {
g2d.draw(s);
}
}
Don't do any code logic within paintComponent -- that method is for drawing and drawing only, and that is the source of your bug. Add the rectangle to the ArrayList in the mouse listener, on mouse release.
When I have done a similar project, I usually have one Rectangle field that I use to draw with the mouse listener on mouse drag, and which is draw within paintComponent. Then on mouse release I place that rectangle into the ArrayList, and set the class field as null.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class RectangleDraw extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color TEMP_RECT_COLOR = Color.LIGHT_GRAY;
private static final Color SHAPE_COLOR = Color.RED;
private Rectangle tempRect = null;
private List<Shape> shapes = new ArrayList<>();
public RectangleDraw() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw the temporary rectangle if not null
if (tempRect != null) {
g2.setColor(TEMP_RECT_COLOR);
g2.draw(tempRect);
}
// draw all the rectangles in the list
g2.setColor(SHAPE_COLOR);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
// size the GUI to my specification
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
// My mouse listener and mouse motion listener
private class MyMouse extends MouseAdapter {
private Point p1; // start point
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
// create temporary rectangle
tempRect = createRectangle(e);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempRect = null; // null temp rectangle and
// add rectangle to List
shapes.add(createRectangle(e));
repaint();
}
// create a rectangle from start point and current point
private Rectangle createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
Rectangle rect = new Rectangle(x, y, w, h);
return rect;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Rectangle Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RectangleDraw());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I have a problem in my application using line primitives and JLables. I try to explain it:
I have to draw a vehicle route using lines to represent roads and JLabels to represent cities. I need the use of JLabels because each JLabel has a Listener that shows a dialog with information about the city.
I redefine paint() method of my main JPanel. In that method I first in invoke the super.paint(), then I draw the lines and finally I add the Labels to the JPanel.
The problem is that the lines overlap the labels regardless the matter the order of painting them. Is there any suggestion?
You can also override paintComponent() or paintChildren() methods of the JPanel.
In the paintChildren() call your lines drawing and then super to draw JLabels.
anothe way should be
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class AddVertexDemo {
public AddVertexDemo() {
}
private static void createAndShowUI() {
JFrame frame = new JFrame("AddVertexDemo");
frame.getContentPane().add(new Gui().getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowUI();
}
});
}
}
class DrawingPanel extends JPanel {
private static final int RADIUS = 6;
private static final long serialVersionUID = 1L;
private List<Shape> vertexList = new ArrayList<Shape>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (vertexList.size() > 1) {
Shape s0 = vertexList.get(0);
Shape s1 = null;
for (int i = 0; i < vertexList.size(); i++) {
s1 = vertexList.get(i);
drawConnectingLine(g, s0, s1);
s0 = s1;
}
s1 = vertexList.get(0);
//drawConnectingLine(g2, s0, s1);
}
for (Shape shape : vertexList) {
g2.setColor(Color.blue);
g2.fill(shape);
g2.setColor(Color.blue.darker().darker());
g2.draw(shape);
}
}
private void drawConnectingLine(Graphics g, Shape s0, Shape s1) {
Rectangle r0 = s0.getBounds();
Rectangle r1 = s1.getBounds();
int x0 = r0.x + r0.width / 2;
int y0 = r0.y + r0.height / 2;
int x1 = r1.x + r1.width / 2;
int y1 = r1.y + r1.height / 2;
g.drawLine(x0, y0, x1, y1);
}
public void addVertex(Point p) {
int x = p.x - RADIUS;
int y = p.y - RADIUS;
int w = 2 * RADIUS;
int h = w;
vertexList.add(new Ellipse2D.Double(x, y, w, h));
repaint();
}
public void removeVertex(Point p) {
if (vertexList.size() > 0) {
for (int i = vertexList.size() - 1; i >= 0; i--) {
if (vertexList.get(i).contains(p)) {
vertexList.remove(i);
repaint();
return;
}
}
}
}
}
class Gui {
private static final Dimension DRAWING_PANEL_SIZE = new Dimension(600, 500);
private JPanel mainPanel = new JPanel(new BorderLayout());
private DrawingPanel drawingPanel = new DrawingPanel();
private JToggleButton addVertexBtn = new JToggleButton("Add Vertex");
private JToggleButton removeVertexBtn = new JToggleButton("Remove Vertex");
Gui() {
JPanel buttonPanel = new JPanel();
buttonPanel.add(addVertexBtn);
buttonPanel.add(removeVertexBtn);
DrawPanelMouseListener mouseListener = new DrawPanelMouseListener();
mouseListener.setDrawingPanel(drawingPanel);
mouseListener.setGui(this);
drawingPanel.addMouseListener(mouseListener);
drawingPanel.setPreferredSize(DRAWING_PANEL_SIZE);
drawingPanel.setBorder(BorderFactory.createLineBorder(Color.black));
mainPanel.add(drawingPanel, BorderLayout.CENTER);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
}
public JPanel getMainPanel() {
return mainPanel;
}
public boolean isAddingVertex() {
return addVertexBtn.isSelected();
}
public boolean isRemovingVertex() {
return removeVertexBtn.isSelected();
}
public void setAddingVertex(boolean addingVertex) {
addVertexBtn.setSelected(addingVertex);
}
public void setRemovingVertex(boolean removingVertex) {
removeVertexBtn.setSelected(removingVertex);
}
}
class DrawPanelMouseListener extends MouseAdapter {
private DrawingPanel drawingPanel;
private Gui gui;
public DrawPanelMouseListener() {
}
public void setGui(Gui gui) {
this.gui = gui;
}
public void setDrawingPanel(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
}
#Override
public void mousePressed(MouseEvent me) {
if (gui.isAddingVertex() && gui.isRemovingVertex()) {
gui.setAddingVertex(false);
gui.setRemovingVertex(false);
return;
}
if (gui.isAddingVertex()) {
drawingPanel.addVertex(me.getPoint());
gui.setAddingVertex(false);
}
if (gui.isRemovingVertex()) {
drawingPanel.removeVertex(me.getPoint());
gui.setRemovingVertex(false);
}
}
}
I'm not sure that this is the right way to do this but you can try this:
Create 2 panels. One for drawing lines and another for drawing buildings(labels).
Add both panels in LayeredPane of JFrame. Add panel with line in lower layer then panel with labels.
You can use LayeredPanes in other ways also to solve your problem. Learn more here: How to use Layered Panes in java