views:

411

answers:

4

How should I detect that column moved action is finished in JTable? I've added columnModeListener to my column model but the problem is columnMoved method is called every time a column moves (by certain pixels). I don't want this behavior. I just want to detect when the column dragging is finished.

columnModel.addColumnModelListener(new TableColumnModelListener() {

            public void columnAdded(TableColumnModelEvent e) {
            }

            public void columnRemoved(TableColumnModelEvent e) {
            }

            public void columnMoved(TableColumnModelEvent e) {
                //this is called so many times
                //I don't want this, but something like column moved finished event
                System.out.println("Moved "+e.getFromIndex()+", "+e.getToIndex());
            }

            public void columnMarginChanged(ChangeEvent e) {
            }

            public void columnSelectionChanged(ListSelectionEvent e) {
            }
        });

I hope it is clear what I'm looking for. Thanks.

A: 

If I understand you correctly, maybe you want to look at the mouse listeners. Maybe the MOUSE_RELEASED event?

Jon
how should I do that? MOUSE_RELEASED on what? table?
chown
Are you clicking and dragging a column? At some point, that action will trigger the appropriate mouse events. The MouseListener may not know what it is you're dragging exactly, but you do, and you can just listen for the button to be unpressed.
Jon
@Jon, I think your suggestion implies addition of a MouseListener to the JTable. But with that the methods in MouseListener are invoked even when the column isn't dragged.
sateesh
@sateesh. That's right. I cannot add mouse listener to column model but only to jtable. If I follow this oath, I need to keep a flag to check whether a column has been dragged and the mouse has been released. But this seems so dirty and lengthy. An obvious feature such as this shouldn't be a part of JTable.
chown
You're right, it's a bit of a hack. I like the way Jason does it but without knowing the mouse state I don't think there's much you can do. I guess the argument for not tying the move-complete into the table API itself is probably that there's no reason to assume anything's being done with a mouse in the first place. You could be moving with the keyboard, or with other code, etc. Anything mouse-specific would just need a MouseListener, and only graphical components themselves make sense to have them. :/
Jon
+3  A: 

Here's an inner class I use to determine when the column ordering has changed. Note that the user may not have let go of the mouse at this point, so the dragging may continue further.

private class ColumnUpdateListener implements TableColumnModelListener {

   int lastFrom = 0;
   int lastTo = 0;

   private void verifyChange(int from, int to) {
      if (from != lastFrom || to != lastTo) {
         lastFrom = from;
         lastTo = to;

         ///////////////////////////////////////
         // Column order has changed!  Do something here
         ///////////////////////////////////////
      }
   }

   public void columnMoved(TableColumnModelEvent e) {
      verifyChange(e.getFromIndex(), e.getToIndex());
   }

   public void columnAdded(TableColumnModelEvent e) {
      verifyChange(e.getFromIndex(), e.getToIndex());
   }

   public void columnRemoved(TableColumnModelEvent e) {
      verifyChange(e.getFromIndex(), e.getToIndex());
   }

   public void columnMarginChanged(ChangeEvent e) {}
   public void columnSelectionChanged(ListSelectionEvent e) {}

}

It's worked well for me.

Jason Nichols
It's better than the default behavior but still the column order changes more frequently. I just need to observe drag finish because I need save the order of all the columns as soon as drag is completed (I don't want to call my expensive saving method that frequently). I'm posting what I ended up doing. Thanks for writing down the codes though. Might be helpful for someone coming for a similar functionality.
chown
+1 given that we can't add a mouse listener to the column this seems to me a clever way to detect that column dragging ended.
sateesh
Understandable. I wrote the above code because saving the column order to preferences on every columnMoved() event was eating up the CPU. I think the TableColumnModelListener is lacking.
Jason Nichols
+1  A: 

This is what I ended up doing. I know it is dirty, but it fits for what I'm looking:

boolean dragComplete = false;
        apTable.getTableHeader().addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (dragComplete) {
                    System.out.println("Drag completed");
                }
                dragComplete = false;
            }
        });
        columnModel.addColumnModelListener(new TableColumnModelListener() {

            public void columnAdded(TableColumnModelEvent e) {
            }

            public void columnRemoved(TableColumnModelEvent e) {
            }

            public void columnMoved(TableColumnModelEvent e) {
                dragComplete = true;
            }

            public void columnMarginChanged(ChangeEvent e) {
            }

            public void columnSelectionChanged(ListSelectionEvent e) {
            }
        });
chown
A: 

This might be a better approach:

table.setTableHeader(new JTableHeader(table.getColumnModel()) {

      @Override
      public void setDraggedColumn(TableColumn column) {
        boolean finished = draggedColumn != null && column == null;
        super.setDraggedColumn(column);
        if (finished) {
          onColumnChange(table); // Handle the event here...
        }
      }
    });
Mark