Java 如何避免在JTable中对单个列重新排序?

Java 如何避免在JTable中对单个列重新排序?,java,swing,jtable,Java,Swing,Jtable,我有一个JTable,我需要能够对列重新排序。但是,我希望第一列不能重新排序。我使用以下选项来启用重新排序: table.getTableHeader().setReorderingAllowed(true); 这些列现在可以重新排序,包括我不想要的第一列。有没有办法锁定第一列 我看到一些解决方案使用两个表,第一列在一个单独的表中,但可能有更好/更简单的方法。我认为您需要覆盖TableColumnModelListener中的columnMoved()方法。TableColumnModelEv

我有一个
JTable
,我需要能够对列重新排序。但是,我希望第一列不能重新排序。我使用以下选项来启用重新排序:

table.getTableHeader().setReorderingAllowed(true);
这些列现在可以重新排序,包括我不想要的第一列。有没有办法锁定第一列


我看到一些解决方案使用两个表,第一列在一个单独的表中,但可能有更好/更简单的方法。

我认为您需要覆盖
TableColumnModelListener
中的
columnMoved()
方法。
TableColumnModelEvent
类有一个
getFromIndex()
方法,您可以查看该方法以确定它是否是您的固定列,然后可以取消该事件


希望有帮助。A

首先,您需要定义一种更好、更简单的方法。您不喜欢2表方法的哪些方面

不能使用TableColumnModelListener,因为事件是在列已被移动的“之后”触发的

在BasicTableHeaderUI中可以找到用于拖动列的代码。因此,您可以尝试重写那里的代码,但随后需要对所有LAF执行此操作

上面的代码对mousePressed事件调用JTableHeader.getReorderingAllowed()以确定是否允许列重新排序。我想您可以在JTableHeader中重写该方法,或者使用MouseInfo类获取当前鼠标位置,以确定它是否位于第一列上,然后返回false。但是现在您还需要创建一个使用自定义表头的自定义JTable

当然,有了上述任何一个建议,您都可以防止移动第一列。但不要忘记,还需要防止第二列插入到第一列之前。我认为这个问题没有简单的答案


这是我用两个表实现的版本。更好吗?我不知道,但它很简单,因为它只有一行代码可以使用。

我也有同样的问题,我正在搜索它。到目前为止,我找到了两种方法

  • 如果我自己重写它”方法:从Java修改基类
TableColumn
需要一个新属性,比如“resizingAllowed”,它需要“reorderingAllowed”。 由此,在
BasicTableHeaderUI
中进行修改:

已经有:

private static boolean canResize(TableColumn column,
                                 JTableHeader header) {
    return (column != null) && header.getResizingAllowed()
                            && column.getResizable();
}
它还需要:

private static boolean canMove(TableColumn column,
                               JTableHeader header) {
    return (column != null) && header.getReorderingAllowed()
                                && column.getReorderable();
}
(请注意,如果不希望仅移动第一列,则无需更改TableColumns即可:

private static boolean canMove(TableColumn column,
                                 JTableHeader header) {
    return (column != null) && header.getReorderingAllowed()
                            && header.getColumnModel().getColumnIndex(column.getIdentifier()) != 0;
}
)

之后,在
鼠标输入侦听器中有两个要修改的位置:

  • 在按下的
    鼠标中,调用
    canMove()
    ,而不是
    标题。getReorderingAllowed()
    。这样可以确保不应移动的列不会移动
  • 但这还不够,我们需要防止在拖动另一根柱子时移动不动的柱子。在获取“newColumnIndex”时,还需要更改鼠标标记的

    if(0
如果可以移动此新索引,则需要添加条件,例如使用“canMove()”方法。这样,当您将一列拖动到此固定列时,您仍然会拖动它,但它不会交换它们

请注意,此方法将要求您显式设置用于JTable的JTableHeader的UI,但这并不理想。但这是最适合的,因为它在它应该去的地方处理问题


  • 方法“让我们试着用我们实际拥有的来阻止正常行为”:该方法不修改UI,而是关注JTableHeader来阻止UI发出的命令
首先,要阻止拖动第一列,我们需要JTableHeader中的一个子类,使用以下重写方法:

@Override
public void setDraggedColumn(TableColumn pAColumn)
{
    int lIndex  = -1;
    if (pAColumn != null)
        lIndex = getColumnModel().getColumnIndex(pAColumn.getIdentifier());
    if (lIndex != 0)
        super.setDraggedColumn(pAColumn);
}
@Override
public void moveColumn(int pColumnIndex, int pNewIndex)
{
    //Move only if the first column is not concerned
    if (pColumnIndex =! 0 && pNewIndex != 0)
        super.moveColumn(pColumnIndex, pNewIndex);
}
这将防止用户拖动第一列。但正如前面所描述的,这只是问题的一部分,我们需要防止另一个拖动的列与第一个列交换

到目前为止,我还没有一个正确的方法。我尝试将TableColumnModel子类化,并重写
moveColumn()
方法:

@Override
public void setDraggedColumn(TableColumn pAColumn)
{
    int lIndex  = -1;
    if (pAColumn != null)
        lIndex = getColumnModel().getColumnIndex(pAColumn.getIdentifier());
    if (lIndex != 0)
        super.setDraggedColumn(pAColumn);
}
@Override
public void moveColumn(int pColumnIndex, int pNewIndex)
{
    //Move only if the first column is not concerned
    if (pColumnIndex =! 0 && pNewIndex != 0)
        super.moveColumn(pColumnIndex, pNewIndex);
}
但这不起作用,因为UI将更新
mouseDragged
方法中的鼠标位置,您将从拖动的列跳转到另一个位置

所以我还在搜索,不知道是否有人对这一部分提出了建议。

我使用了“让我们用我们实际拥有的方法来阻止正常行为”的方法Gnoupi说他没有解决问题的第二部分。以下是仅适用于Windows XP L&F的解决方案:

  • 将XPStyle类复制到您自己
  • 扩展
    WindowsTableHeaderUI
    。请看下面的图片
  • 使用它:
    getTableHeader().setUI(新的TreeTableWindowsTableHeaderUI())

  • 感谢Gnoupi的努力。

    这是我用来防止第1列被重新排序的解决方案

    private int columnValue = -1; 
    private int columnNewValue = -1; 
    
    
    tblResults.getColumnModel().addColumnModelListener(new TableColumnModelListener() 
    { 
        public void columnAdded(TableColumnModelEvent e) {} 
    
        public void columnMarginChanged(ChangeEvent e) {} 
    
        public void columnMoved(TableColumnModelEvent e) 
        { 
            if (columnValue == -1) 
                columnValue = e.getFromIndex(); 
    
            columnNewValue = e.getToIndex(); 
        } 
    
        public void columnRemoved(TableColumnModelEvent e) {} 
    
        public void columnSelectionChanged(ListSelectionEvent e) {} 
    }); 
    
    tblResults.getTableHeader().addMouseListener(new MouseAdapter() 
    { 
        @Override 
        public void mouseReleased(MouseEvent e) 
        { 
            if (columnValue != -1 && (columnValue == 0 || columnNewValue == 0)) 
            tblResults.moveColumn(columnNewValue, columnValue); 
    
            columnValue = -1; 
            columnNewValue = -1; 
        } 
    }); 
    

    干杯,

    近4年后,仍然没有看到任何最佳解决方案

    另一种防止拖动第一列(以及第一列上的其他列)的次优方法是在uidelegate安装的mouseInputListener能够处理mouseEvents()之前拦截mouseEvents

    合作者

    • 自定义MouseMotionListener,它将所有事件委托给最初安装的,但拖动的事件除外,前提是它将导致第一列之上的另一列
    • 将原始文件替换为自定义文件
    • 每当LAF发生变化时更新更换件(因为原始
      table.getTableHeader().setUI(new WindowsTableHeaderUI() {
              @Override
              protected MouseInputListener createMouseInputListener() {
                  return new BasicTableHeaderUI.MouseInputHandler() {
      
                      @Override
                      public void mouseDragged(MouseEvent e) {
                          if (header.isEnabled() && header.getReorderingAllowed() && header.getDraggedColumn() != null && header.getDraggedColumn().getModelIndex() == frozenColumnModelIndex) {
                              header.setDraggedDistance(0);
                              header.setDraggedColumn(null);
                              return;
                          }
                          super.mouseDragged(e);
                      }
      
                      @Override
                      public void mouseReleased(MouseEvent e) {
                          if (header.isEnabled() && header.getReorderingAllowed() && header.getDraggedColumn() != null &&
                              0 <= illegalTableColumnMoveFromIndex && illegalTableColumnMoveFromIndex < header.getTable().getColumnModel().getColumnCount()) {
                              header.setDraggedDistance(0);
                              header.setDraggedColumn(null);
                              header.getTable().getColumnModel().moveColumn(illegalTableColumnMoveToIndex, illegalTableColumnMoveFromIndex);
                              illegalTableColumnMoveFromIndex = -1;
                              illegalTableColumnMoveToIndex = -1;
                              return;
                          }
                          super.mouseReleased(e);
                      }
                  };
              }
          });
          table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
              @Override
              public void columnAdded(TableColumnModelEvent e) {
              }
      
              @Override
              public void columnRemoved(TableColumnModelEvent e) {
              }
      
              @Override
              public void columnMoved(TableColumnModelEvent e) {
                  if (e.getFromIndex() != e.getToIndex() && table.getColumnModel().getColumn(e.getFromIndex()).getModelIndex() == frozenColumnModelIndex) {
                      illegalTableColumnMoveFromIndex = e.getFromIndex();
                      illegalTableColumnMoveToIndex = e.getToIndex();
                  } else {
                      illegalTableColumnMoveFromIndex = -1;
                      illegalTableColumnMoveToIndex = -1;
                  }
              }
      
              @Override
              public void columnMarginChanged(ChangeEvent e) {
              }
      
              @Override
              public void columnSelectionChanged(ListSelectionEvent e) {
              }
          });
      
      @Override
      public void moveColumn(int from, int to) {
            super.moveColumn(from, to);
            if (from == 0 || to == 0) {
                 super.moveColumn(to, from);
            }
      }