当前位置: 首页 > 知识库问答 >
问题:

使用swing进行放置位置渲染

孙渝
2023-03-14

我想为组件(例如JPanel或JLabel)实现自定义放置位置渲染。我的目标是在用户将可拖放项悬停在组件上时显示蓝色边框,并在离开组件时再次删除边框。

摇摆教程提供了以下内容:
删除位置渲染
这对我一点帮助都没有。我缺少类似entComponent(事件e)exitComponent(事件e)这样的东西,或者这个页面引用的东西与我预期的不同?

所以我通过万维网搜索,找到了一些例子(大部分来自这个博客)。过了一会儿,我可以完成一个我需要的工作示例(来源如下)。但是我找到的例子都使用了java.awt的类来呈现放置位置。因为我仍然没有得到所有这些拖放类的完整概述,所以我没有找到一种方法来实现只使用摇摆类的自定义拖放位置渲染。

所以我的问题是:
是否可以仅使用swing类在“enterComponent”“exitComponent”事件上呈现JComponent?

附加问题:
如果我删除行新的DropTarget(标签,dropListener) ListItemTransferHandler。导入数据(…) 将被调用,否则它将不会被调用。这是什么原因?我真的很感激一些关于dnd类的课程和/或行动图(这不是回答的必要条件)。

(请不要回答JavaFX)

工作示例的源代码(使用AWT类)。抱歉,代码行太多,但是JavaDND需要很大的空间。

public class DnDTransferableTest {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DnDTransferableTest();
            }
        });
    }

    public DnDTransferableTest() {
        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setLocationRelativeTo(null);

//      JPanel panel = new JPanel(new MigLayout("wrap 2, fill", "fill, grow", "align center"));
        JPanel panel = new JPanel(new GridLayout(1,2));

        JList<ListItem> list = new JList<ListItem>();
        JLabel label = new JLabel();

        // Initializing list
        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);

        // Initializing label and its drop listener
        label.setText("Drag on me...");
        label.setTransferHandler(new ListTransferHandler());

        DropTargetListener dropListener = new JLabelDropTargetListener();
        new DropTarget(label, dropListener);

        // Adding the components to the panel
        panel.add(new JScrollPane(list), "sg test");
        panel.add(label, "sg test");

        frame.setContentPane(panel);
        frame.setVisible(true);
    }

}

class ListItem implements Transferable {

    public static final DataFlavor LIST_ITEM_DATA_FLAVOR = new DataFlavor(ListItem.class, ListItem.class.getName());
    private String text;
    private int number;

    public ListItem(String text, int number) {
        this.text = text;
        this.number = number;
    }

    public String getText() {
        return text;
    }

    public int getNumber() {
        return this.number;
    }

    @Override
    public String toString() {
        return this.getText() + ": " + this.getNumber();
    }

    @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 this;
    }
}

class ListTransferHandler extends TransferHandler {

    private static final long serialVersionUID = 1L;

    @Override
    public boolean canImport(TransferSupport support) {
        return (support.getComponent() instanceof JLabel) && support.isDataFlavorSupported(ListItem.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(ListItem.LIST_ITEM_DATA_FLAVOR);
                if (value instanceof ListItem) {
                    Component component = support.getComponent();
                    if (component instanceof JLabel) {
                        ((JLabel) component).setText(((ListItem) value).getNumber() + ". " + ((ListItem) value).getText());
                    }
                }
            } catch (Exception exp) {
                exp.printStackTrace();
            }
        }
        System.out.println("import data " + accept);
        return accept;
    }

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

    @Override
    protected Transferable createTransferable(JComponent c) {

        if (c instanceof JList<?>) {
            JList<?> list = (JList<?>) c;
            Object value = list.getSelectedValue();
            if (value instanceof ListItem) {
                return (ListItem) value;
            }
        }
        return null;
    }

    @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...
    }

}

class JLabelDropTargetListener implements DropTargetListener {

    private int thickness = 2;
    private Border blueBorder = BorderFactory.createLineBorder(Color.BLUE, thickness);
    private Border emptyBorder = BorderFactory.createEmptyBorder(thickness, thickness, thickness, thickness);

    @Override
    public void dragEnter(DropTargetDragEvent dtde) {
        System.out.println("dragEnter");
        Object src = dtde.getDropTargetContext().getComponent();

        if (src instanceof JLabel) {
            JLabel label = (JLabel) src;
            label.setForeground(Color.RED);
            label.setBorder(blueBorder);
        } else {
            System.out.println(src.getClass().getName());
            System.out.println(dtde.getDropTargetContext().getComponent());
        }
    }

    @Override
    public void dragOver(DropTargetDragEvent dtde) {
    }

    @Override
    public void dropActionChanged(DropTargetDragEvent dtde) {
    }

    @Override
    public void dragExit(DropTargetEvent dte) {
        System.out.println("dragExit");
        Component src = dte.getDropTargetContext().getComponent();

        if (src instanceof JLabel) {
            JLabel label = (JLabel) src;
            label.setForeground(null);
            label.setBorder(emptyBorder);
        }

    }

    @Override
    public void drop(DropTargetDropEvent dtde) {
        System.out.println("drop");
        Component src = dtde.getDropTargetContext().getComponent();

        if (src instanceof JLabel) {
            JLabel label = (JLabel) src;
            label.setForeground(null);
            label.setBorder(emptyBorder);

            Transferable t = dtde.getTransferable();
            Object value;
            try {
                value = t.getTransferData(ListItem.LIST_ITEM_DATA_FLAVOR);

                if (value instanceof ListItem) {
                    ListItem li = (ListItem) value;
                    label.setText(li.getNumber() + ". " + li.getText());
                }

            } catch (UnsupportedFlavorException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

共有2个答案

贝滨海
2023-03-14

我能够想出如何做到这一点。基于您的代码

    DropTarget dropTarget = label.getDropTarget();
    try
    {
        dropTarget.addDropTargetListener(dropListener);
    }
    catch (TooManyListenersException e)
    {
        e.printStackTrace();
    }

像往常一样设置传输处理程序。这将处理实际的拖放功能,而拖放侦听器将处理标签的绘制。不要创建自己的放置目标对象。

冷英博
2023-03-14

我深入研究了swing的TransferHandler的源代码,发现了JComponent
setDropLocation(TransferHandler.DropLocation位置、对象状态、布尔forDrop)
在每个DragEvent上都被TransferHandler调用(TransferHandler有自己的私有DropTargetListener类)。首先,我想在我自己的JLabel扩展类中重写它,但后来注意到它受到了保护。

有了这些新信息,我无意中发现了这两个帖子:

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6448332
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6500024

所以答案是:这是一个bug,或者说是一个尚未实现的特性(我不知道它在Java8中是否可用,但我认为JavaFX比swing做得更好。不幸的是,现在切换到JavaFX有点晚)。

 类似资料:
  • 问题内容: 我正在编写一个使用android中的位置模拟可能性的应用程序。 我想实现的是模拟我的位置,而无需在开发人员选项中设置“允许模拟位置”标志。 我知道这是可能的,因为它可以与此应用一起使用: https //play.google.com/store/apps/details?id=com.lexa.fakegps&hl=zh- CN 我试过的 生成一个apk,将其移动到/ system

  • 我正在写一个应用程序,它利用了android中位置模拟的可能性。 我想要实现的是模拟我的位置,而不在开发者选项中设置“允许模拟位置”标志。 我知道这是可能的,因为是工程与此应用程序:https://play.google.com/store/apps/details?id=com.lexa.fakegps 我所尝试的: 生成一个apk,将其移动到/system/app,重新启动 ,我还尝试了使用和

  • 问题内容: 位和位掩码是我一直在努力理解的东西,但是我想学习如何在PHP中使用它们进行设置和类似操作。 我终于找到了一个声称完全可以做到这一点的类,而且据我所知,它似乎可以工作,但是我不确定这是否是实现此目的的最佳方法。我将使用下面的示例代码发布类文件,以按工作顺序显示它。 如果您有经验,请告诉我是否可以改进,性能或其他方面。我真的很想学习这一点,而且我一直在阅读它,但是到目前为止,这对我来说很难

  • 进化放置(Idle Evolution)是一款渐进式的游戏,讲述的是将一个文明从原始渗出物进化成一个航天帝国的过程。结合了点击游戏和闲置游戏的元素,并且有很多微观管理的内容。

  • 问题内容: 我知道如何在AngularJS中创建 视图 条件,该条件将根据条件显示或隐藏dom元素: 但是如何创建确定是否渲染div 的 渲染 条件? 问题答案: 针对angularjs 1.1.5及更高版本用户的更新(在1.0.7中不受支持): 相关提交:https : //github.com/angular/angular.js/commit/2f96fbd17577685bc013a4f7

  • 问题内容: 我正在尝试使用Java中的Selenium来获取用户的地理坐标,但是使用IP地址不够准确,因此我想使用该网站http://www.whataremycoordinates.com/,但是它无法正常工作,我猜这是因为您必须允许位置使用,所以无论如何我都可以在Selenium中使用位置使用,或者也许可以通过其他方法来获取确切的地理坐标 问题答案: 通常,当站点想要获取此类数据时,浏览器会询