I love the forum - having postponed for some time to implement popups because of exactly this problem :-) Thanks.
Just a comment though:
the recommended approach for deciding about showing a popup is to check for e.isPopupTrigger() (instead of isRightButton) in both mousePressed and mouseReleassed because the interpretation is OS-dependent. Adjusting the code to do so makes it tricky to know the time when the selection is done and the popup should be shown. The solution I came up with is to wrap the showing into a SwingUtilities.invokeLater().
Well here is another way to do this without the need
to use a Robot.
The problem with this code is that it resets the selection as this handler thinks is right and ignores what the UIDelegate would do. Using the robot will give the UIDelegatethe chance to first do its work as usual (f.i. set/extend/add selections) and then trigger the popup. I really like it - don't have to duplicate all the selection/edit terminating/whatever code in the internal mouseHandler, but that's just my opinion :-)
The solution I came up with is to wrap the showing into a SwingUtilities.invokeLater().
I would be interested in seeing your final solution.
I am only working with Windows 98, so I have no knowledge of other platforms. In Windows applications (IE, Outlook, ...):
a) mousePressed causes the selection to occur
b) mouseReleased caused the popup to appear
So we need some code in mousePressed to select the item. However, when I used e.isPopupTrigger() it was always returning false (it only returns true in the mouseReleased() method).
So if you require item selection on mousePressed then you could change the code as follows:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
publicclass SelectAndPopup implements MouseListener
{
private JPopupMenu popup;
public SelectAndPopup(JPopupMenu popup)
{
this.popup = popup;
}
publicvoid mousePressed(MouseEvent e)
{
if ( SwingUtilities.isRightMouseButton(e) )
{
try
{
Robot robot = new java.awt.Robot();
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
catch (AWTException ae) {}
}
}
publicvoid mouseReleased(MouseEvent e)
{
if (e.isPopupTrigger())
{
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
publicvoid mouseClicked(MouseEvent e) {}
publicvoid mouseEntered(MouseEvent e) {}
publicvoid mouseExited(MouseEvent e) {}
publicstaticvoid main(String[] args)
{
JPopupMenu popup = new JPopupMenu();
popup.add( new JMenuItem("Do Something1") );
popup.add( new JMenuItem("Do Something2") );
popup.add( new JMenuItem("Do Something3") );
String[] data = { "zero", "one", "two", "three", "four", "five" };
JList list = new JList( data );
list.addMouseListener( new SelectAndPopup( popup ) );
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( new JScrollPane(list) );
frame.setSize(400, 100);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}
If you don't care about item selection on mousePressed, then you can replace the mousePressed/mouseRelease methods from above with:
I am only working with Windows 98, so I have no
knowledge of other platforms. In Windows applications
(IE, Outlook, ...):
a) mousePressed causes the selection to occur
b) mouseReleased caused the popup to appear
you are right -should have checked before :-)
So we have several issues here:
1) winLF is behaving incorrectly by not selecting on a right mousePressed. Hmm... does it happen always, even if there is no popup to show? Could not find an example...
2) make sure the selection is updated at the time we are showing the popup
The first is handled by using the robot in right pressed, the second is not an issue if the popup trigger is "released" - as in win - but maybe an issue if the popup trigger is in the pressed as well. I can't really verify it (I'm on win2k) but tried to simulate the situation by manually interpreting a "right pressed" as popup gesture - and simulating the popup by writing out the selection. Without the invokeLater the list selection has the old value:
privatevoid installMouseHandler(JList list) {
list.addMouseListener(new MouseAdapter() {
publicvoid mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
try {
Robot robot = new java.awt.Robot();
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
} catch (AWTException ae) {
System.out.println(ae);
}
}
maybePopupTrigger(e);
}
privatevoid maybePopupTrigger(MouseEvent e) {
// this is for win - working as expected
// if (e.isPopupTrigger()) {
// next line is for simulating a popup trigger on pressed
if (SwingUtilities.isRightMouseButton(e)
&& (e.getID() == MouseEvent.MOUSE_PRESSED)) {
showPopup(e);
}
}
privatevoid showPopup(final MouseEvent e) {
// without invokeLater
// selection is not yet updated if we simulated
// the popup trigger on pressed
SwingUtilities.invokeLater(new Runnable() {
publicvoid run() {
System.out.println(e);
JList list = (JList) e.getSource();
System.out.println(list.getSelectedValue() + " selected");
}
});
}
publicvoid mouseReleased(MouseEvent e) {
maybePopupTrigger(e);
}
});
}
could somebody on another OS check this (with the "real" trigger), please?
How is the selection behaviour on right-pressed in other OS? I faintly remember some discussions in the early days of Swing when a right - pressed did change the selection (though not consistently across JList, JTable, ...). The outcome of these was the current behaviour.
My first example was not very good as I got lazy and just displayed the selected item, rather than displaying a real popup. I found that when I tried to display a real popup it would not display, even when the popup code was added to a SwingUtilities.invokeLater(). I mention this because your code is also just showing the selected item and not a real popup.
My second example is more realistic and does show the the popup as expected, but it has only been tested on Windows 98.
My first example was not very good as I got lazy and
just displayed the selected item, rather than
displaying a real popup. I found that when I tried to
display a real popup it would not display, even when
the popup code was added to a
SwingUtilities.invokeLater(). I mention this because
your code is also just showing the selected item and
not a real popup.
Hmm... don't know why a popup should not show. Sounds to me like being unrelated to the selection state which is the real issue here (my real code actually shows a popup in the runnable instead of printing out the selection): we have to guarantee that the selection has been changed before showing the popup. That seems to be problematic if both the robot's mouseEvent and the popuptrigger happen in the same mouseXX. If the selection is changed in the pressed and the popup triggered in the release, all is working without the need for invokeLater. Could be wrong, though.
this topic became really interisting. Thanks for your help so far. Now I have another problem ;-)
My Application supports drag&drop. In an table the user is able to multiselect rows und then drag it to another place. With the new MouseListener-solution there will be a new selection of one single row when the mouse is clicked. the "multi-line-drag-and-drop" is no more possible.
I have no idea, how to combine the listeners to get the optimal solution. please help me again.
to continue this thread on the original topic, for me this robot code doesnt work (Java5) in a way that the current row doesnt get selected - popup appears though.
Another choice would be to go directly to the UI Delegate:
publicclass MBTableUI extends BasicTableUI {
protected MouseInputListener createMouseInputListener() {
returnnew MyMouseInputHandler();
}
class MyMouseInputHandler extends MouseInputHandler {
publicvoid mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
// select the current table row somehow
} else {
// not a right click
super.mousePressed(e);
}
}
}
}
But there are some problems. I solved this with a plain mouseListener on first try and it was ok, i got the row selected, but when you have Multiple_Selection activated on your table, it gets tricky, because it will kill the multiple selection and only select the current one. So i trashed my first approach and are now on the way to implement it correctly.
BTW i know Kleopatra is using and coding JGoodies, someone posted an enhancement to ExtBasicTableUI that should also do this trick. I still didnt have the time to check it out., but i can post the code if someone wants to see it.