14 Replies Latest reply: Mar 14, 2010 5:49 PM by 843807 RSS

    JList where mouse click acts like ctrl-mouse click

    843807
      I'd like to create a JList where I can select multiple items as if the control key were down, but without having the control key down. I thought that perhaps I could do this by extending JList and overriding its processMouseEvent method, setting the MouseEvent object to think that control is pressed and then calling the super method like so, but it doesn't work (I still need to press the control key to get my desired effect):
      import java.awt.Component;
      import java.awt.event.InputEvent;
      import java.awt.event.MouseEvent;
      
      import javax.swing.*;
      
      public class Ctrl_Down_JList {
        private static void createAndShowUI() {
          String[] items = {"Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"};
          
          JList myJList = new JList(items) {
            @Override
            protected void processMouseEvent(MouseEvent e) {
              
              // change the modifiers to believe that control key is down
              int modifiers = e.getModifiers() | InputEvent.CTRL_DOWN_MASK;
              
              // can I use this anywhere?  I don't see how to change the 
              // modifiersEx of the MouseEvent
              int modifiersEx = e.getModifiersEx() | InputEvent.CTRL_DOWN_MASK;
              
              MouseEvent myME = new MouseEvent(
                  (Component) e.getSource(), 
                  e.getID(), 
                  e.getWhen(), 
                  modifiers, // my changed modifier
                  e.getX(), 
                  e.getY(), 
                  e.getXOnScreen(), 
                  e.getYOnScreen(), 
                  e.getClickCount(), 
                  e.isPopupTrigger(), 
                  e.getButton());
              super.processMouseEvent(myME);
            }
          };
          
          JFrame frame = new JFrame("Ctrl_Down_JList");
          frame.getContentPane().add(new JScrollPane(myJList));
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
        }
      
        public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
              createAndShowUI();
            }
          });
        }
      }
      Any ideas would be much appreciated!
        • 1. Re: JList where mouse click acts like ctrl-mouse click
          843807
          Any ideas would be much appreciated!
          Here is a hack, idea is same as yours, but using Robot:
          public static void createAndShowUI2() {
               String[] items = { "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat" };
          
               final JList myJList = new JList(items);
               myJList.addMouseListener(new MouseAdapter() {
                    Robot robot;
                    {
                         try {
                              robot = new Robot();
                         } catch (AWTException ex) {
                              ex.printStackTrace();
                         }
                    }
          
                    @Override
                    public void mouseEntered(MouseEvent e) {
                         if (robot != null)
                              robot.keyPress(KeyEvent.VK_CONTROL);
                    }
          
                    @Override
                    public void mouseExited(MouseEvent e) {
                         if (robot != null)
                              robot.keyRelease(KeyEvent.VK_CONTROL);
                    }
               });
               JFrame frame = new JFrame("Ctrl_Down_JList");
               frame.getContentPane().add(new JScrollPane(myJList));
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               frame.pack();
               frame.setLocationRelativeTo(null);
               frame.setVisible(true);
          }
          It does work, but there has to be some cleaner way of doing this, perhaps using SelectionModel but I don't know about it.

          Thanks!

          Edit: I found that if Control key is pressed manually, then this hack obviously, to handle this, it has to made dirtier:
          myJList.addMouseListener(new MouseAdapter() {
               Robot robot;
               {
                    try {
                         robot = new Robot();
                    } catch (AWTException ex) {
                         ex.printStackTrace();
                    }
               }
               Timer timer = new Timer(20, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                         if (robot != null)
                              robot.keyPress(KeyEvent.VK_CONTROL);
                    }
               });
               
                  @Override
               public void mouseEntered(MouseEvent e) {
                    if (robot != null) {
                         robot.keyPress(KeyEvent.VK_CONTROL);
                         timer.start();
                    }
               }
               
                  @Override
               public void mouseExited(MouseEvent e) {
                    if (robot != null) {
                         robot.keyRelease(KeyEvent.VK_CONTROL);
                         timer.stop();
                    }
               }
          });
          Edited by: T.B.M on Mar 13, 2010 10:06 PM
          • 2. Re: JList where mouse click acts like ctrl-mouse click
            Darryl Burke
            JList's processMouseEvent(...) is inherited form JComponent and doesn't handle selection. That's done in BasicListUI.Handler#mouseClicked(...).

            Private classes, private methods ... I'm thinking it might be easier (or not) to implement this via a custom ListSelectionModel.

            db

            edit Try this:
            import javax.swing.*;
            
            public class MultiSelectListDemo {
            
              public static void main(String[] args) {
                SwingUtilities.invokeLater(new Runnable() {
            
                  @Override
                  public void run() {
                    new MultiSelectListDemo().makeUI();
                  }
                });
              }
            
              public void makeUI() {
                String[] items = {"Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"};
                final JList list = new JList(items);
                list.setSelectionModel(new MultiListSelectionModel());
            
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.add(new JScrollPane(list));
                frame.setVisible(true);
              }
            }
            
            class MultiListSelectionModel extends DefaultListSelectionModel {
            
              @Override
              public void setSelectionInterval(int index0, int index1) {
                if (index0 != index1) {
                  super.setSelectionInterval(index0, index1);
                  return;
                }
                if (isSelectedIndex(index0)) {
                  super.removeSelectionInterval(index0, index1);
                } else {
                  super.addSelectionInterval(index0, index1);
                }
              }
            }
            Edited by: DarrylBurke
            • 3. Re: JList where mouse click acts like ctrl-mouse click
              843807
              DarrylBurke wrote:
              JList's processMouseEvent(...) is inherited form JComponent and doesn't handle selection. That's done in BasicListUI.Handler#mouseClicked(...).
              I didn't know this, but it makes sense and explains quite a bit of why it's not working. Thanks.
              Private classes, private methods ... I'm thinking it might be easier (or not) to implement this via a custom ListSelectionModel.
              I'll look into this. Thanks again Darryl

              /Pete
              • 4. Re: JList where mouse click acts like ctrl-mouse click
                843807
                The problem is you are using the wrong mask when doing your hack.

                InputEvent.CTRL_DOWN_MASK is used by ModifiersEx while InputEvent.CTRL_MASK is used by plain old Modifiers, sent to the MouseEvent constructor (for backwards compatibility). Change
                int modifiers = e.getModifiers() | InputEvent.CTRL_DOWN_MASK;
                to
                int modifiers = e.getModifiers() | InputEvent.CTRL_MASK;
                and it works.


                Edit: it also seems to work if you simply pass in the modifiersEx instead of your modifiers variable.
                • 5. Re: JList where mouse click acts like ctrl-mouse click
                  Darryl Burke
                  and it works.
                  An honest question, not a nitpick. Wouldn't that depend on processMouseEvent being executed before BasicListUI.Handler#mouseClicked(...) ? And is that behavior documented somewhere, or at least possible to infer from the API?

                  db
                  • 6. Re: JList where mouse click acts like ctrl-mouse click
                    843807
                    DarrylBurke wrote:
                    and it works.
                    An honest question, not a nitpick. Wouldn't that depend on processMouseEvent being executed before BasicListUI.Handler#mouseClicked(...) ? And is that behavior documented somewhere, or at least possible to infer from the API?

                    db
                    It is my understanding that JComponent.processMouseEvent notifies all the listeners. As to whether the behavior is documented - don't know but it would probably break a lot of people's code if it were to be implemented differently somehow. I've overriden processMouseEvent to filter out events I don't want the UI to process for instance.
                    • 7. Re: JList where mouse click acts like ctrl-mouse click
                      Darryl Burke
                      Thanks, Aephyr.

                      db
                      • 8. Re: JList where mouse click acts like ctrl-mouse click
                        843807
                        Aephyr wrote:
                        The problem is you are using the wrong mask when doing your hack.
                        That's it! Thanks!

                        I'm out of Dukes stars, but if you want some, I'll figure out a way to get you some. Again, thanks!
                        • 9. Re: JList where mouse click acts like ctrl-mouse click
                          Kleopatra
                          hope this thread is not regarded as so old that a comment is regarded as resurrection <g>
                          DarrylBurke wrote:
                          An honest question, not a nitpick. Wouldn't that depend on processMouseEvent being executed before BasicListUI.Handler#mouseClicked(...) ? And is that behavior documented somewhere, or at least possible to infer from the API?
                          Well, I think it's documented: all processXXEvent methods are documented as dispatching the XXEvents as they deem appropriate, f.i to registered XXlisteners. So it's one level-of-control above the listeners - which is what all ui-delegate installed Handlers are.

                          CU
                          Jeanette
                          • 10. Re: JList where mouse click acts like ctrl-mouse click
                            Darryl Burke
                            Thanks Jeanette, I had gathered that from looking at the sources.

                            And since this has already been resurrected, I'll hijack it to ask a question that's been on my mind: which would you consider the 'cleaner' way to achiever the desired result: a customized selection model or a synthetic mouse event? Or is it an even draw?

                            db
                            • 11. Re: JList where mouse click acts like ctrl-mouse click
                              Kleopatra
                              Darryl,

                              not sure if it's possible to do completely on the selection model level - once tried on SwingX JXDatePicker without success, felt like not enough information at the time of the setSelection to decide what exactly to do. So dropped the idea without further digging ;-)

                              CU
                              Jeanette
                              • 12. Re: JList where mouse click acts like ctrl-mouse click
                                Darryl Burke
                                not sure if it's possible to do completely on the selection model level
                                Isn't that what I showed at #2? or what did I miss this time?

                                Thanks, db
                                • 13. Re: JList where mouse click acts like ctrl-mouse click
                                  Kleopatra
                                  could be - didn't try your code snippet :-) Just saying that from my experience it turned out to be a dead end. Forgot the details, though.

                                  CU
                                  Jeanette
                                  • 14. Re: JList where mouse click acts like ctrl-mouse click
                                    Kleopatra
                                    after some sleep: the answer to the "cleaner" might be "depends" - on what exactly is the requirement. The base question is if you want to change the overall behaviour of the selectionModel's setSelectionInterval or if you want to change the effect of individual user gestures. Doing the first will effect all clients - ui delegates in their key and mouseListeners plus all application code which programatically sets the selection. Personally, would stick to plug into the event level until it turns out that I really need a generally changed model behaviour. Which might be violating super's contract (or not, too lazy to check right now :-)

                                    CU
                                    Jeanette