2010-01-29 27 views
11

应该如何检测在JTable中移动操作完成的列?我已经将columnModeListener添加到我的列模型中,但问题是columnMoved方法在每次列移动时(通过某些像素)都会调用。我不想要这种行为。我只想检测列拖动结束的时间。列在JTable中移动[完成]事件

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) { 
      } 
     }); 

我希望这是清楚我要找的。谢谢。

+0

你必须知道,当用户完成拖动列,或就足以知道什么时候列的顺序实际上已经改变(但用户仍可以进一步拖动它)? – 2010-01-29 18:16:20

+0

我只想知道用户何时完成拖动列。列顺序更改通知如何?我应该如何实现? – ashokgelal 2010-01-29 18:38:58

+0

http://stackoverflow.com/questions/1543981/is-there-an-event-called-when-a-column-is-moved-in-a-jtable – Ben 2012-05-11 00:19:07

回答

14

这就是我最终做的。我知道这是肮脏的,但它适合什么我在寻找:

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) { 
      } 
     }); 
+1

+1脏的,这实际上可以很好地表现我目前的应用程序,它(其他人一样的应用程序可能不会太)保存宽度,顺序和排序,以一个首选项文件信息。每次在标题中释放鼠标时,我都会保存文件,拖动和移动时所有的绒毛都不会再影响保存。 – Ben 2012-05-13 23:07:50

+1

我会说出布尔“拖”或类似的,你选择的名称比较混乱...... :-)感谢您问这个问题呢。 – PhiLho 2012-07-31 14:34:34

+0

我也这样做,虽然我有我自己的表头类,但概念是相同的,它的工作原理。 – DejanLekic 2012-11-08 09:19:42

0

如果我正确理解你,也许你想看看鼠标听众。也许MOUSE_RELEASED事件?

+0

我应该怎么做呢? MOUSE_RELEASED什么?表? – ashokgelal 2010-01-29 18:00:39

+0

你是否在点击并拖动一列?在某个时候,该动作将触发适当的鼠标事件。 MouseListener可能不知道你准确拖动的是什么,但是你可以,并且你可以只听按钮被按下。 – Jon 2010-01-29 18:05:12

+0

我认为你的建议意味着将一个MouseListener添加到JTable中。但是,即使列没有被拖动,MouseListener中的方法也会被调用。 – sateesh 2010-01-29 18:18:26

4

下面是我用来确定列排序何时发生变化的内部类。请注意,此时用户可能没有放开鼠标,因此拖动可能会继续进行。

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) {} 

}

它的工作很适合我。

+1

它比默认行为更好,但列顺序更改频率更高。我只需要观察拖动完成情况,因为我需要在拖动完成后立即保存所有列的顺序(我不想经常拨打我昂贵的存储方法)。我发布了我最终做的事情。感谢您编写代码。可能会有人来参加类似的功能。 – ashokgelal 2010-01-29 18:55:58

+0

+1因为我们不能鼠标监听器添加到这个在我看来,列聪明的方式来检测该列拖动结束。 – sateesh 2010-01-29 18:58:29

+0

可以理解。我写了上面的代码,因为将列顺序保存到每个columnMoved()事件的偏好设置上都吃掉了CPU。我认为TableColumnModelListener是缺乏的。 – 2010-01-29 18:58:47

2

这可能是一个更好的方法:

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... 
     } 
     } 
    }); 
+0

好主意,因为头已经拥有了自己的鼠标监听,即使JavaDoc的说:“应用程序代码将无法使用此方法显式地“... :-)可能需要与columnMoved事件组合以获取from和value。 – PhiLho 2012-07-31 14:32:54

1

这对我来说(包括柱的运动和保证金调整大小是什么在起作用):

我在扩展表并重写columnMovedcolumnMarginChanged 方法以下列方式:

...先加s为保持领先状态

private int lastMovementDistance = 0; 
private boolean bigMove = false; 
private boolean resizeBegan = false; 

青梅变量...

@Override 
public void columnMarginChanged(ChangeEvent e) { 
    super.columnMarginChanged(e); 
    if (isShowing()){ 
     resizeBegan = true; 
    } 
} 

@Override 
public void columnMoved(TableColumnModelEvent e) { 
    super.columnMoved(e); 

    //this will be set to 0 when the column is dragged 
    //to where it should begin if released  
    lastMovementDistance = Math.abs(getTableHeader().getDraggedDistance()); 


    if (e.getFromIndex() != e.getToIndex()){ 
    //note, this does not guarantee that the columns will be eventually 
    //swapped - the user may move the column back. 
    //but it prevents us from reacting to movements where 
    //the user hasn't even moved the column further then its nearby region. 
    //Works for me, because I don't care if the columns stay the same 
    //I only need the updates to be infrequent and don't want to miss 
    //changes to the column order 
bigMove = true; 
    } 
} 

...然后在我的表的构造函数我这样做:

public MyTable(){ 

    ... 

getTableHeader().addMouseListener(new MouseAdapter(){ 

    public void mouseReleased(MouseEvent evt) { 
     if (bigMove && lastMovementDistance == 0){ 
     //react! the tables have possibly switched! 
     } 

      else if (resizeBegan){ 
    //react! columns resized 
     } 

     resizeBegan = false; 
     bigMove = false; 
} 
}); 
    ... 
} 

它有点像一个黑客,但它适用于我。

-1

所有答案在一个用例中失败:如果表格在填充整个窗口的布局中,那么调整窗口大小将调整表格和列的大小。通过查看列标题上的鼠标事件,我们无法在用户调整窗口大小时收到事件。

我查看了JTable &朋友的源代码,并且columnMarginChanged()方法始终在由JTable.doLayout()调用的sub-sub-sub ...-函数中调用。

然后,我的解决方案是监视触发至少一个columnMarginChanged()的doLayout()调用。

实际上,columnMarginChanged()是为每一列调用的。

这里是我的解决方案:

private class ResizableJTable extends JTable { 

    private TableColumnModelListener columnModelListener; 

    private boolean columnsWereResized; 

    @Override 
    public void setColumnModel(TableColumnModel columnModel) { 
     if (getColumnModel() != null) { 
      getColumnModel().removeColumnModelListener(columnModelListener); 
      columnModelListener = null; 
     } 

     if (columnModel != null) { 
      columnModelListener = new TableColumnModelListener() { 

       public void columnSelectionChanged(ListSelectionEvent e) { 
        // Nothing to do 
       } 

       public void columnRemoved(TableColumnModelEvent e) { 
        // Nothing to do 
       } 

       public void columnMoved(TableColumnModelEvent e) { 
        // Nothing to do 
       } 

       public void columnMarginChanged(ChangeEvent e) { 
        columnsWereResized = true; 
       } 

       public void columnAdded(TableColumnModelEvent e) { 
        // Nothing to do 
       } 
      }; 

      columnModel.addColumnModelListener(columnModelListener); 
     } 

     super.setColumnModel(columnModel); 
    } 

    @Override 
    public void doLayout() { 
     columnsWereResized = false; 
     super.doLayout(); 
     if (columnsWereResized) { 
      onColumnsResized(); 
     } 
    } 

    /** 
    * Sub-classes can override this method to 
    * get the columns-were-resized event. 
    * By default this method must be empty, 
    * but here we added debug code. 
    */ 
    protected void onColumnsResized() { 
     int[] columnSizes = getColumnSizes(); 
     String sizes = ""; 
     for (int i : columnSizes) { 
      sizes += i + " "; 
     } 
     System.out.println("COLUMNS RESIZED: [ " + sizes + "]"); 
    } 

    protected int[] getColumnSizes() { 
     TableColumnModel columnModel = getTableHeader().getColumnModel(); 
     int columnCount = columnModel.getColumnCount(); 
     int[] columnSizes = new int[columnCount]; 

     for(int i = 0; i < columnCount; i++) { 
      TableColumn column = columnModel.getColumn(i); 
      columnSizes[i] = column.getWidth(); 
     } 

     return columnSizes; 
    } 
} 
+0

我不确定你想说什么,但我想你可能是错的。调整列大小不会移动列。调整大小后,列索引是相同的。 OP想要知道什么时候“Column Moved”事件完成的好方法。 – hfontanez 2015-07-17 14:44:25

1

在你自己的问题ashokgelal尼斯的答案。我觉得有点改进。您的代码也可以通过单击标题来触发。当列还没有真正改变时,再使用一个标志可以防止'dragComplete'触发器。 修改后的代码:

boolean mDraggingColumn = false; 
    boolean mColumnCHangedIndex = false; 

    tblObjects.getTableHeader().addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (mDraggingColumn && mColumnCHangedIndex) { 
       System.out.println("Column changed"); 
      } 
      mDraggingColumn = false; 
      mColumnCHangedIndex = false; 
     } 
    }); 
    tblObjects.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 
     @Override 
     public void columnAdded(TableColumnModelEvent e) {} 
     @Override 
     public void columnRemoved(TableColumnModelEvent e) {} 
     @Override 
     public void columnMoved(TableColumnModelEvent e) { 
      mDraggingColumn = true; 
      if (e.getFromIndex() != e.getToIndex()) { 
       mColumnCHangedIndex = true; 
      } 
     } 
     @Override 
     public void columnMarginChanged(ChangeEvent e) {} 
     @Override 
     public void columnSelectionChanged(ListSelectionEvent e) {} 
    });