将自定义对象从 JList 拖放到 JLabel

Posted

技术标签:

【中文标题】将自定义对象从 JList 拖放到 JLabel【英文标题】:Drag and Drop custom object from JList into JLabel 【发布时间】:2012-12-01 01:37:26 【问题描述】:

我有一个包含自定义对象的 ArrayList 的 JList,我正在尝试创建拖放到字段中的操作。我无法理解如何在 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 引用对象本身的占位符?

理想情况下,应该有 4 个字段,每个字段都包含一个可以删除的对象。如果他们被删除,该人将从列表中删除,但如果被替换,则返回到列表中。

【问题讨论】:

“我无法理解如何在 Transferable 中打包和接收对象。” 请参阅Drag and Drop and Data Transfer 并在您尝试过后再联系我们可以提出具体问题。 我已经读了几个小时了。我无法从 JList 中选择对象并从中创建可转移对象。使用上面的代码,对象的 toString 表示只是简单地粘贴在文本字段中,因此我无法从放置的位置获取对象数据。 cannot find symbol symbol: variable Database location: class FlightProjectInterface - 为了尽快获得更好的帮助,请发布SSCCE。 【参考方案1】:

拖放可能是一种复杂的野兽,可用的相互矛盾的信息并没有使它变得更容易。就个人而言,我喜欢避免使用 Transfer API,但我是这样的老派。

DnD 的粘合剂确实是DataFlavor。我更喜欢自己动手,让生活更轻松。

在此示例中,我使用了一个 TransferHandler,但实际上,您确实应该有一个用于拖放,一个用于拖放,尤其是每个要拖放的组件都应该有一个。

这样做的主要原因是,我在我的canImport 方法中设置了一个陷阱,如果您拖过JList,则拒绝它,所以您只能将其放在JLabel 上,这是一个小技巧和可能不是最好的主意。

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();
        
    

【讨论】:

这正是我想要的,完美的解释!谢谢! 你是指单身Transferable还是单身TransferHandler @johnchen902 谁知道我的意思,我觉得你说得对,听起来像TransferHandler 如果我可能会问,它是否打算在 importData() 方法的末尾始终返回 false @LucasMorgan 不,认为这是我的疏忽

以上是关于将自定义对象从 JList 拖放到 JLabel的主要内容,如果未能解决你的问题,请参考以下文章

自定义对象从 FX 拖放到 Swing

Qt学习之路(54): 自定义拖放数据对象

使用自定义数据将 QTreeWidgetItem 拖放到 QGraphicsView

无法将自定义对象从 API 保存到核心数据

Android将自定义对象从服务传递给活动

使用拖放重新排序 JList