here is my problem: I have a jList and a popup menu. When I right click the jList, the popup menu shows. The problem is that the jList item which the mouse is pointing at won't se开发者_如何学运维lect. And I want it to do that. When I point my cursor at an item in the list and press the right button, I want two things to happen. Select the item on which I clicked and show the popup menu.
I tried this:
jLists.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
jList.setSelectedIndex(jList.locationToIndex(e.getPoint()));
}
});
jList.setComponentPopupMenu(jPopupMenu);
But it only shows the popup menu. If I delete this line:
jList.setComponentPopupMenu(jPopupMenu);
then the right-click select works (but the popup menu doesn't show).
So, what do you think is the best way to make these two functions (both) work ?
Thanks and sorry for my english.
Don't do setComponentPopupMenu
. In the MouseAdapter
do the following:
public void mousePressed(MouseEvent e) {check(e);}
public void mouseReleased(MouseEvent e) {check(e);}
public void check(MouseEvent e) {
if (e.isPopupTrigger()) { //if the event shows the menu
jList.setSelectedIndex(jList.locationToIndex(e.getPoint())); //select the item
jPopupMenu.show(jList, e.getX(), e.getY()); //and show the menu
}
}
This should work.
EDIT: The code now checks both press
and release
events, because some platforms show popups when mouse presses and some other on release. See the Swing tutorial for more info.
If you want to continue to use setComponentPopupMenu
(which is nice because it handles mouse and keyboard invocations of the popup in a cross platform way), you could override JPopupMenu.show(Component, int, int)
to select the appropriate row.
JPopupMenu jPopupMenu = new JPopupMenu() {
@Override
public void show(Component invoker, int x, int y) {
int row = jList.locationToIndex(new Point(x, y));
if (row != -1) {
jList.setSelectedIndex(row);
}
super.show(invoker, x, y);
}
};
jList.setComponentPopupMenu(jPopupMenu);
Note that when your popup is invoked via the keyboard (and you don't also override getPopupLocation
on your target component), the x, y location you get in JPopupMenu.show
will be the midpoint of your component. If there's already a selection in this case you probably don't want to change the selection.
The solution I came up with to solve the keyboard vs. mouse invocation problem was to set a client property on the component in an override of getPopupLocation
and then check it when showing the popup. The argument to getPopupLocation
will be null
when invoked via the keyboard. Here's the core code (perhaps implemented in a utility class available to your component and its popup menu).
private static final String POPUP_TRIGGERED_BY_MOUSE_EVENT = "popupTriggeredByMouseEvent"; // NOI18N
public static Point getPopupLocation(JComponent invoker, MouseEvent event)
{
boolean popupTriggeredByMouseEvent = event != null;
invoker.putClientProperty(POPUP_TRIGGERED_BY_MOUSE_EVENT, Boolean.valueOf(popupTriggeredByMouseEvent));
if (popupTriggeredByMouseEvent)
{
return event.getPoint();
}
return invoker.getMousePosition();
}
public static boolean isPopupTriggeredByMouseEvent(JComponent invoker)
{
return Boolean.TRUE.equals(invoker.getClientProperty(POPUP_TRIGGERED_BY_MOUSE_EVENT));
}
Then override getPopupLocation
in your component:
@Override
public Point getPopupLocation(MouseEvent event)
{
return PopupMenuUtils.getPopupLocation(this, event);
}
and call isPopupTriggeredByMouseEvent
in an override of JPopupMenu.show
to determine whether or not to select the row at the popup location (or whatever action may make sense for the underlying component):
JPopupMenu jPopupMenu = new JPopupMenu() {
@Override
public void show(Component invoker, int x, int y) {
int row = jList.locationToIndex(new Point(x, y));
if (row != -1 && PopupMenuUtils.isPopupTriggeredByMouseEvent((JComponent) invoker)) {
jList.setSelectedIndex(row);
}
super.show(invoker, x, y);
}
};
精彩评论