0

过去一周我试图解决这个问题,但不知何故我似乎无法找到解决方案。关于这个主题的信息不多,因此很难找到示例或代码来查看。

我这里有一个 JList,它使用创建自定义 Transferable 的自定义 TransferHandler,供参考,这里是所涉及类的代码:

可转让:

package org.dinhware.swing.special;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

/**
 * Created by: Niklas
 * Date: 20.10.2017
 * Alias: Dinh
 * Time: 20:03
 */

public class GenericTransferable<T> implements Transferable {
    static DataFlavor FLAVOR;
    private T object;

    GenericTransferable(T object) {
        GenericTransferable.FLAVOR = new DataFlavor(object.getClass(), object.getClass().getCanonicalName());
        this.object = object;
    }

    @Override
    public DataFlavor[] getTransferDataFlavors() {
        return new DataFlavor[]{FLAVOR};
    }

    @Override
    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return flavor.equals(FLAVOR);
    }

    @Override
    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
        return object;
    }
}

传输处理程序:

package org.dinhware.swing.special;

import javax.swing.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

/**
 * Created by: Niklas
 * Date: 19.10.2017
 * Alias: Dinh
 * Time: 18:54
 */

@SuppressWarnings("unchecked")
public class HListItemTransferHandler<T> extends TransferHandler {

    @Override
    protected Transferable createTransferable(JComponent component) {
        JList<T> list = (JList<T>) component;
        index = list.getSelectedIndex();
        T transferredObject = list.getSelectedValue();
        return new GenericTransferable<>(transferredObject);
    }

    @Override
    public boolean canImport(TransferSupport info) {
        return info.isDataFlavorSupported(GenericTransferable.FLAVOR);
    }

    @Override
    public int getSourceActions(JComponent c) {
        return MOVE;
    }

    @Override
    public boolean importData(TransferSupport info) {
        if (!canImport(info)) {
            return false;
        }

        JList<Object> target = (JList<Object>) info.getComponent();
        JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
        DefaultListModel<Object> listModel = (DefaultListModel<Object>) target.getModel();
        int index = dl.getIndex();
        int max = listModel.getSize();

        if (index < 0 || index > max)
            index = max;

        addIndex = index;

        try {
            Object object = info.getTransferable().getTransferData(GenericTransferable.FLAVOR);
            listModel.add(index, object);
            target.addSelectionInterval(index, index);
            return moveAllowed = true;
        } catch (UnsupportedFlavorException | IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    protected void exportDone(JComponent c, Transferable data, int action) {
        if (moveAllowed)
            cleanup(c, action == MOVE, false);

    }

    private void cleanup(JComponent component, boolean remove, boolean bin) {
        if (remove && index != -1) {
            JList<T> source = (JList<T>) component;
            DefaultListModel<T> model = (DefaultListModel<T>) source.getModel();
            int removeAt = index > addIndex ? index + 1 : index;
            model.remove(bin ? removeAt - 1 : removeAt);
        }

        index = -1;
        addIndex = -1;
        moveAllowed = false;
    }

    private int index = -1;
    private int addIndex = -1;
    private boolean moveAllowed = false;
}

HBin

package org.dinhware.swing.child;

import org.dinhware.swing.special.HListItemTransferHandler;

import javax.swing.*;

/**
 * Created by: Niklas
 * Date: 20.10.2017
 * Alias: Dinh
 * Time: 19:57
 */

public class HBin<T> extends HImageLabel {
    public HBin(String text, Icon image, int distance) {
        super(text, image, distance);
        setTransferHandler(new HListItemTransferHandler<T>());
    }
}

以及它应该如何工作的可视化,可悲的是,即使没有将容器拖到 Hbin 容器上,它也总是会消失。我一直以为它一直在工作,直到我不小心把它移到了我的框架之外,它仍然消失了。上面的代码只允许在预期的列表内拖放。

在此处输入图像描述

我的问题是如何添加功能以正确使容器仅在拖到 Hbin 容器上时才消失

我使用的代码的第一部分是这个

@Override
protected void exportDone(JComponent c, Transferable data, int action) {
    if (moveAllowed) cleanup(c, action == MOVE, false);
    else try {
        if (data.getTransferData(GenericTransferable.FLAVOR) instanceof RewardItem) {
            cleanup(c, true, true);
        }
    } catch (UnsupportedFlavorException | IOException e) {
        e.printStackTrace();
    }
}

我背后的逻辑是 List 和 Hbin 共享相同的类型(RewardItem),我可以比较,后来我意识到(在制作该方法的更通用版本之后)数据将始终是 RewardItem 类型并且总是会导致在清理电话中。这导致了我目前仍然面临的错误。

我今天早些时候采取的方法真的让我质疑自己的想法,也让我写了这篇文章。我在名为 bin 的 TransferHandler 中添加了一个布尔值,默认情况下为 false。在 canImport 签入 importData 之后,我添加bin = info.getComponent() instanceof HBin了我认为应该可以工作的内容。但这个领域总是假的。我继续为它添加了一个日志

System.out.println("IMPORT");
if (info.getComponent() instanceof HBin) {
    System.out.println("bin");
    return bin = true;
}

它最终打印了 IMPORT,然后是 bin。在调用 importData exportData 之后,我在其中记录了 bin 的值,无论出于何种原因,它现在再次为 false。与此同时,moveAllowed 字段似乎发生了变化。

这是我完全修改过的 TransferHandler

package org.dinhware.swing.special;

import org.dinhware.swing.child.HBin;

import javax.swing.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

/**
 * Created by: Niklas Date: 19.10.2017 Alias: Dinh Time: 18:54
 */

@SuppressWarnings("unchecked")
public class HListItemTransferHandler<T> extends TransferHandler {

    @Override
    protected Transferable createTransferable(JComponent component) {
        System.out.println("CREATE");
        JList<T> list = (JList<T>) component;
        index = list.getSelectedIndex();
        T transferredObject = list.getSelectedValue();
        return new GenericTransferable<>(transferredObject);
    }

    @Override
    public boolean canImport(TransferSupport info) {
        return info.isDataFlavorSupported(GenericTransferable.FLAVOR);
    }

    @Override
    public int getSourceActions(JComponent c) {
        System.out.println("ACTION");
        return MOVE;
    }

    @Override
    public boolean importData(TransferSupport info) {
        System.out.println("IMPORT");
        if (!canImport(info)) {
            return false;
        }
        if (info.getComponent() instanceof HBin) {
            System.out.println("bin");
            return bin = true;
        }

        JList<Object> target = (JList<Object>) info.getComponent();
        JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
        DefaultListModel<Object> listModel = (DefaultListModel<Object>) target.getModel();
        int index = dl.getIndex();
        int max = listModel.getSize();

        if (index < 0 || index > max)
            index = max;

        addIndex = index;

        try {
            Object object = info.getTransferable().getTransferData(GenericTransferable.FLAVOR);
            listModel.add(index, object);
            target.addSelectionInterval(index, index);
            return moveAllowed = true;
        } catch (UnsupportedFlavorException | IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    protected void exportDone(JComponent c, Transferable data, int action) {
        System.out.println("EXPORT " + moveAllowed + "/" + bin);
        if (moveAllowed)
            cleanup(c, action == MOVE, false);
        else
            cleanup(c, true, true);

    }

    private void cleanup(JComponent component, boolean remove, boolean bin) {
        System.out.println("CLEAN");
        if (remove && index != -1) {
            JList<T> source = (JList<T>) component;
            DefaultListModel<T> model = (DefaultListModel<T>) source.getModel();
            int removeAt = index > addIndex ? index + 1 : index;
            model.remove(bin ? removeAt - 1 : removeAt);
        }

        index = -1;
        addIndex = -1;
        moveAllowed = false;
    }

    private int index = -1;
    private int addIndex = -1;
    private boolean moveAllowed = false, bin = false;
}   

在列表内移动时一切正常(打印)

ACTION
CREATE
IMPORT
EXPORT true/false
CLEAN

但是当掉到 Hbin 容器上时,我无法解释发生了什么(打印)

ACTION
CREATE
IMPORT
bin
EXPORT false/false

我很确定它应该是假/真

现在我被卡住了,无法使容器仅在放到 Hbin 上时消失,同时也对字段值在明确记录它已设置为 true 时没有改变感到困惑。

请帮忙...

4

1 回答 1

1

Drag'n'Drop 很复杂,至少有两种方法可以做到这一点,这无济于事。

D'n'D 围绕将对象“包装”在“可转移”包中的想法展开,该包可以通过多种不同方式(即DataFlavors) “导入”

所以,在这个例子中JList,我只专注于从传递更多信息)TrashListTrash

然后,TrashTransferable当在JList

拥有一个对象的主要原因是Trash它允许DataFlavor标准化。“垃圾桶”只关心Trash对象,不关心其他。如果你有更多TransferHandler的 s 做更多的操作,这一点尤其重要

我做的另一件事是创建两个TransferHandlers. 一个用于“垃圾箱”,一个用于“垃圾箱”,JList主要原因是它隔离了每个处理程序想要执行的功能并降低了复杂性,因为您还没有尝试确定哪个对象正在尝试执行哪个操作。

该示例还有另一个组件根本没有做太多事情,因此它可以拒绝 drop 操作。

如果你有另一个使用TransferHandlers 的组件,那么那些需要拒绝TrashTransferable.FLAVOR

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
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.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.TransferHandler.TransferSupport;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Test");
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            DefaultListModel<String> model = new DefaultListModel<>();
            model.addElement("Cooks_Assistant");
            model.addElement("Romeo_and_Juliet");
            model.addElement("Sheep_Shearer");

            JList list = new JList(model);
            list.setTransferHandler(new HListItemTransferHandler());
            list.setDragEnabled(true);

            JLabel noDrop = new JLabel("No drop here", JLabel.CENTER);
            JLabel trash = new JLabel("All your trash belong to us", JLabel.CENTER);
            trash.setTransferHandler(new BinTransferHandler());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 0.5;
            gbc.weighty = 1;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.insets = new Insets(4, 4, 4, 4);

            add(new JScrollPane(list), gbc);

            gbc.gridx++;
            add(noDrop, gbc);

            gbc.gridx = 0;
            gbc.gridy++;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            add(trash, gbc);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }

    }

    public class BinTransferHandler extends TransferHandler {

        @Override
        public boolean canImport(TransferSupport info) {
            return info.isDataFlavorSupported(TrashTransferable.FLAVOR);
        }

        @Override
        public int getSourceActions(JComponent c) {
            System.out.println("ACTION");
            return DnDConstants.ACTION_MOVE;
        }

        @Override
        public boolean importData(TransferSupport support) {
            if (!canImport(support)) {
                return false;
            }
            // Check target component
            Transferable transferable = support.getTransferable();
            try {
                Trash trash = (Trash) transferable.getTransferData(TrashTransferable.FLAVOR);
                Object item = trash.getItem();
                System.out.println(">> Trash " + item);

                return true;
            } catch (UnsupportedFlavorException | IOException ex) {
                ex.printStackTrace();
            }
            return false;
        }

    }

    public class HListItemTransferHandler<T> extends TransferHandler {

        @Override
        protected Transferable createTransferable(JComponent component) {
            System.out.println("createTransferable");
            JList<T> list = (JList<T>) component;
            int index = list.getSelectedIndex();
            T transferredObject = list.getSelectedValue();
            return new TrashTransferable(new ListTrash<>(list, index, transferredObject));
        }

        @Override
        public boolean canImport(TransferSupport info) {
            return info.isDataFlavorSupported(TrashTransferable.FLAVOR);
        }

        @Override
        public int getSourceActions(JComponent c) {
            return DnDConstants.ACTION_MOVE;
        }

        @Override
        public boolean importData(TransferSupport info) {
            JList<Object> target = (JList<Object>) info.getComponent();
            JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
            DefaultListModel<Object> listModel = (DefaultListModel<Object>) target.getModel();
            int index = dl.getIndex();
            int max = listModel.getSize();

            if (index < 0 || index > max) {
                index = max;
            }

            try {
                Object object = info.getTransferable().getTransferData(DataFlavor.stringFlavor);
                listModel.add(index, object);
                target.addSelectionInterval(index, index);
                return true;
            } catch (UnsupportedFlavorException | IOException e) {
                e.printStackTrace();
            }
            return false;
        }

        @Override
        protected void exportDone(JComponent c, Transferable data, int action) {
            System.out.println("Export data");
            try {
                if (action != MOVE) {
                    return;
                }
                if (!(c instanceof JList)) {
                    return;
                }
                JList list = (JList) c;
                if (!(list.getModel() instanceof DefaultListModel)) {
                    return;
                }
                DefaultListModel model = (DefaultListModel) list.getModel();
                if (!(data instanceof TrashTransferable)) {
                    return;
                }
                Object transferData = data.getTransferData(TrashTransferable.FLAVOR);
                if (transferData == null || !(transferData instanceof Trash)) {
                    return;
                }
                Trash trash = (Trash) transferData;
                Object item = trash.item;
                int index = model.indexOf(item);
                if (index == -1) {
                    return;
                }
                model.remove(index);
            } catch (UnsupportedFlavorException | IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    public static class ListTrash<T> extends Trash<T> {

        private JList list;
        private int index;

        public ListTrash(JList list, int index, T item) {
            super(item);
            this.list = list;
            this.index = index;
        }

        public JList getList() {
            return list;
        }

        public int getIndex() {
            return index;
        }

    }

    public static class Trash<T> {

        private T item;

        public Trash(T item) {
            this.item = item;
        }

        public T getItem() {
            return item;
        }

    }

    public static class TrashTransferable<T> implements Transferable {

        public static final DataFlavor FLAVOR = new DataFlavor(Trash.class, "Trash");

        private Trash<T> trash;

        TrashTransferable(Trash<T> object) {
            trash = object;
        }

        @Override
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{FLAVOR};
        }

        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return flavor.equals(flavor);
        }

        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            return trash;
        }
    }
}
于 2017-11-12T22:00:19.050 回答