【问题标题】:How do I drag and drop a row in a JTable?如何在 JTable 中拖放一行?
【发布时间】:2010-10-12 22:25:24
【问题描述】:

如何设置 JTable 以便能够将行拖动到表中的不同索引。例如,如果我有 5 行,我想将第 4 行拖到第 2 位?

【问题讨论】:

  • 下面的答案有帮助吗?

标签: java swing drag-and-drop jtable mouse


【解决方案1】:

以下允许对单个拖动行进行 JTable 重新排序:

  table.setDragEnabled(true);
  table.setDropMode(DropMode.INSERT_ROWS);
  table.setTransferHandler(new TableRowTransferHandler(table)); 

您的 TableModel 应实现以下内容以允许重新排序:

public interface Reorderable {
   public void reorder(int fromIndex, int toIndex);
}

这个 TransferHandler 类处理拖放,并在手势完成时调用 TableModel 上的 reorder()。

/**
 * Handles drag & drop row reordering
 */
public class TableRowTransferHandler extends TransferHandler {
   private final DataFlavor localObjectFlavor = new ActivationDataFlavor(Integer.class, "application/x-java-Integer;class=java.lang.Integer", "Integer Row Index");
   private JTable           table             = null;

   public TableRowTransferHandler(JTable table) {
      this.table = table;
   }

   @Override
   protected Transferable createTransferable(JComponent c) {
      assert (c == table);
      return new DataHandler(new Integer(table.getSelectedRow()), localObjectFlavor.getMimeType());
   }

   @Override
   public boolean canImport(TransferHandler.TransferSupport info) {
      boolean b = info.getComponent() == table && info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
      table.setCursor(b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
      return b;
   }

   @Override
   public int getSourceActions(JComponent c) {
      return TransferHandler.COPY_OR_MOVE;
   }

   @Override
   public boolean importData(TransferHandler.TransferSupport info) {
      JTable target = (JTable) info.getComponent();
      JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
      int index = dl.getRow();
      int max = table.getModel().getRowCount();
      if (index < 0 || index > max)
         index = max;
      target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      try {
         Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
         if (rowFrom != -1 && rowFrom != index) {
            ((Reorderable)table.getModel()).reorder(rowFrom, index);
            if (index > rowFrom)
               index--;
            target.getSelectionModel().addSelectionInterval(index, index);
            return true;
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      return false;
   }

   @Override
   protected void exportDone(JComponent c, Transferable t, int act) {
      if ((act == TransferHandler.MOVE) || (act == TransferHandler.NONE)) {
         table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      }
   }

}

【讨论】:

  • 我在转移时遇到了异常,我通过将 localObjectFlavor 更改为:private final DataFlavor localObjectFlavor = new DataFlavor(Integer.class, "Integer Row Index"); 来解决此问题
  • +1 但不幸的是,这不适用于多行选择。
  • +1 - 一些简单的修改,效果很好!
  • 很好的例子!虽然我注意到 exportDone 中有一个错误。如果您将选定的值拖到组件外并释放,光标将保留“复制图标”。我通过将 exportDone 中的 if 语句修改为“act == TransferHandler.MOVE || act == TransferHandler.NONE”来纠正这个问题。
  • 很棒的代码。我遇到的一个问题是我不断收到java.lang.ClassCastException: java.lang.Integer cannot be cast to java.io.InputStream 错误。改用localObjectFlavor = new ActivationDataFlavor(Integer.class, "application/x-java-Integer;class=java.lang.Integer", "Integer Row Index") 解决了错误。
【解决方案2】:

查看 Java 教程的 drag and drop 部分。有一些关于如何为JTable 实现此功能的示例。

【讨论】:

    【解决方案3】:

    我喜欢 Soley 的修改,但是他的代码依赖于外部库,我不确定他从哪里得到它,所以我重新编写了它,这样你就不需要 TableUtil 类了......

     @Override
       public boolean importData(TransferHandler.TransferSupport info) {
         JTable target = (JTable) info.getComponent();
            JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
            int index = dl.getRow();
            int max = table.getModel().getRowCount();
            if (index < 0 || index > max) {
                index = max;
            }
            target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    
            try {
                Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
                if (rowFrom != -1 && rowFrom != index) {
    
                    int[] rows = table.getSelectedRows();
                    int iter = 0;
                    for (int row : rows) {
                        if (index > row) {
                            index--;
                            ((Reorderable) table.getModel()).reorder(row - iter, index);
                        }
    
                        else {
                            ((Reorderable) table.getModel()).reorder(row, index);
                        }
                        index++;
                        iter++;
                    }
    
                    target.getSelectionModel().addSelectionInterval(index, index);
    
                    return true;
                }
    
          } catch (Exception e) {
                String error = e.getMessage();
                JOptionPane.showMessageDialog(null, error, "Error", JOptionPane.ERROR_MESSAGE);
          }
          return false;
       }
    

    【讨论】:

      【解决方案4】:

      也许……像这样:

          table.addMouseMotionListener(new MouseMotionListener() {
          public void mouseDragged(MouseEvent e) {
              e.consume();
              JComponent c = (JComponent) e.getSource();
              TransferHandler handler = c.getTransferHandler();
              handler.exportAsDrag(c, e, TransferHandler.MOVE);
          }
      
          public void mouseMoved(MouseEvent e) {
          }
      });
      

      【讨论】:

        【解决方案5】:

        仅用于记录和多行重新排序:

        在某处使用....

         JTable table = t_objects;
            table.setDragEnabled(true);
            table.setDropMode(DropMode.INSERT_ROWS);
            table.setTransferHandler(new TableRowTransferHandler(table));
        

        这是上述答案中的主要类,我对其进行了修改以匹配多行 DnD 的需求。 我所做的只是使用第一个选定的行,然后计算放置位置上方的行。删除选定的项目并将它们保存在对象列表(行数组对象)中。然后将它们插入计算行。最后选择删除/拖动的行以完成该过程。

        public class TableRowTransferHandler extends TransferHandler {
        
            private final DataFlavor localObjectFlavor = new DataFlavor(Integer.class, "Integer Row Index");
            private JTable table = null;
        
            public TableRowTransferHandler(JTable table) {
                this.table = table;
            }
        
            @Override
            protected Transferable createTransferable(JComponent c) {
                assert (c == table);
                return new DataHandler(new Integer(table.getSelectedRow()), localObjectFlavor.getMimeType());
            }
        
            @Override
            public boolean canImport(TransferHandler.TransferSupport info) {
                boolean b = info.getComponent() == table && info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
                table.setCursor(b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
                return b;
            }
        
            @Override
            public int getSourceActions(JComponent c) {
                return TransferHandler.COPY_OR_MOVE;
            }
        
            @Override
            public boolean importData(TransferHandler.TransferSupport info) {
                JTable target = (JTable) info.getComponent();
                JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
                int index = dl.getRow();
                int max = table.getModel().getRowCount();
                if (index < 0 || index > max) {
                    index = max;
                }
                target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        
                try {
                    Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
                    if (rowFrom != -1 && rowFrom != index) {
        
                        int[] rows = table.getSelectedRows();
                        int dist = 0;
                        for (int row : rows) {
                            if (index > row) {
                                dist++;
                            }
                        }
                        index -= dist;
        
                        //**TableUtil** is a simple class that just copy, remove and select rows.
        
                        ArrayList<Object> list = TableUtil.getSelectedList(table);
                        TableUtil.removeSelected(table);
                        ArrayList<Integer> sels = new ArrayList<Integer>();
                        for (Object obj : list) {
                            sels.add(index);
                            TableUtil.addRowAt(table, obj, index++);
                        }
                        TableUtil.selectMultipleRow(table, sels);
        
        
                        return true;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return false;
            }
        
            @Override
            protected void exportDone(JComponent c, Transferable t, int act) {
                if (act == TransferHandler.MOVE) {
                    table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                }
            }
        }
        

        【讨论】:

        • 什么是 TableUtil?
        • 这是一个使处理行变得简单的类。方法名称描述了我们将从他们那里收到什么。可以用自己的方法替换,也可以使用 Table 自己的方法。
        猜你喜欢
        • 1970-01-01
        • 2010-10-17
        • 2016-03-14
        • 2010-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-15
        • 2012-10-04
        相关资源
        最近更新 更多