问题描述
我有一个 JList,其中包含一个自定义对象的 ArrayList,我正在尝试创建一个拖放到字段中的操作.我无法理解如何在 Transferable 中打包和接收对象.
I have a JList containing an ArrayList of custom objects and I'm trying to create a drag and drop into fields. I'm having trouble understanding how to package and receive the object in Transferable.
这大概是我得到的:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
public class FlightProjectInterface extends JFrame{
//create GUI Objects
private JFrame primaryFrame;
private JPanel createFlightPanel;
private JPanel aircraftLayout;
private JList personsJList, personsOnFlightJList;
private JTextField pilotLabel, coPilotLabel, backseat1Label, backseat2Label;
public FlightProjectInterface(){
//establish frame
super("Create Flight");
setLayout( new FlowLayout());
//aircraftPanel
aircraftLayout = new JPanel();
aircraftLayout.setLayout(new GridLayout(2,2));
pilotLabel = new JTextField("Drag Pilot Here");
//build person load list
DefaultListModel listModel = new DefaultListModel();
for (Person person : Database.persons)
listModel.addElement(person);
personsJList = new JList(listModel);
personsJList.setVisibleRowCount(5);
personsJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
personsJList.setDragEnabled(true);
add( new JScrollPane(personsJList) );
aircraftLayout.add(pilotLabel);
add(aircraftLayout);
}//end constructor
}
澄清:我无法从 JList 中选择对象并从中创建 Transferable.使用上面的代码,对象的 toString 表示只是粘贴在文本字段中,因此我无法从放置的位置提取对象数据.如何打包"对象本身并将其放入一个占位符中,以便我可以从 GUI 引用对象本身?
Clarification: I'm having trouble taking the object selection from the JList and creating a Transferable out of it. With the code above, the toString representation of the object is simply pasted in the text field, so I'm not able to pull object data from the dropped location. How can I "package" the object itself and drop it into a placeholder that I can reference the object itself from the GUI?
理想情况下,将有 4 个字段,每个字段都包含一个可以删除的对象.如果他们被删除,该人将从列表中删除,但如果被替换,则会返回到列表中.
Ideally, there would be 4 fields that each contains an object that can be dropped. The person would be removed from the list if they are dropped, but returned to the list if replaced.
推荐答案
拖放可能是一个复杂的野兽,并不会因为可用的冲突信息而变得更容易.就我个人而言,我喜欢避免使用 Transfer API,但我就是那样的老派.
Drag and Drop can be a complex beast, not made any easier by the conflicting information that's available. Personally, I like to avoid the Transfer API, but I'm old school like that.
DnD 的粘合剂实际上是 DataFlavor
.我更喜欢自己动手,让生活更轻松.
The glue to DnD really is the DataFlavor
. I prefer to roll my own, makes life a lot easier.
在这个例子中,我使用了一个 TransferHandler
,但实际上,你真的应该有一个用于拖放,一个用于放置,特别是,你应该为每个你想要的组件使用一个下车.
In this example, I've used a single TransferHandler
, but realistically, you really should have one for dragging and one for dropping, in particular, you should have one for each component you want to drop onto.
这样做的主要原因是,我在我的 canImport
方法中放了一个陷阱,如果你拖过一个 JList
就拒绝它,所以你只能把它放在JLabel
,这是一个小技巧,可能不是最好的主意.
The main reason for this is, I put a trap in my canImport
method to reject it if your dragging over a JList
, so you can only drop it on the JLabel
, this is a little hack and probably not the best idea.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.io.IOException;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DnDTransferableTest {
public static void main(String[] args) {
new DnDTransferableTest();
}
public DnDTransferableTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
@SuppressWarnings("serial")
public class TestPane extends JPanel {
private JList<ListItem> list;
private JLabel label;
public TestPane() {
list = new JList<ListItem>();
list.setDragEnabled(true);
list.setTransferHandler(new ListTransferHandler());
DefaultListModel<ListItem> model = new DefaultListModel<ListItem>();
for (int index = 0; index < 10; index++) {
model.addElement(new ListItem("Item " + index));
}
list.setModel(model);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weighty = 1;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.BOTH;
add(new JScrollPane(list), gbc);
label = new JLabel("Drag on me...");
gbc.gridx++;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.NONE;
add(label, gbc);
label.setTransferHandler(new ListTransferHandler());
}
}
@SuppressWarnings("serial")
public class ListTransferHandler extends TransferHandler {
@Override
public boolean canImport(TransferSupport support) {
return (support.getComponent() instanceof JLabel) && support.isDataFlavorSupported(ListItemTransferable.LIST_ITEM_DATA_FLAVOR);
}
@Override
public boolean importData(TransferSupport support) {
boolean accept = false;
if (canImport(support)) {
try {
Transferable t = support.getTransferable();
Object value = t.getTransferData(ListItemTransferable.LIST_ITEM_DATA_FLAVOR);
if (value instanceof ListItem) {
Component component = support.getComponent();
if (component instanceof JLabel) {
((JLabel)component).setText(((ListItem)value).getText());
accept = true;
}
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
return accept;
}
@Override
public int getSourceActions(JComponent c) {
return DnDConstants.ACTION_COPY_OR_MOVE;
}
@Override
protected Transferable createTransferable(JComponent c) {
Transferable t = null;
if (c instanceof JList) {
@SuppressWarnings("unchecked")
JList<ListItem> list = (JList<ListItem>) c;
Object value = list.getSelectedValue();
if (value instanceof ListItem) {
ListItem li = (ListItem) value;
t = new ListItemTransferable(li);
}
}
return t;
}
@Override
protected void exportDone(JComponent source, Transferable data, int action) {
System.out.println("ExportDone");
// Here you need to decide how to handle the completion of the transfer,
// should you remove the item from the list or not...
}
}
public static class ListItemTransferable implements Transferable {
public static final DataFlavor LIST_ITEM_DATA_FLAVOR = new DataFlavor(ListItem.class, "java/ListItem");
private ListItem listItem;
public ListItemTransferable(ListItem listItem) {
this.listItem = listItem;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{LIST_ITEM_DATA_FLAVOR};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(LIST_ITEM_DATA_FLAVOR);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return listItem;
}
}
public static class ListItem {
private String text;
public ListItem(String text) {
this.text = text;
}
public String getText() {
return text;
}
@Override
public String toString() {
return getText();
}
}
}
这篇关于将自定义对象从 JList 拖放到 JLabel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!