4 Replies Latest reply on Jan 11, 2004 5:55 AM by 807587

    Smoother Drag Drop JList JTable

    807587
      Hi all,

      I have been adding drag/drop to several JTable widgets in my application, and was not satisfied with the operation of dragging in JTable and JList. (I am working with Java 1.4.2 on SOLARIS).

      Specifically:

      1.     When clicking, a row selection is made, however dragging the mouse after that does not trigger the drag operation. In order to commence the drag operation the user must click again, in the selected row, and then drag the mouse.

      2.     When dragging, rows in the JTable and JList are selected as the mouse cursor moves over the rows in the widget ? I find this somewhat disconcerting.

      I started working with the code from the tutorial: ?Extending Default DnD Support?, http://java.sun.com/docs/books/tutorial/uiswing/misc/dnd.html that demonstrates both of the problems I have with JList and JTable drag/drop.

      By extending JTable and JList is have overcome the above problems, and have included the extended classes here incase they are of use to anyone. In addition, if anyone spots any major flaw in what I am trying to do, or knows a better way to solve the above problems, please let me know.

      Regards,

      Nick


      The following code can be added to the end of the java file in the tutorial: ExtendedDnDDemo.java, and then the DnDJList and DnDJTable objects should be created instead of JList and JTable in the tutorial.
      /**
       * A JTable with (in my opinion) improved DragDrop.
       */
      
      class DnDJTable extends JTable {
          
          private boolean canSelect = true;
          private boolean isDragging;
          private MouseEvent pressEvent = null;
          
          /**
           * Constructor for NTable.
           */
          public DnDJTable() {
              super();
          }
      
          /**
           * Constructor for NTable.
           * @param dm
           */
          public DnDJTable(TableModel dm) {
              super(dm);
          }
      
          /**
           * Constructor for NTable.
           * @param dm
           * @param cm
           */
          public DnDJTable(TableModel dm, TableColumnModel cm) {
              super(dm, cm);
          }
      
          /**
           * Constructor for NTable.
           * @param dm
           * @param cm
           * @param sm
           */
          public DnDJTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
              super(dm, cm, sm);
          }
      
          /**
           * @see java.awt.Component#processMouseMotionEvent(java.awt.event.MouseEvent)
           */
          protected void processMouseMotionEvent(MouseEvent e) {
              handleMouseEvent(e);
              super.processMouseMotionEvent(e);
          }
      
          /**
           * @see java.awt.Component#processMouseEvent(java.awt.event.MouseEvent)
           */
          protected void processMouseEvent(MouseEvent e) {
              handleMouseEvent(e);
              super.processMouseEvent(e);
          }
          
          /**
           * Performs two tasks:
           * 1. Start Drag/Drop.
           * Commence drag/drop operation if we are not already dragging.
           * Commencing a drag/drop requires the mouse event of the MOUSE_PRESSED
           * kind - which has hopefully been recorded before the MOUSE_DRAGGED mouse event
           * is received.
           * 
           * 2. Disable row selection while dragging.
           * 
           * @param e the mouse event
           */
          private void handleMouseEvent(MouseEvent e) {
              canSelect = (e.getID() != MouseEvent.MOUSE_DRAGGED);
              if (e.getID() == MouseEvent.MOUSE_PRESSED) {
                  isDragging = false;
                  pressEvent = e;
              } else if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
                  if (!isDragging && pressEvent != null) {
                      TransferHandler handler = getTransferHandler();
                      handler.exportAsDrag(this, pressEvent, TransferHandler.COPY);
                  }
                  pressEvent = null;
                  isDragging = true;
              } else if (e.getID() == MouseEvent.MOUSE_RELEASED) {
                  isDragging = false;
              }
          }
          
          /**
           * Only permit row selection if we are not dragging.
           * @see javax.swing.JTable#changeSelection(int, int, boolean, boolean)
           */
          public void changeSelection(
              int rowIndex,
              int columnIndex,
              boolean toggle,
              boolean extend) {
                  
              if (canSelect) {
                  super.changeSelection(rowIndex, columnIndex, toggle, extend);
              }
          }
      
          /**
           * Only permit row selection if we are not dragging.
           * @see javax.swing.JTable#setColumnSelectionInterval(int, int)
           */
          public void setColumnSelectionInterval(int index0, int index1) {
              if (canSelect) {
                  super.setColumnSelectionInterval(index0, index1);
              }
          }
      
          /**
           * Only permit row selection if we are not dragging.
           * @see javax.swing.JTable#setRowSelectionInterval(int, int)
           */
          public void setRowSelectionInterval(int index0, int index1) {
              if (canSelect) {
                  super.setRowSelectionInterval(index0, index1);
              }
          }
      
      }
      
      
      
      /**
       * A JList with (in my opinion) improved Drag/Drop.
       */
      
      class DnDJList extends JList {
          
          private boolean canSelect = true;
          private boolean isDragging;
          private MouseEvent pressEvent = null;
          
          /**
           * Constructor for NList.
           * @param dataModel
           */
          public DnDJList(ListModel dataModel) {
              super(dataModel);
          }
      
          /**
           * Constructor for NList.
           * @param listData
           */
          public DnDJList(Object[] listData) {
              super(listData);
          }
      
          /**
           * Constructor for NList.
           * @param listData
           */
          public DnDJList(Vector listData) {
              super(listData);
          }
      
          /**
           * Constructor for NList.
           */
          public DnDJList() {
              super();
          }
      
          /**
           * @see java.awt.Component#processMouseMotionEvent(java.awt.event.MouseEvent)
           */
          protected void processMouseMotionEvent(MouseEvent e) {
              handleMouseEvent(e);
              super.processMouseMotionEvent(e);
          }
      
          /**
           * Only permit row selection if we are not dragging.
           * @see javax.swing.JList#setSelectionInterval(int, int)
           */
          public void setSelectionInterval(int anchor, int lead) {
              if (canSelect) {
                  super.setSelectionInterval(anchor, lead);
              } 
          }
          
          /**
           * @see java.awt.Component#processMouseEvent(java.awt.event.MouseEvent)
           */
          protected void processMouseEvent(MouseEvent e) {
              handleMouseEvent(e);
              super.processMouseEvent(e);
          }
          
          /**
           * Performs two tasks:
           * 1. Start Drag/Drop.
           * Commence drag/drop operation if we are not already dragging.
           * Commencing a drag/drop requires the mouse event of the MOUSE_PRESSED
           * kind - which has hopefully been recorded before the MOUSE_DRAGGED mouse event
           * is received.
           * 
           * 2. Disable row selection while dragging.
           * 
           * @param e the mouse event
           */
          protected void handleMouseEvent(MouseEvent e) {
              canSelect = (e.getID() != MouseEvent.MOUSE_DRAGGED);
              if (e.getID() == MouseEvent.MOUSE_PRESSED) {
                  isDragging = false;
                  pressEvent = e;
              } else if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
                  if (!isDragging && pressEvent != null) {
                      TransferHandler handler = getTransferHandler();
                      handler.exportAsDrag(this, pressEvent, TransferHandler.COPY);
                  }
                  pressEvent = null;
                  isDragging = true;
              } else if (e.getID() == MouseEvent.MOUSE_RELEASED) {
                  isDragging = false;
                  pressEvent = null;
              }       
          }
      }
        • 1. Re: Smoother Drag Drop JList JTable
          807587
          Yup, that is what happens with the 1.4 drag and drop, it's
          pretty annoying that you can't click and drag. However, it
          does work with the old drag and drop system, which you have
          already found out. I ran into the same problem when I
          converted to 1.4. I never found a way around it except
          going back to the old way. But now the product is deprecated,
          so I don't have to worry about it. :)

          However, you shouldn't have to override the processMouse events.
          Look at the java.awt.dnd package. The Drag/Drop Listeners there
          should be all you need to implement.

          Good luck!

          Matt
          • 2. Re: Smoother Drag Drop JList JTable
            807587
            Thanks for the feedback Matt - i will try your suggestions using the DnD listeners - but I wonder, will that stop the row selection "following" the dragging mouse cursor (problem number 2, from my first entry)?

            ...will let you know....

            - Nick

            • 3. Re: Smoother Drag Drop JList JTable
              807587
              Hey thanks for posting this solution- I had been working to disable the continued-selection-during-drag "feature" for a couple hours before checking the forums.

              I really like coding in Java- except for Swing. It baffles me that the default DnD behavior is so clunky. I mean does any native windowing toolkit require an explicit selection before begining a drag? And why does a JList contiue selecting nodes after a drag has begun? Is there any reasonable argument that can be made for why it works that way? It's a good thing the rest of the Java story is so compelling or we would all be using .Net...
              • 4. Re: Smoother Drag Drop JList JTable
                807587
                We worked out a similar solution in this thread:

                http://forum.java.sun.com/thread.jsp?forum=57&thread=465997

                The solution forJTable I think is analogous to the JList solution (but I have not tried it).

                As far as your issue #2, I did two different things. SInce I am only dragging from list to another (not dragging within a list), the first thing I did was turn off the drop target of the list I was dragging from (which turns off selection from source list). The second thing was to create a custom cell renderer for the destination list that did not draw selected items differently than non-selected items only when dragging.