列在JTable中移动[finished]事件

时间:2010-01-29 17:46:24

标签: java swing events jtable

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

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

我希望很清楚我在寻找什么。感谢。

7 个答案:

答案 0 :(得分: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 :(得分: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) {}

}

这对我有用。

答案 2 :(得分:3)

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

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

答案 3 :(得分:1)

这对我有用(列移动和边距调整大小):

我扩展表并覆盖columnMovedcolumnMarginChanged 方法如下:

...首先添加一些状态保存变量

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

它有点像黑客,但它对我有用。

答案 4 :(得分:1)

关于你自己的问题ashokgelal的答案很好。我认为只是一点点改进。您的代码也会在单击标题时触发。再使用一个标记,您可以阻止“拖动完成”'当列没有真正改变时触发。 修改后的代码:

g(long)

答案 5 :(得分:0)

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

答案 6 :(得分:-1)

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

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

然后,我的解决方案是监视触发至少一个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;
    }
}