I am a new in java, and I need to implement a paint application, and I'm kinda stuck at the beggining, I managed to draw lines to a JPanel which I added to a JFrame, but each line drawn resets the entire drawing, and in the draw area remains only the last line drawn. I hope I made myself understood, here his the code:
class Shapes extends JFrame {
public JFrame mf = new JFrame("Paint");
DrawArea da = new DrawArea();
JToggleButton lineButton = new JToggleButton(new ImageIcon("line.gif"));
JToggleButton brushButton = new JToggleButton();
JToggleButton pencilButton = new JToggleButton();
JToggleButton eraserButton = new JToggleButton(new ImageIcon("eraser_icon.png"));
JToggleButton rectangleButton = new JToggleButton();
JToggleButton ovalButton = new JToggleButton();
Shapes() {
da.setBounds(120, 50, 500, 350);
da.setBackground(Color.YELLOW);
mf.setSize(700, 500);
mf.setLayout(null);
lineButton.setBounds(0, 50, 40, 40);
brushButton.setBounds(40, 50, 40, 40);
eraserButton.setBounds(0, 90, 40, 40);
pencilButton.setBounds(40, 90, 40, 40);
rectangleButton.setBounds(0, 130, 40, 40);
ovalButton.setBounds(40, 130, 40, 40);
mf.setBackground(Color.red);
mf.add(lineButton);
mf.add(brushButton);
mf.add(pencilButton);
mf.add(eraserButton);
mf.add(rectangleButton);
mf.add(ovalButton);
mf.add(da);
mf.show();
mf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
mf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("x:" + e.getX() + "y:" + e.getY() + "\n" + "x2:" + e.getXOnScreen() + "y2:" + e.getYOnScreen());
}
});
eraserButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
eraserButton.setSelectedIcon(new ImageIcon("eraser_icon_selected.png"));
}
});
lineButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
lineButton.setSelectedIcon(new ImageIcon("line_selected.png"));
}
});
da.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
da.setXvalue(e.getX());
da.setYvalue(e.getY());
}
public void mouseReleased(MouseEvent e) {
da.setX2value(e.getX());
da.setY2value(e.getY());
da.repaint();
}
});
da.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
da.repaint();
da.setX2value(e.getX());
da.setY2value(e.getY());
}
});
}
}
public class DrawArea extends JPanel {
int x1value,y1value,x2value,y2value;
public int getX2value() {
return x2value;
}
public void setX2value(int x2value) {
this.x2value = x2value;
}
public int getY2value() {
return y2value;
}
public void setY2value(int y2value) {
this.y2value = y2value;
}
public JPanel dra=new JPanel();
public int getXvalue() {
return x1value;
}
public void setXvalue(int xvalue) {
this.x1value = xvalue;
}
public int getYvalue() {
return y1value;
}
public void setYvalue(int yvalue) {
this.y1value = yvalue;
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
g.drawLine(getXvalue(),getYvalue(),getX2value(),getY2value());
}
}
class Paint extends JPanel
{
public static void main(String args[])
{
Shapes s=new Shapes();
}
}
See Custom Painting Approaches for two solutions. The examples draw rectangles, but the concept is the same for lines.
Override paintComponent(), not paint(). Read this tutorial. When a panel needs to be redrawn, you call that panels repaint() method.
Paint is called by the window manager any time it considers that area 'unfresh'. If you do it the way you're doing it right now, you will draw the last line drawn every time.
The proper way to do this would be to make a BufferedImage in memory and draw on that. Then, in the paint method, blit the BufferedImage onto the surface. This also makes scrolling and zooming quite easy to do.
Whenever you perform such an action, invalidate the surface so that the window manager will call the paint method for you.
You are only storing one line, and overwriting it each time, so when the component is repainted, the old one is erased and the new one is redrawn.
The expectation of paintComponent and the like is that your implementation will draw EVERY graphical element that you want to appear, each time it is called.
Instead of storing x1, y1, x2, y2, you should make a LineSegment class or similar that stores those values. Then, when you paint, you call g.drawLine() for each LineSegment object that you've stored (presumably in an ArrayList or similar). Then, when the component is redrawn, all of your line segments should appear on the screen.
A little bit off topic, but I had a few uncomfortable minutes cause I used update() instead of repaint(). I advice to everyone working with SWING to spend some time checking which methods should handled as thread safe and which ones has to be on EDT (Event Dispatcher Thread) to make sure you won't get some unexpected errors.
This is a good article about this.
Also, at the beginning think through if you want to have an undo/redo system in your app...
If so, than how many steps you want to allow being withdrawn. If you want to allow this feature than you cannot just draw and forget about what you draw last time.
Also it would be not memory efficient to store all the images you draw so far. I'm not an expert and I'm not saying this is the best practice but I would go this way:
I would make two lists.
One of them would store the applied drawing actions,
the other would contain the withdrawn drawing actions.
Drawing action would be an interface and some class would implement it for each specific kind of drawing action (LineDrawAction, CirceDrawAction...).
When you draw a new line or whatever you would empty the withdrawn actions list and add it to the applied action list. When someone undo the last action, than I would just remove the last drawing actions from the applied list and would add to the withdrawn list (etc...). Depending on if you want to allow only the last x action to be undone when a list reaches this x limit I would remove the first drawing action from the list or queue and would finally draw to the picture - this means permanent drawing and this cannot be undone.
I hope it's clear and useful even if not a direct answer to your question.
Related
After writing and modifying this code, I encountered with this problem:
Clicking with the mouse is making the object appear for a secong and then fly out diagonally of the image bounds.
apparentally the function "repaint()" is responsible for this occurence in "paint(Graphics g)" block.
eliminating the reapaint() part make the object appear for a second and then dissappear.
public class MainWindow extends JFrame implements MouseListener
{
public BufferedImage myImage,packman_icon;
private ArrayList<Point> points;
public MainWindow()
{
initGUI();
this.addMouseListener(this);
}
private void initGUI()
{
MenuBar menuBar = new MenuBar();
Menu File = new Menu("File");
Menu Run=new Menu("Run");
Menu Insert=new Menu("Insert");
MenuItem New=new MenuItem("New");
MenuItem Open = new MenuItem("Open");
MenuItem Save=new MenuItem("Save");
MenuItem start=new MenuItem("start");
MenuItem stop=new MenuItem("stop");
MenuItem packman=new MenuItem("packman");
MenuItem fruit=new MenuItem("fruit");
menuBar.add(File);
menuBar.add(Run);
menuBar.add(Insert);
File.add(New);
File.add(Open);
File.add(Save);
Run.add(start);
Run.add(stop);
Insert.add(packman);
Insert.add(fruit);
this.setMenuBar(menuBar);
try {
myImage = ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\Matala3\\Ariel1.png"));//change according to your path
packman_icon=ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\pacman_icon.gif"));
} catch (IOException e) {
e.printStackTrace();
}
}
int x = -1;
int y = -1;
public void paint(Graphics g)
{
super.paintComponents(g);
g.drawImage(myImage, 0, 0, this);
g.drawImage(packman_icon, x, y, 20, 20, this);
if(x!=-1 && y!=-1)
{
int r = 10;
x = x - (r / 2);
y = y - (r / 2);
g.fillOval(x, y, r, r);
}
}
#Override
public void mouseClicked(MouseEvent arg) {
System.out.println("mouse Clicked");
System.out.println("("+ arg.getX() + "," + arg.getY() +")");
x = arg.getX();
y = arg.getY();
repaint();
}
}
public class Main
{
public static void main(String[] args)
{
MainWindow window = new MainWindow();
window.setVisible(true);
window.setSize(window.myImage.getWidth(),window.myImage.getHeight());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I want the image icon to stay in picture and not dissappear, thus creating multiple objects that appear on the picture.
**I edited the code acoording to instructions: deleted reapint()
method from paint and used
super.paintComponet(g)
but now it inly appears for a brief second and then dissappears.
Don't use AWT components in a Swing application. Swing component start with "J" (JMenuBar, JMenu, JMenuItem).
//public void paint(Graphics g)
protected void paintComponent(Graphics g)
The original comment was to override paintCompnent(...).
Also, painting is a dynamic process and the painting methods are invoked whenever Swing determines the components needs to be painted so you need to make sure to reset the state each time the component is painted.
Therefore, a painting method should NOT change the state of the class. You are using the x/y variables for two purposes:
to paint the image
to paint the oval.
Because you update the x/y variable in the painting method, this will affect the location of the image the next time the painting method is invoked.
If you want the image fixed then you need to use separate variables for the location of the image.
You will also need to reset the x/y variables in the painting method to paint the ovals, since these variables are local and need to be reset each time the painting is done.
I'm having trouble with my jbutton not displaying. If i do not use paintComponent, then my JButtons with images show up no problem. However now, the image does not show up. If i hover over where it should be, the image shows up for one second. So it's like the button is still there, just maybe below the background?
public class Game extends JPanel implements KeyListener, ActionListener {
//layout variables
private ImageIcon right,left,up,down;
private JButton rightButton,leftButton,upButton,downButton;
//play variables
private boolean play=false;
private int score=0;
private int paddleX= 200; //paddle X position
private int paddleY= 300; //paddle Y pos
private int ballX= 210; //ball x position
private int ballY= 260; //ball y position
private int ballXdir=-1; //x direction
private int ballYdir=-2; //y direction
private Timer time; //my timer
public Game() {
Display(); //display the layout
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
time= new Timer(8,this);
time.start();
}
public void Display(){
//setLayout
this.setLayout(null);
//Setting the Images
//right = new ImageIcon(getClass().getResource("images\\rightIcon.png"));
left = new ImageIcon(getClass().getResource("images\\leftIcon.png"));
up = new ImageIcon(getClass().getResource("images\\upIcon.png"));
down = new ImageIcon(getClass().getResource("images\\downIcon.png"));
//Setting the JButtons for the arrow images
rightButton= new JButton("right");
rightButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(paddleX>=400){
paddleX=400;
}
else{
moveRight();
}
repaint();
}
});
//rightButton.setOpaque(false);
//rightButton.setContentAreaFilled(false);
//rightButton.setBorderPainted(false);
leftButton= new JButton(left);
leftButton.setOpaque(false);
leftButton.setContentAreaFilled(false);
leftButton.setBorderPainted(false);
upButton= new JButton(up);
upButton.setOpaque(false);
upButton.setContentAreaFilled(false);
upButton.setBorderPainted(false);
downButton= new JButton(down);
downButton.setOpaque(false);
downButton.setContentAreaFilled(false);
downButton.setBorderPainted(false);
//setting image bounds and adding it to screen
rightButton.setBounds(135,450,50,50);
leftButton.setBounds(45,450,50,50);
upButton.setBounds(90,400,50,50);
downButton.setBounds(90,500,50,50);
//rightButton.addActionListener(this);
leftButton.addActionListener(this);
add(upButton);
add(downButton);
add(leftButton);
add(rightButton);
}
//painting the screen with graphics
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(25,25,425,300); //game area
//drawing the paddle
g.setColor(Color.YELLOW);
g.fillRect(paddleX,paddleY,50,8);
//drawing the ball
g.setColor(Color.PINK);
g.fillOval(ballX,ballY,20,20);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
time.start();
if(e.getSource()==right) {
if(paddleX>=400){
paddleX=400;
}
else{
moveRight();
}
}
if(e.getSource()==left) {
if(paddleX<35){
paddleX=35;
}
else{
moveLeft();
}
}
repaint();
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
if(paddleX>=400){
paddleX=400;
}
else{
moveRight();
}
}
if(e.getKeyCode()==KeyEvent.VK_LEFT){
if(paddleX<35){
paddleX=35;
}
else{
moveLeft();
}
}
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
public void moveRight(){
play=true;
paddleX+=10;
}
public void moveLeft(){
play=true;
paddleX-=10;
}
}
I highly recommend having a look at Performing Custom Painting and Painting in AWT and Swing as it will explain how the painting system works.
Basically, you are passed a reference to the Graphics context which is currently been used to perform the current paint pass, via the paintComponent method. This is a shared resource. All components involved in the paint pass are passed the same Graphics context.
By calling dispose, you are releasing all the underlying resources for the context, which can, on some systems, prevent other components from been painted.
But they paint when I move my mouse over them
Because components can be painted independently of their parent, but you also call repaint on the parent component, which will, you guessed it, paint it's children.
Recommendations
Create a custom component dedicated solely to performing the custom painting operations (and possible some of the other basic game functions)
Create another component to hold the buttons (and make use of appropriate layouts)
Use a some kind of data model which is shared between them. This model will hold the state of the "actions" (ie up/down/left/right) and the "engine" will use this information to update the state of the game.
Make use of the Key bindings API which will solve the unreliability issues associated with KeyListener
I created this java program and I wanted an output of which if int x and int y are above 100, it would draw a rectangle. But it doesn't. How can I make it work?Is there another line of code I need to add?
Here's my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class GameSetup extends JPanel implements MouseMotionListener{
public static JFrame njf = new JFrame("Test");
public static int x, y;
public static void main(String[] args){
GameSetup gs = new GameSetup();
njf.add(gs);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.GREEN);
g.fillRect(150, 75, 200, 100);
g.setColor(Color.ORANGE);
g.drawString("Play", 239, 123);
njf.addMouseListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
}
});
if(x > 100 && y > 100){
g.drawRect(10, 10, 100, 100);
}
}
public GameSetup(){
njf.setSize(500,500);
njf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
njf.setResizable(false);
njf.setLocationRelativeTo(null);
njf.setVisible(true);
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
Okay, there are several things wrong with the code that you included above.
The first that stood out to me was the way that you are adding the mouse action listener to frame. There are multiple things that are wrong with this.
First of all, you are doing this in the paintComponent method, which, if it works, is still considered to be bad practice because the paintComponent method may be called multiple times. Do that, as pointed out by the comments, in the constructor of the panel.
The second is that you are adding the mouse listener to the frame, not the panel, which doesn't work because the panel is "above" the frame, so the mouse event will only be recognized within the panel. Your best bet here is to add a MouseMotionListener directly to the panel itself.
The third is that you are implementing the MouseMotionListenerinterface in the GameSetup class, but never actually doing anything with this implementation. So what I did was that I got rid of the inner class, and just had the panel be its own MouseMotionListnener
The second thing that is wrong with the code is that the paintComponent method is only called at certain points in time (see this). That means that even though the mouse might have moved within the zone, your paintComponent method isn't being called to update the screen accordingly. For this, you need to call the repaint method for your panel.
The third is that you didn't set a size for your panel, and the default one is 0x0, so you need to set a size of your panel (which should be the same as the frame itself) (if you want to keep the default layout).
All of that being said, here is your code that I fixed up. I added a variable called enteredZone to keep track of if the mouse had previously entered the zone, so that the rectangle would stay up even if the mouse left the zone after entering it (its your choice if you want to keep it). Note that there are other things with this code that might be considered bad practice, but this is enough to get you started:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class GameSetup extends JPanel implements MouseMotionListener {
public static JFrame njf = new JFrame("Test");
public static int x = 0, y = 0;
public static boolean enteredZone = false;
public static void main(String[] args) {
GameSetup gs = new GameSetup();
gs.addMouseMotionListener(gs);
njf.add(gs);
njf.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.GREEN);
g.fillRect(150, 75, 200, 100);
g.setColor(Color.ORANGE);
g.drawString("Play", 239, 123);
if (x > 100 && y > 100 || enteredZone){
g.drawRect(10, 10, 100, 100);
enteredZone = true;
}
}
public GameSetup() {
super();
setSize(500, 500);
njf.setSize(500,500);
njf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
njf.setResizable(false);
njf.setLocationRelativeTo(null);
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
if (x > 100 && y > 100) repaint();
}
}
I want the user of my program to be able to highlight an area on a JFrame to select a group of items on screen. The code I posted below works, but it is very choppy, which becomes quite an eyesore every single time the JFrame repaints. Here's an image of what I'm talking about: http://i1065.photobucket.com/albums/u400/mfgravesjr/choppy%20draw%20rectangle_zpsspqsqnyf.png
Maybe someone here has suggestions to improve my code?
This is the mouseDragged method in MouseMotionListener:
public void mouseDragged(MouseEvent me)
{
if(groupingTerr&&me.getSource()==background)
{
endPoint = MouseInfo.getPointerInfo().getLocation();
topLeftRect = new Point(Math.min(startPoint.x,endPoint.x),Math.min(startPoint.y,endPoint.y));
bottomRightRect = new Point(Math.max(startPoint.x,endPoint.x),Math.max(startPoint.y,endPoint.y));
for(Point p:map.territoryPoints)
{
if(p.x>topLeftRect.x&&p.x<bottomRightRect.x&&p.y>topLeftRect.y&&p.y<bottomRightRect.y)img.getGraphics().drawImage(selectedIco,p.x-selectedIco.getWidth()/2,p.y-selectedIco.getHeight()/2,null);
else img.getGraphics().drawImage(defaultIco,p.x-defaultIco.getWidth()/2,p.y-defaultIco.getHeight()/2,null);
}
background.repaint();
}
}
This is the private overridden JFrame class
private static class DrawableJFrame extends JFrame
{
#Override
public void paint(Graphics g)
{
super.paint(g);
g.setColor(new Color(0,0,0,100));
g.drawRect(topLeftRect.x,topLeftRect.y,bottomRightRect.x-topLeftRect.x,bottomRightRect.y-topLeftRect.y);
g.setColor(new Color(200,10,10,100));
g.fillRect(topLeftRect.x,topLeftRect.y,bottomRightRect.x-topLeftRect.x,bottomRightRect.y-topLeftRect.y);
}
}
The image is original artwork. Please do not use it.
I've got a problem in Java using a "canvas" class I created, which is an extended JPanel, to draw an animated ring chart. This chart is using a MouseListener to fetch click events.
The problem is that the mouse position does not seem to be accurate, meaning it does not seem to be relative to the "canvas" but instead relative to the window (in the left, upper corner I got about 30px for y coord).
This is my code:
I created a class, that extends JPanel and does have a BufferedImage as member.
public class Canvas extends JPanel {
public BufferedImage buf;
private RingChart _parent;
public Canvas(int width, int height, RingChart parent){
buf = new BufferedImage(width, height, 1);
...
In the paint component method I just draw the buffered image, so I am able to paint on the canvas from 'outside' by painting on the buffered image, which is public.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(buf, null, 0, 0);
}
Now there's a class RingChart which contains a "canvas":
public class RingChart extends JFrame{
public Canvas c;
...
And I create a Graphics2D from the bufferedImage in the canvas class. This g2d is used for painting:
public RingChart(){
c = new Canvas(1500,980,this);
add(c);
setSize(1500, 1000);
setTitle("Hans");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
g2d = (Graphics2D)c.buf.createGraphics();
...
What I now was trying to achieve, was a mouse listener that listened to mouse events happening on the canvas. So when the user clicks on the canvas I could retrieve the position he clicked on, upon the canvas, through the event variable.
So I created a mouse listener:
class MouseHandler implements MouseListener {
#Override
public void mouseClicked(MouseEvent e){
RingChart r = ((Canvas)e.getSource()).getParent();
r.mouseClick(e);
}
...
...and added this mouse listener to the canvas of the RingChart class (myChart is an instance of RingChart and c is the canvas it contains):
...
MouseHandler mouse = new MouseHandler();
myChart.c.addMouseListener(mouse);
...
But as I mentioned above, the mouse position, that's returned when the click event is called, does not seem to be accurate. I think the mistake must be somehow in the way I created that mouseListener or maybe assigned it to the wrong element or something like that. But I've tried quite a couple of things and it didn't change. Can maybe someone tell me, what I've done wrong?
UPDATE:
The code of the function "mouseClick" that is a member of RingChart and is called in the mouse listener:
public void mouseClick(MouseEvent evt){
//evt = SwingUtilities.convertMouseEvent(this, evt, c);
if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
for(Element e : elements){
if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
//do some stuff
}
}
}
}
Again, the hierarchy of my classes:
RingChart --contains a--> Canvas --got a--> MouseListener.
The shapes in this function are shapes that have been painted on the canvas c. Now I want to check, if the user has clicked on one of them. So as I thought, the shapes should be in canvas-coordinates and the event position should be in canvas-coordinates and everything should fit together. But it doesn't.
Now user MadProgrammer told me, to use the ConvertMouseEvent function. But I currently don't see which exact way I should use this sensibly.
UPDATE:
I found a solution: All I had to do is adding the canvas not directly to the JFrame but to the ContentPane of the JFrame instead:
So instead:
public RingChart(){
c = new Canvas(1500,980,this);
add(c);
...
I do:
public RingChart(){
c = new Canvas(1500,980,this);
getContentPane().add(c);
...
Then I give the MouseListener to the ContentPane.
getContentPane().addMouseListener(new MouseHandler());
getContentPane().addMouseMotionListener(new MouseMoveHandler());
I don't know, if this is an elegant solution, but it works.
The mouse event is automatically converted to be relative to the component that it occurred in that is, point 0x0 is always the top left corner of the component.
By using RingChart r = ((Canvas)e.getSource()).getParent(), you've effectively changed the reference, which now means the location is no longer valid.
You need to convert the location so that its coordinates are in the context of the parent component. Take a look at SwingUtilities.convertMouseEvent(Component, MouseEvent, Component)
UPDATE with PICTURES
Lets take this example...
The blue box has a relative position of 50px x 50px to the red box. If you click in the blue box, lets say at 25x25, the mouse coordinates will be relative to the blue box (0x0 will be the top left of the blue box).
If you then pass this event to the red box and try and use the coordinates from it, you will find that the coordinates will now be half way between the top left of the red box and the blue box, because the coordinates are context sensitive.
In order to get it to work, you need to translate the mouse events location from the blue box to the red box, which would make it 75x75
Now, I don't know what you're doing when you pass the mouse event to the RingChart so I'm only guessing that this is the issue you're facing.
UPDATED with Click Code
Okay, lets say, you have a Canvas at 100x100. You click on that Canvas at 50x50. You then pass that value back up the chain.
public void mouseClick(MouseEvent evt){
//evt = SwingUtilities.convertMouseEvent(this, evt, c);
if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
for(Element e : elements){
// Here, we are asking the shape if it contains the point 50x50...
// Not 150x150 which would be the relative position of the click
// in the context to the RingChart, which is where all your objects
// are laid out.
// So even the original Canvas you clicked on will return
// false because it's position + size (100x100x width x height)
// does not contain the specified point of 50x50...
if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
//do some stuff
}
}
}
}
UPDATED
I think you have your references around the wrong way...
public static MouseEvent convertMouseEvent(Component source,
MouseEvent sourceEvent,
Component destination)
I think it should read something like
evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);
UPDATE with Code Example
Okay, so, I put this little example together...
public class TestMouseClickPoint extends JFrame {
private ContentPane content;
public TestMouseClickPoint() throws HeadlessException {
setSize(600, 600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
content = new ContentPane();
add(content);
}
protected void updateClickPoint(MouseEvent evt) {
content.updateClickPoint(evt);
}
protected class ContentPane extends JPanel {
private Point relativePoint;
private Point absolutePoint;
public ContentPane() {
setPreferredSize(new Dimension(600, 600));
setLayout(null); // For testing purpose only...
MousePane mousePane = new MousePane();
mousePane.setBounds(100, 100, 400, 400);
add(mousePane);
}
protected void updateClickPoint(MouseEvent evt) {
absolutePoint = new Point(evt.getPoint());
evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);
relativePoint = new Point(evt.getPoint());
System.out.println(absolutePoint);
System.out.println(relativePoint);
repaint();
}
protected void paintCross(Graphics2D g2d, Point p) {
g2d.drawLine(p.x - 5, p.y - 5, p.x + 5, p.y + 5);
g2d.drawLine(p.x - 5, p.y + 5, p.x + 5, p.y - 5);
}
/*
* This is not recommended, but I want to paint ontop of everything...
*/
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
if (relativePoint != null) {
g2d.setColor(Color.BLACK);
paintCross(g2d, relativePoint);
}
if (absolutePoint != null) {
g2d.setColor(Color.RED);
paintCross(g2d, absolutePoint);
}
}
}
protected class MousePane extends JPanel {
private Point clickPoint;
public MousePane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
clickPoint = e.getPoint();
TestMouseClickPoint.this.updateClickPoint(e);
repaint();
}
});
setBorder(new LineBorder(Color.RED));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
if (clickPoint != null) {
g2d.drawLine(clickPoint.x, clickPoint.y - 5, clickPoint.x, clickPoint.y + 5);
g2d.drawLine(clickPoint.x - 5, clickPoint.y, clickPoint.x + 5, clickPoint.y);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
new TestMouseClickPoint().setVisible(true);
}
}
Basically, it will paint three points. The point that the mouse was clicked (relative to the source of the event), the unconverted point in the parent container and the converted point with the parent container.
The next thing you need to do is determine the mouse location is actually been converted, failing that. I'd probably need to see a working example of your code to determine what it is you're actually doing.