JTable 中的列移动 [完成] 事件

发布于 2024-08-19 23:54:38 字数 866 浏览 3 评论 0原文

我应该如何检测 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) {
            }
        });

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

旧伤慢歌 2024-08-26 23:54:38

这就是我最终所做的。我知道它很脏,但它适合我正在寻找的东西:

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

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) {
            }
        });
想挽留 2024-08-26 23:54:38

这是我用来确定列顺序何时更改的内部类。请注意,此时用户可能还没有松开鼠标,因此拖动可能会继续进行。

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

对我来说效果很好。

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.

枕花眠 2024-08-26 23:54:38

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

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

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...
        }
      }
    });
杯别 2024-08-26 23:54:38

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

我扩展表格并覆盖 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;
 } 
 });
  ...
}

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

This is what works for me (both column movements and margin resizes):

I extend the table and override the columnMoved and columnMarginChanged
methods in the following way:

... first add some variables for state keeping

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

... then in the constructor of my table i do this:

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

It is kinda like a hack, but it works for me.

等待我真够勒 2024-08-26 23:54:38

关于您自己的问题的答案很好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) {}
    });

Nice answer on your own question ashokgelal. Just a little improvement I think. Your code also trigger on single click on the header. Using one more flag you can prevent the 'dragComplete' trigger when the column haven't really changed.
Modified code:

    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) {}
    });
醉生梦死 2024-08-26 23:54:38

如果我理解正确的话,也许你想看看鼠标监听器。也许是 MOUSE_RELEASED 事件?

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

肥爪爪 2024-08-26 23:54:38

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

我查看了 JTable&friends 源代码,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;
    }
}

All answers fail at one use-case: if the table is in a layout filling up the entire window, then resizing the window will resize the table and thus its columns. By watching for mouse events on the column headers, we fail to receive the event when the user resize the window.

I looked at the JTable&friends source-code, and the columnMarginChanged() method is always called in a sub-sub-sub...-function called by JTable.doLayout().

Then, my solution is to watch for doLayout() calls that trigger at least one columnMarginChanged().

In fact, columnMarginChanged() is called for every columns.

Here is my solution:

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文