Reputation: 79
Below is some code that shows the essence of my issue. I show a JFrame
containing a yellow and a green JPanel
. These are two objects of the same class that extends JPanel
and implements Mouselistener
.
What I want is that, if the user right mouse clicks on either panel, a JDialog
pops up at the mouse location. Alas, it doesn't, and I simply cannot find out how to get the correct behaviour (after trying loads of things). Can you help me?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DialogPositioning extends JFrame {
public DialogPositioning() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add two silly panels, then show this JFrame object
add(new NonsensePanel(Color.YELLOW), BorderLayout.NORTH);
add(new NonsensePanel(Color.GREEN), BorderLayout.CENTER);
pack();
setVisible(true);
}
private class NonsensePanel extends JPanel implements MouseListener {
NonsensePanel(Color bgColor) {
setPreferredSize(new Dimension(200,200));
setBackground(bgColor);
addMouseListener(this);
}
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
new NonsenseDialog(this, e.getX(), e.getY()); //popup a home-made JDialog at mouse position
}
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
}
private class NonsenseDialog extends JDialog {
NonsenseDialog(Component c, int x, int y) {
//Add a simple, emmpty panel to this JDialog so that there is something to see, then show this JDialog at the x,y position relative to Component c
JPanel pnl = new JPanel();
pnl.setPreferredSize(new Dimension(100, 100));
add(pnl);
pack();
setModal(true);
setLocationRelativeTo(c); //Should ensure the dialog pops up at posn x,y relative to the top/left corner of ...
setLocation(x, y); //... Component c (in our case the yellow or green NonsensePanel objects). DOES NOT WORK???
setVisible(true);
}
}
public static void main(String[] args) {
new DialogPositioning();
}
}
Upvotes: 0
Views: 630
Reputation: 2486
Edit: You should use camickr's answer, as it is the better solution.
The issue you are having here is, that the coordinates returned by e.getX()
and e.getY()
are relative to the corresponding JPanel
where you clicked. But when you pass these coordinates into your JDialog
and use them with setLocation(x, y)
, these coordinates will be relative to your screen.
You are missing a mapping between your original coordinates and your target coordinates.
If you want to keep the custom dialog and not use e.g. JPopupMenu
(which provides this for free), you can just copy the way that JPopupMenu#show()
handles this. (See here)
For your example, using the code from the link above, the changes to the NonsenseDialog
should look like the following:
private class NonsenseDialog extends JDialog {
NonsenseDialog(Component c, int x, int y) {
// code taken from jpopupmenu#show
Point invokerOrigin;
if (c != null) {
invokerOrigin = c.getLocationOnScreen();
// To avoid integer overflow
long lx, ly;
lx = ((long) invokerOrigin.x) + ((long) x);
ly = ((long) invokerOrigin.y) + ((long) y);
if (lx > Integer.MAX_VALUE)
lx = Integer.MAX_VALUE;
if (lx < Integer.MIN_VALUE)
lx = Integer.MIN_VALUE;
if (ly > Integer.MAX_VALUE)
ly = Integer.MAX_VALUE;
if (ly < Integer.MIN_VALUE)
ly = Integer.MIN_VALUE;
setLocation((int) lx, (int) ly);
} else {
setLocation(x, y);
}
// your code here
setVisible(true);
}
}
What this does is, it takes the coordinates from the component you clicked (your JPanel
) and adds the coordinates you passed to the dialog (the coordinates relative to the panel), then uses the resulting coordinates to set the location of the dialog.
With this approach, your dialog should pop up at the origin of the right click.
Upvotes: 0
Reputation: 324098
The getPoint()
method of the MouseEvent
will return the point that is relative to the panel.
The setLocation(...)
method sets the JDialog
relative to the screen.
So you need to convert the mouse point to the screen location.
I would change your NonsenseDialog to receive the mouse Point as a parameter (instead of the separate x/y values).
So you would use the getPoint()
method of the MouseEvent
to pass to your class.
Then in the constructor of your class you can use:
Point location = SwingUtilities.convertPointToScreen(...);
setLocation( location );
Upvotes: 1