好的,这个问题不在我的联盟中。我正在尝试在swing中实现一个GUI小部件,允许将文件放到JTable上,并允许拖动JTable的行进行重新排序。想想VLC的播放列表或iTunes中的播放列表。
我从操作系统(资源管理器,Finder等)中删除文件工作得很好,但是一旦文件进入,我就有了重新安排表行的不可能的时间。问题是当我向表中添加自定义TransferHandler时,从拖动表会立即被杀死。以下是一些示例代码:
import javax.swing.*;
public class TableTest
{
public static void main (String [] argv)
{
// setup table data
String [] columns = new String [] {"Foo", "Bar", "Baz", "Quux"};
String [][] data = new String [][] {{"A", "B", "C", "D"},
{"1", "2", "3", "4"},
{"i", "ii", "iii", "iv"}};
// create table
JTable table = new JTable(data, columns);
// set up drag and drop
table.setDragEnabled(true);
table.setDropMode(DropMode.INSERT_ROWS);
table.setFillsViewportHeight(true);
TransferHandler dnd = new TransferHandler() {
// here be code to handle drops, and one would
// presume drag exporting, too
};
table.setTransferHandler(dnd);
JScrollPane scroll = new JScrollPane(table);
// create and show window
JFrame window = new JFrame();
window.getContentPane().add(scroll);
window.pack();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
}
按原样运行此代码,您将看到无法启动对表的拖动。如果您在表上注释掉对setTransferHandler()的调用,则拖动工作(即,当我开始拖动表行时,我得到X'd圆圈光标,说我不能放弃那里)。但是只要为表设置了TransferHandler,我就无法拖动任何行。问题必须在TransferHandler中,但是我彻底麻烦并调试它,并确定一旦桌面上有TransferHandler就永远不会开始拖动。我做错了什么?
答案 0 :(得分:5)
我遇到了同样的问题,它与您自定义的TransferHandler实现无关。当您替换TransferHandler时,您还需要保留默认的DragSource并告诉它识别拖动手势。您可能还需要实现自己的Transferable,因为您需要将它传递给DragGestureEvent.startDrag()方法。
table.setTransferHandler(new MyTransferHandler());
table.setDragEnabled(true);
DragSource source = DragSource.getDefaultDragSource();
source.createDefaultDragGestureRecognizer(table, DnDConstants.ACTION_COPY, new DragGestureListener() {
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
//grab the selected files from the table model
ArrayList<File> files = new ArrayList<File>();
for (int row : table.getSelectedRows()) {
files.add((File) dm.getValueAt(row, 1));
}
//FileTransferable is a custom Transferable implementation
Transferable transferable = new FileTransferable(files);
//and this is the magic right here
dge.startDrag(null,transferable);
}
});
答案 1 :(得分:3)
看起来你没有正确使用TransferHandler。尝试阅读教程here。
请参阅TransferHandler文档here。空构造函数看起来不适合在TransferHandler的子类之外使用。
并且您没有实现Swing组件上提供的标准TransferHandler中提供的任何功能。请参阅DnD教程here(我的粗体)中的exerpt:
注意:如果将自定义TransferHandler安装到Swing组件上,则会替换默认支持。例如,如果将JTextField的TransferHandler替换为仅处理颜色的TransferHandler,则将禁用其支持文本导入和导出的功能。 如果必须替换默认的TransferHandler(例如,处理文本的TransferHandler),则需要重新实现文本导入和导出功能。这不需要像Swing提供的那样广泛 - 它可以像支持StringFlavor数据风格一样简单,具体取决于您的应用程序的需求。
答案 2 :(得分:3)
我认为问题是空的TransferHandler实际上阻止了DnD事件的发生。这里有一个可能相关的样本。
http://www.java2s.com/Code/Java/Swing-JFC/ExtendedDnDDragandDropDemo.htm
答案 3 :(得分:1)
我不想深入了解正在发生的事情,所以我只是委托我对旧的TransferHandler不感兴趣的方法。
tree.setDragEnabled(true);
tree.setDropMode(DropMode.XXXX);
tree.setTransferHandler(new MyTransferHandler(tree.getTransferHandler());
从标准设置开始,但将旧的TransferHandler传递到您的自定义TransferHandler。
private class MyTransferHandler extends TransferHandler {
private TransferHandler delegate;
public MyTransferHandler(TransferHandler delegate) {
this.delegate = delegate;
}
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
return delegate.canImport(comp, transferFlavors);
}
public boolean canImport(TransferSupport support) {
return true;
}
protected Transferable createTransferable(JComponent c) {
try {
Method method = delegate.getClass().getDeclaredMethod("createTransferable", JComponent.class);
method.setAccessible(true);
return (Transferable) method.invoke(delegate, c);
} catch (Exception e) {
return super.createTransferable(c);
}
}
public void exportAsDrag(JComponent comp, InputEvent event, int action) {
delegate.exportAsDrag(comp, event, action);
}
protected void exportDone(JComponent source, Transferable data, int action) {
try {
Method method = delegate.getClass().getDeclaredMethod("exportDone", JComponent.class, Transferable.class,
int.class);
method.setAccessible(true);
method.invoke(delegate, source, data, action);
} catch (Exception e) {
super.exportDone(source, data, action);
}
}
public int getSourceActions(JComponent c) {
return delegate.getSourceActions(c);
}
public Icon getVisualRepresentation(Transferable t) {
return delegate.getVisualRepresentation(t);
}
public boolean importData(JComponent comp, Transferable t) {
return delegate.importData(comp, t);
}
public boolean importData(TransferHandler.TransferSupport support) {
return delegate.importData(support);
}
}
一个问题是createTransferable(JComponent)和exportDone(JComponent,Transferable,int)方法受到保护,因此您需要进行反射才能委派给这些方法。当我没有做这个反思代表时,策略不起作用。一旦我执行了这个委托,拖放工作按预期工作而不更改DragSource或必须编写新的Transferable。