如何在 JTable 中拖放一行?
Posted
技术标签:
【中文标题】如何在 JTable 中拖放一行?【英文标题】:How do I drag and drop a row in a JTable? 【发布时间】:2010-10-12 22:25:24 【问题描述】:如何设置 JTable 以便能够将行拖动到表中的不同索引。例如,如果我有 5 行,我想将第 4 行拖到第 2 位?
【问题讨论】:
下面的答案有帮助吗? 【参考方案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 自己的方法。以上是关于如何在 JTable 中拖放一行?的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:如何在 macOS 上从 Mail 中拖放电子邮件