Swing: Paint over all other components and preserve events - java

What I am trying to do: draw a vertical line and a horizontal line that are perpendicular to each other and meet where the mouse points. A sort of cursor tracker.
My structure: JFrame -> CustomPanel -> other panels/components etc.
CustomPanel inherits from JPanel and it's set as my JFrame's ContentPane.
I tried to use a GlassPane, everything worked perfectly, but I want to keep my events, not disable them. I still want to be able to click buttons etc.
A relevant question is this Painting over the top of components in Swing?. Everything behaves as expected when I move my mouse where there are empty places in my CustomPanel, but it still doesn't paint over the other components.
In the image it should have continued painting over the button, but it stopped when I entered it and then resumed when I exited.
Code below.
public class Painter {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
JFrame frame = new JFrame();
frame.setSize(600, 600);
frame.setPreferredSize(new Dimension(600, 600));
frame.setContentPane(new CustomPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class CustomPanel extends JPanel {
int x = 0;
int y = 0;
public CustomPanel() {
addMouseListener(new AdapterImplementation(this));
addMouseMotionListener(new AdapterImplementation(this));
add(new JButton("TESTBTN"));
setSize(new Dimension(600, 600));
setPreferredSize(new Dimension(600, 600));
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawLine(0, y, getWidth(), y);
g.drawLine(x, 0, x, getHeight());
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
and my adapter:
public class AdapterImplementation extends MouseAdapter {
CustomPanel pane;
public AdapterImplementation(CustomPanel pane) {
this.pane = pane;
}
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
pane.setX(x);
pane.setY(y);
pane.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("MOUSE MOVED");
int x = e.getX();
int y = e.getY();
pane.setX(x);
pane.setY(y);
pane.repaint();
}
}

The problem here is that the MouseListeners are registered with your CustomPanel but not with the JButton so the latter does not process events from the listeners.
Also, as you've seen, events to underlying components will be blocked when using GlassPane.
A JLayeredPane could be used to as a topmost container to capture the MouseEvents using your current listeners.
Note: Override paintComponent instead of paint for custom painting in Swing and remember to invoke super.paintComponent(g).
JLayeredPane Example
How to Use Layered Panes

Related

JPanel not rendering correctly, it is taller than the JFrame and things that sould render on top of the bottom border render below it

When I tell awt/swing to draw a component at a given y that is smaller than the window height, that object renders on the bottom of the bottom border, but it should not, it is supposed to render at that given y.
Here some code example:
public class Main {
public static GameWindow window;
public static void main(String[] args) {
window = new GameWindow();
}
}
class GameWindow extends JFrame {
private final GamePanel panel;
public GameWindow() {
super();
this.setSize(600, 400); //Observe that the height is 400
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new GamePanel();
this.add(panel);
//Uncomment the following line and observe how the square now renders where it should
//setUndecorated(true);
this.setVisible(true);
}
//Uncomment the following method to see a black line just on top of the bottom border
/*#Override
public int getHeight() {
return panel.getHeight();
}*/
}
class GamePanel extends JPanel {
public GamePanel() {
super();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Here it should render just above the bottom border, but it doesn't, it renders well below
g.fill3DRect(0, Main.window.getHeight() - 22, 22, 22, false);
}
}
Case 1: If you live it decorated, you have to resize the window in order to see the square.
Case 2: If you make the JFrame undecorated it renders as it should: just on top of the bottom border.
Case 3: If you live it decorated, but override the getHeight method so that it returns the height of the panel, a black line is rendered in the bottom of the window.
Images:
Case 1:
Case 2:
Case 3:
The coordinate system used by Swing starts in the left upper corner and is relative to the component, and so 0,0 is the left upper part of the JPanel. Here:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fill3DRect(0, Main.window.getHeight() - 22, 22, 22, false);
}
You are in fact telling Swing to always draw in a non-visible part of your JPanel, above the JPanel, and so this code will never work.
If you want to draw at the bottom, use component's getHeight() method to find the bottom of the JPanel, and draw above that:
int yPos = getHeight() - 22;
g.fill3DRect(0, yPos, 22, 22, false);
But also, never use "magic numbers" such as 22 here. Also, avoid setting sizes but instead override getPreferredSize():
e.g.,
public class GamePanel extends JPanel {
public static final int PREF_W = 600;
public static final int PREF_H = 400;
public static final int SPRITE_WIDTH = 22;
public GamePanel() {
super();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int yPos = getHeight() - SPRITE_WIDTH;
g.fill3DRect(0, yPos, SPRITE_WIDTH, SPRITE_WIDTH, false);
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int w = Math.max(PREF_W, superSize.width);
int h = Math.max(PREF_H, superSize.height);
return new Dimension(w, h);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GamePanel mainPanel = new GamePanel();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Problem was I was using/overriding JFrame getWidth and Height, I just made a method with another name to get those informations and now it works fine, turns out that returning the panel dimensions in the window methods is not ok.

How to move around an object drawn on a panel with button click

I am trying to build a bounce game in Java. My project has three classes ie the Main class which creates a new window(frame) where the game buttons and bounce objects are drawn.
The GameInterface class which represents the properties of the frame being drawn and the RightPanel class which I created so that I could override the paint(Graphics) method to draw my bounce object. So far this is what I have managed to draw with the code.
You can see that I have two JPanels, one that holds my buttons and the other one that accepts the drawing of a round ball on it ie RightPanel
I need help with the Button Event listeners to move the ball up and down and when user holds the button down, it needs to keep moving down until reaches the down order, sam for the up button.
The code am using is provided below.
GameInterface class
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class GameInterface extends JFrame {
//we need this panel declaration in the class level for reference from other methods
RightPanel rightpanel;
//define the physical properties of the window
public GameInterface(){
setSize(new Dimension(600, 600));
setResizable(false);
setTitle("Bounce Game");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(Color.black);
//define a new JSplitPane and use it to add two JPanels
JPanel leftpanel= new JPanel();
//add buttons to the left panel programatically
JButton up= new JButton("Move up");
//set the event listeners for the buttons
up.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//move my ball up
//clear and redraw the ball while in a new position, use a timer or
something
}
});
JButton down = new JButton("Move down");
down.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//move my ball down
// rightpanel.getGraphics.fillColor(Color.RED);
}
});
leftpanel.add(up);
leftpanel.add(down);
//add a new RightPanel with a drawn red object
rightpanel= new RightPanel();
JSplitPane splitpane= new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,leftpanel,rightpanel);
this.add(splitpane);
setVisible(true);
}
}
RightPanel class
import javax.swing.*;
import java.awt.*;
public class RightPanel extends JPanel {
//define the position where the circle will be drawn
private int positionX=150;
private int positionY=150;
//I had an idea where we need a timer and then on delay we
//decrement positionX by 3 for move down but can't figure out how to clear RightPanel
private int radius=100;//as the shape is a circle
//override the paint method to draw the bounce ball on the second panel
#Override
public void paint(Graphics g) {
g.setColor(Color.RED);
g.fillOval(positionX,positionY,radius,radius);
}
}
Main class
public class Main
{
public static void main(String args[]){
new GameInterface();
}
}
How do I add logic to my code to make it move the circle up an down, Thank You.
I tried using a timer object to clear the panel and then redraw the ball in the new position of the ball but it draws a vertical bar, not clearing the original ball drawn.
Never call getGraphics() on a component.
Override paintComponent not paint
Call the super.paintComponent(g) in your override.
Give the RightPanel class setter methods that allow you to change the positionX and positionY locations for drawing,
In the button listener, call an appropriate setter method, and then call repaint() on on the RightPanel instance after changing the positions.
For example:
The key code below is here in the ActionListener where you update the position values and call repaint:
moveRightBtn.addActionListener(e -> {
// get and update the x position
int x = drawOval.getPositionX();
x += DELTA;
// call the setter method
drawOval.setPositionX(x);
// request that Java repaint the JPanel
drawOval.repaint();
});
and in the drawing JPanel's paintComponent method where you call the super's method and draw the oval:
#Override
protected void paintComponent(Graphics g) {
// this is needed to do house-keeping painting, to clear "dirty" pixels
super.paintComponent(g);
// this is needed to draw smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(positionX, positionY, RADIUS, RADIUS);
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveCircle extends JPanel {
private static final int DELTA = 5;
private DrawOval drawOval = new DrawOval();
public MoveCircle() {
JButton moveRightBtn = new JButton("Move Right");
moveRightBtn.addActionListener(e -> {
// get and update the x position
int x = drawOval.getPositionX();
x += DELTA;
// call the setter method
drawOval.setPositionX(x);
// request that Java repaint the JPanel
drawOval.repaint();
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(moveRightBtn);
setLayout(new BorderLayout());
add(drawOval);
add(buttonPanel, BorderLayout.LINE_START);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MoveCircle mainPanel = new MoveCircle();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class DrawOval extends JPanel {
private static final int RADIUS = 100;
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 450;
private static final Color OVAL_COLOR = Color.RED;
private int positionX = 0;
private int positionY = 0;
public DrawOval() {
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
#Override
protected void paintComponent(Graphics g) {
// this is needed to do house-keeping painting, to clear "dirty" pixels
super.paintComponent(g);
// this is needed to draw smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(positionX, positionY, RADIUS, RADIUS);
}
}

Jcomponent paintcomponent not appearing on the panel

i am making a simple GUI in which small boxes should appear on the Jpanel according to their x,y coordinates. So i in my structure i have got three classes:
1: MyFrame which contains the main JFrame
2: MyPanel extends JPanel
3: Icon extends JComponent
In my MyFrame i want to have a MenuBar through which i can open a file of X,Y coordinates and below the menu bar i want to have the MyPanel which will have all the Icons for each X,Y coordinates. The first problem i have is that the Icon do not appear on MyPanel when i add the Icons.
My code can be seen below:
public class MyFrame {
private JFrame frame;
private MyPanel panel;
public MyFrame(){
panel = new MyPanel();
}
/*
*HERE GOES THE `FILE OPEN` LISTENER
* it creates `Coordinate` for each line
* passes the coordinate to panel.makeIcons()
*/
public void createGui(){
frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
//create, get and set the Jframe menu bar
//createMenuBar() returns a JMenuBar
frame.setJMenuBar(createMenuBar());
Container frame_pane = frame.getContentPane();
panel.setBounds(0, 0, frame.getWidth(), frame.getHeight());
frame_pane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]){
MyFrame window = new MyFrame();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
window.createGui();
}
});
}
}
Code For the panel for holding icons:
public class MyPanel extends JPanel{
private Set<Icon> points;
public MyPanel(){
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
}
}
Code for Icon which needs to be shown on the above panel:
public Icon extends JComponent{
private Coordinate location;
public Icon(Coordinate obj){
location = obj;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(location.getX(), location.getY(), 20, 20);
g.setColor(Color.BLACK);
g.drawRect(location.getX(), location.getY(), 20, 20);
}
}
First Problem: The Icons do not show up in the panel with the above code.
Second Problem: When i change the makeIcon method in MyPanel.class to below. It shows the Icons By the MenuBar erases them when the MenuBar appears on any of the icons:
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
temp.paintComponent(this.getGraphics());
revalidate();
}
Any help is appreciated. Thanks
Don't call paintComponent (or any paint) method yourself, ever. This is not how painting works.
The core reasons why a component won't be painted are because:
it's size is 0x0
it's invisible
it's not added to a container that is (indirectly) added to a native peer.
Based on my brief observation, I would say you're suffering from point number 1, in part due to the use of a null layout
Also, remember, when painting a component, the component's Graphics context has already been translated so that 0x0 is the top/left corner of the component. This means, based on your code, you'd most likely be painting beyond the visible bounds of the component any way.
So, you basically have two choices. Implement your own layout manager, which uses the Coordinate information to place the Icons with in the container (which would then need to override getPreferredSize in order to provide sizing hints) or, paint it yourself
Which might look something like this...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(new MyPanel());
frame.pack();
frame.setVisible(true);
}
});
}
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class Icon {
private Coordinate coordinate;
public Icon(Coordinate coordinate) {
this.coordinate = coordinate;
}
public Coordinate getCoordinate() {
return coordinate;
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, 20, 20);
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, 20, 20);
}
}
public class MyPanel extends JPanel {
private Set<Icon> points;
public MyPanel() {
points = new HashSet<>();
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj) {
points.add(new Icon(obj));
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Icon icon : points) {
Graphics2D g2d = (Graphics2D) g.create();
Coordinate coordinate = icon.getCoordinate();
// I'd have a size component associated with the Icon
// which I'd then use to offset the context by half its
// value, so the icon is paint around the center of the point
g2d.translate(coordinate.getX() - 10, coordinate.getY() - 10);
icon.paint(g2d);
g2d.dispose();
}
}
}
}
I've not seeded any values, I'm lazy, but that's the basic idea

what is Alternative of Paint and repaint function?

Is there any function which can be replaced with paint() and repaint()in java.
I have a scenario.
There is a triangle (Triangle 1). when user will click in triangle another triangle (Triangle 2) will appear and 1st (Triangle 1) will be removed from screen. (coded using JFrame, paint() and repaint())
I have achieved it so far. but problem is when I minimize or change size of window with mouse the output window, it just paint again Triangle 1 rather than Triangle 2. OR Clear the whole screen if i call g2d.clearRect(0, 0, 1000, 1000);
triangle.reset();
Note: These both functions are to remove previous triangle (Triangle 1).
Is there any function that state should not be changed on minimize or when window size changed ?
or can we override repaint() or anything helping according to scenario.
Here is the Working code. Execute it, Click in triangle then minimize and see again. You will get the problem more clearly.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Triangle_shape extends JFrame implements ActionListener {
public static JButton btnSubmit = new JButton("Submit");
public Triangle_shape() {
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setLayout(new BorderLayout());
frame.add(new TrianglePanel(), BorderLayout.CENTER);
frame.add(btnSubmit, BorderLayout.PAGE_END);
frame.pack();
frame.repaint();
frame.setTitle("A Test Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
public static class TrianglePanel extends JPanel implements MouseListener {
private Polygon triangle, triangle2;
public TrianglePanel() {
//Create triangle
triangle = new Polygon();
triangle.addPoint(400, 550); //left
triangle.addPoint(600, 550); //right
triangle.addPoint(500, 350); //top
//Add mouse Listener
addMouseListener(this);
//Set size to make sure that the whole triangle is shown
setPreferredSize(new Dimension(300, 300));
}
/**
* Draws the triangle as this frame's painting
*/
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.draw(triangle);
}
//Required methods for MouseListener, though the only one you care about is click
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
/**
* Called whenever the mouse clicks. Could be replaced with setting the
* value of a JLabel, etc.
*/
public void mouseClicked(MouseEvent e) {
Graphics2D g2d = (Graphics2D) this.getGraphics();
Point p = e.getPoint();
if (triangle.contains(p)) {
System.out.println("1");
g2d.clearRect(0, 0, 1000, 1000);
triangle.reset();
g2d.setColor(Color.MAGENTA);
triangle2 = new Polygon();
triangle2.addPoint(600, 550); // left
triangle2.addPoint(700, 350); //top
triangle2.addPoint(800, 550); //right
g2d.draw(triangle2);
} else {
System.out.println("Triangle dont have point");
}
}
}
}
paint() and repaint() work fine, but you are not using them as they are designed to be used. The window system doesn't keep a persistent image of what a component looks like. It expects your component to be able to repaint its entire appearance on demand (such as when the window is resized or un-minimized).
If you grab a Graphics object with getGraphics() and draw something on the component, the stuff you draw will indeed be lost if/when the entire component needs to be repainted. So you should not do that, but instead make sure your paintComponent method has all the information it needs to completely repaint the component.
If you only want one triangle on the screen at once, do not create a separate variable triangle2. Just replace the one triangle you have by altering your mouse click handler as follows:
public void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
if (triangle.contains(p)) {
triangle = new Polygon();
triangle.addPoint(600, 550); // left
triangle.addPoint(700, 350); //top
triangle.addPoint(800, 550); //right
repaint();
} else {
System.out.println("Point not in triangle");
}
}
Your paintComponent method should call super.paintComponent to ensure the background is painted, but otherwise you do not need to change it:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.draw(triangle);
}
Alternatively if you are trying to keep multiple triangles on the screen, for example, to add a new one at every click, you should add them into a list of shapes which will be drawn whenever the component needs to be repainted:
private final List<Shape> shapes = new ArrayList<>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
for (Shape s : shapes)
g2d.draw(s);
}
Then to control the set of shapes that is on screen, manipulate the contents of the list, and call repaint();.
For instance, to add a new shape to the ones on screen:
Polygon triangle = new Polygon();
triangle.addPoint(200, 300);
triangle.addPoint(200, 200);
triangle.addPoint(300, 200);
shapes.add(triangle);
repaint();
To remove all shapes from the screen:
shapes.clear();
repaint();
You should also make sure that you switch to the Swing thread at the start of the program, because it is not safe to interact with Swing components from the main thread. In main:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
.
.
.
frame.setVisible(true);
}
});
}
Your mouseClicked method should not create a new Triangle object. After resetting triangle just add new points to it. Also don't draw in this method but call repaint:
public void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
if (triangle.contains(p)) {
System.out.println("1");
triangle.reset(); // change the current triangle
triangle.addPoint(600, 550); // new left
triangle.addPoint(700, 350); // new top
triangle.addPoint(800, 550); // new right
repaint(); // force repainting
} else {
System.out.println("Triangle dont have point");
}
}
Now if you want many triangles you should have a collection of Polygons. Like this :
public static class TrianglePanel extends JPanel implements MouseListener {
private Vector<Polygon> triangles;
public TrianglePanel() {
n = 0;
// Create an empty collection
triangles = new Vector<Polygon>();
//Create first triangle
Polygon triangle = new Polygon();
triangle.addPoint(400, 550); //left
triangle.addPoint(600, 550); //right
triangle.addPoint(500, 350); //top
// Add the triangle to the collection
triangles.add(triangle);
//Add mouse Listener
addMouseListener(this);
//Set size to make sure that the whole triangle is shown
setPreferredSize(new Dimension(300, 300));
}
/**
* Draws the triangles as this frame's painting
*/
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
for (Polygon p : triangles) // Draw all triangles in the collection
g2d.draw(p);
}
//Required methods for MouseListener, though the only one you care about is click
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
/**
* Called whenever the mouse clicks. Could be replaced with setting the
* value of a JLabel, etc.
*/
public void mouseClicked(MouseEvent e) {
Graphics2D g2d = (Graphics2D) this.getGraphics();
Point p = e.getPoint();
// Do what you want with p and the collection
// For example : remove all triangles that contain the point p
ListIterator<Polygon> li = triangles.listIterator();
while (li.hasNext()) {
if (li.next().containsâ„—) li.remove();
}
// Do what you want to update the list
// For example: Add a new triangle...
Polygon triangle = new Polygon();
triangle.addPoint(600+n, 550); // left
triangle.addPoint(700+n, 350); //top
triangle.addPoint(800+n, 550); //right
triangles.add(triangle); // add the new triangle to the list
n += 10; // next new triangle will be "moved" right
repaint();
}
private int n;
}

Why can i not make a circles with the mouse?

I'm resolving an excercise about to create a closest pair of points. The first satge i'm doing is trying to make a points(cricles) with my mouse. But i got no respons with the left button (just one circle in (0,0)), the others buttons 2 and 3 work fine. I'm stuck in why and how to resolve that? Any hint or help is appreciate.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ClosestPairOfPoints extends JFrame {
// Create a canvas
private Circle canvas = new Circle();
public ClosestPairOfPoints() {
// Create a panel
JPanel p = new JPanel();
// Add canvas and panel
add(canvas, BorderLayout.CENTER);
// add(p);
canvas.addMouseListener(new MouseAdapter() {
#Override
// Handle mouse clicked event
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1)
canvas.createCircle();
else if (e.getButton() == MouseEvent.BUTTON2)
System.out.println("Try again with the left button");
else if (e.getButton() == MouseEvent.BUTTON3)
System.out.println("Try again with the left button");
}
});
}
public static void main(String[] args) {
JFrame frame = new ClosestPairOfPoints();
frame.setTitle("Closest pair of Ppoints");
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
static class Circle extends JPanel { // Inner class
private int x;
private int y;
private int radius = 10; // Default circle radius
// Create a circle
public void createCircle() {
}
// paint the component
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, radius, radius);
}
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ClosestPairOfPoints extends JFrame {
// Create a canvas
private Circle canvas = new Circle();
public ClosestPairOfPoints() {
// Add canvas and panel
add(canvas, BorderLayout.CENTER);
canvas.addMouseListener(new MouseAdapter() {
#Override
// Handle mouse clicked event
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1){
canvas.createCircle(e.getX(), e.getY());
}else if (e.getButton() == MouseEvent.BUTTON2){
System.out.println("Try again with the left button");
}else if (e.getButton() == MouseEvent.BUTTON3){
System.out.println("Try again with the left button");
}
}
});
}
public static void main(String[] args) {
JFrame frame = new ClosestPairOfPoints();
frame.setTitle("Closest pair of Ppoints");
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
static class Circle extends JPanel { // Inner class
private int x;
private int y;
private int radius = 10; // Default circle radius
// Create a circle
public void createCircle(int x, int y) {
this.x = x;
this.y = y;
repaint();
}
// paint the component
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, radius, radius);
}
}
}
It should work now. You needed to call createCircle and pass it the position of the mouseClick, and then call repaint so the paint component can be called again and the circle redrawn in the correct position.
Haha it seems like another person has posted an answer while I was typing this. As mentioned the event object "e" contains information about the mouse click, so using the getX() and getY() methods, you can get the x and y position of the mouse click.
Also, you don't need the JPanel p = new JPanel(); in your code either.. because "canvas" is already a JPanel and the one you added to the JFrame.
Hope this helps
The left mouse button is responding normally (did a System.out.println with the left mouse button), but, as Hovercraft Full of Eels stated, your createCircle() method is empty. That's your problem.
In terms of actually drawing the circle, I won't write the entire code for you, but I'll tell you that e.getX() and e.getY() will come in handy when figuring out where the mouse is when the mouse click occurred.

Categories

Resources