Java 中文官方教程 2022 版(二十四)(2)

简介: Java 中文官方教程 2022 版(二十四)

Java 中文官方教程 2022 版(二十四)(1)https://developer.aliyun.com/article/1486791

这是TopLevelTransferHandlerDemo.java的源代码:

/**
 * Demonstration of the top-level {@code TransferHandler}
 * support on {@code JFrame}.
 */
public class TopLevelTransferHandlerDemo extends JFrame {
    private static boolean DEMO = false;
    private JDesktopPane dp = new JDesktopPane();
    private DefaultListModel listModel = new DefaultListModel();
    private JList list = new JList(listModel);
    private static int left;
    private static int top;
    private JCheckBoxMenuItem copyItem;
    private JCheckBoxMenuItem nullItem;
    private JCheckBoxMenuItem thItem;
    private class Doc extends InternalFrameAdapter implements ActionListener {
        String name;
        JInternalFrame frame;
        TransferHandler th;
        JTextArea area;
        public Doc(File file) {
            this.name = file.getName();
            try {
                init(file.toURI().toURL());
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
        public Doc(String name) {
            this.name = name;
            init(getClass().getResource(name));
        }
        private void init(URL url) {
            frame = new JInternalFrame(name);
            frame.addInternalFrameListener(this);
            listModel.add(listModel.size(), this);
            area = new JTextArea();
            area.setMargin(new Insets(5, 5, 5, 5));
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
                String in;
                while ((in = reader.readLine()) != null) {
                    area.append(in);
                    area.append("\n");
                }
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            th = area.getTransferHandler();
            area.setFont(new Font("monospaced", Font.PLAIN, 12));
            area.setCaretPosition(0);
            area.setDragEnabled(true);
            area.setDropMode(DropMode.INSERT);
            frame.getContentPane().add(new JScrollPane(area));
            dp.add(frame);
            frame.show();
            if (DEMO) {
                frame.setSize(300, 200);
            } else {
                frame.setSize(400, 300);
            }
            frame.setResizable(true);
            frame.setClosable(true);
            frame.setIconifiable(true);
            frame.setMaximizable(true);
            frame.setLocation(left, top);
            incr();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    select();
                }
            });
            nullItem.addActionListener(this);
            setNullTH();
        }
        public void internalFrameClosing(InternalFrameEvent event) {
            listModel.removeElement(this);
            nullItem.removeActionListener(this);
        }
        public void internalFrameOpened(InternalFrameEvent event) {
            int index = listModel.indexOf(this);
            list.getSelectionModel().setSelectionInterval(index, index);
        }
        public void internalFrameActivated(InternalFrameEvent event) {
            int index = listModel.indexOf(this);
            list.getSelectionModel().setSelectionInterval(index, index);
        }
        public String toString() {
            return name;
        }
        public void select() {
            try {
                frame.toFront();
                frame.setSelected(true);
            } catch (java.beans.PropertyVetoException e) {}
        }
        public void actionPerformed(ActionEvent ae) {
            setNullTH();
        }
        public void setNullTH() {
            if (nullItem.isSelected()) {
                area.setTransferHandler(null);
            } else {
                area.setTransferHandler(th);
            }
        }
    }
    private TransferHandler handler = new TransferHandler() {
        public boolean canImport(TransferHandler.TransferSupport support) {
            if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                return false;
            }
            if (copyItem.isSelected()) {
                boolean copySupported = (COPY & support.getSourceDropActions()) == COPY;
                if (!copySupported) {
                    return false;
                }
                support.setDropAction(COPY);
            }
            return true;
        }
        public boolean importData(TransferHandler.TransferSupport support) {
            if (!canImport(support)) {
                return false;
            }
            Transferable t = support.getTransferable();
            try {
                java.util.List<File> l =
                    (java.util.List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
                for (File f : l) {
                    new Doc(f);
                }
            } catch (UnsupportedFlavorException e) {
                return false;
            } catch (IOException e) {
                return false;
            }
            return true;
        }
    };
    private static void incr() {
        left += 30;
        top += 30;
        if (top == 150) {
            top = 0;
        }
    }
    public TopLevelTransferHandlerDemo() {
        super("TopLevelTransferHandlerDemo");
        setJMenuBar(createDummyMenuBar());
        getContentPane().add(createDummyToolBar(), BorderLayout.NORTH);
        JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, list, dp);
        sp.setDividerLocation(120);
        getContentPane().add(sp);
        //new Doc("sample.txt");
        //new Doc("sample.txt");
        //new Doc("sample.txt");
        list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting()) {
                    return;
                }
                Doc val = (Doc)list.getSelectedValue();
                if (val != null) {
                    val.select();
                }
             }
        });
        final TransferHandler th = list.getTransferHandler();
        nullItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (nullItem.isSelected()) {
                    list.setTransferHandler(null);
                } else {
                    list.setTransferHandler(th);
                }
            }
        });
        thItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (thItem.isSelected()) {
                    setTransferHandler(handler);
                } else {
                    setTransferHandler(null);
                }
            }
        });
        dp.setTransferHandler(handler);
    }
    private static void createAndShowGUI(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        TopLevelTransferHandlerDemo test = new TopLevelTransferHandlerDemo();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        if (DEMO) {
            test.setSize(493, 307);
        } else {
            test.setSize(800, 600);
        }
        test.setLocationRelativeTo(null);
        test.setVisible(true);
        test.list.requestFocus();
    }
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal's use of bold fonts
                UIManager.put("swing.boldMetal", Boolean.FALSE);
                createAndShowGUI(args);
            }
        });
    }
    private JToolBar createDummyToolBar() {
        JToolBar tb = new JToolBar();
        JButton b;
        b = new JButton("New");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Open");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Save");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Print");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Preview");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        tb.setFloatable(false);
        return tb;
    }
    private JMenuBar createDummyMenuBar() {
        JMenuBar mb = new JMenuBar();
        mb.add(createDummyMenu("File"));
        mb.add(createDummyMenu("Edit"));
        mb.add(createDummyMenu("Search"));
        mb.add(createDummyMenu("View"));
        mb.add(createDummyMenu("Tools"));
        mb.add(createDummyMenu("Help"));
        JMenu demo = new JMenu("Demo");
        demo.setMnemonic(KeyEvent.VK_D);
        mb.add(demo);
        thItem = new JCheckBoxMenuItem("Use Top-Level TransferHandler");
        thItem.setMnemonic(KeyEvent.VK_T);
        demo.add(thItem);
        nullItem = new JCheckBoxMenuItem("Remove TransferHandler from List and Text");
        nullItem.setMnemonic(KeyEvent.VK_R);
        demo.add(nullItem);
        copyItem = new JCheckBoxMenuItem("Use COPY Action");
        copyItem.setMnemonic(KeyEvent.VK_C);
        demo.add(copyItem);
        return mb;
    }
    private JMenu createDummyMenu(String str) {
        JMenu menu = new JMenu(str);
        JMenuItem item = new JMenuItem("[Empty]");
        item.setEnabled(false);
        menu.add(item);
        return menu;
    }
}

添加剪切、复制和粘贴(CCP)

原文:docs.oracle.com/javase/tutorial/uiswing/dnd/cutpaste.html

到目前为止,我们的讨论主要集中在拖放支持上。然而,将剪切、复制或粘贴(ccp)连接到传输处理程序是一件容易的事情。这需要以下步骤:

  • 确保组件上安装了传输处理程序。
  • 创建一种方式,通过该方式可以调用TransferHandler的 ccp 支持。通常,这涉及向输入和动作映射添加绑定,以便在特定按键响应中调用TransferHandler的 ccp 操作。
  • 创建 ccp 菜单项和/或按钮。(此步骤是可选的,但建议执行。)对于文本组件,这很容易做到,但对于其他组件,需要更多的工作,因为您需要逻辑来确定在哪个组件上触发操作。查看非文本组件中的 CCP 获取更多信息。
  • 决定在哪里执行粘贴。也许在当前选择的上方或下方。在importData方法中安装逻辑。

接下来,我们将看一个包含文本组件的剪切和粘贴示例。

在文本组件中进行 CCP

原文:docs.oracle.com/javase/tutorial/uiswing/dnd/textpaste.html

如果您正在使用 Swing 文本组件(文本字段、密码字段、格式化文本字段或文本区域)之一实现剪切、复制和粘贴,您的工作非常简单。这些文本组件利用了DefaultEditorKit,它提供了内置的剪切、复制和粘贴操作。默认编辑工具包还处理了记住上次焦点在哪个组件的工作。这意味着如果用户使用菜单或键盘快捷键启动其中一个操作,正确的组件将接收该操作 —— 不需要额外的代码。

下面的演示TextCutPaste包含三个文本字段。如您在屏幕截图中所见,您可以剪切、复制和粘贴到任何一个文本字段或从中粘贴。它们还支持拖放操作。



试一试:

  1. 点击启动按钮以使用Java™ Web Start运行TextCutPaste下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
  2. 在其中一个文本字段中选择文本。使用编辑菜单或键盘快捷键从源处剪切或复制文本。
  3. 将光标定位到要粘贴文本的位置。
  4. 使用菜单或键盘快捷键粘贴文本。
  5. 使用拖放执行相同的操作。

这是创建编辑菜单的代码,通过将DefaultEditorKit中定义的内置剪切、复制和粘贴操作与菜单项连接起来。这适用于任何继承自JComponent的组件:

/**
     * Create an Edit menu to support cut/copy/paste.
     */
    public JMenuBar createMenuBar () {
        JMenuItem menuItem = null;
        JMenuBar menuBar = new JMenuBar();
        JMenu mainMenu = new JMenu("Edit");
        mainMenu.setMnemonic(KeyEvent.VK_E);
        menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
        menuItem.setText("Cut");
        menuItem.setMnemonic(KeyEvent.VK_T);
        mainMenu.add(menuItem);
        menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
        menuItem.setText("Copy");
        menuItem.setMnemonic(KeyEvent.VK_C);
        mainMenu.add(menuItem);
        menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
        menuItem.setText("Paste");
        menuItem.setMnemonic(KeyEvent.VK_P);
        mainMenu.add(menuItem);
        menuBar.add(mainMenu);
        return menuBar;
    }

接下来我们将看看如何使用不具有DefaultEditorKit内置支持的组件实现相同的功能。

非文本组件中的 CCP

原文:docs.oracle.com/javase/tutorial/uiswing/dnd/listpaste.html

如果您正在使用 Swing 组件之一来实现剪切、复制和粘贴,而不是文本组件,您需要进行一些额外的设置。首先,您需要在动作映射中安装剪切、复制和粘贴操作。以下方法显示了如何执行此操作:

private void setMappings(JList list) { 
        ActionMap map = list.getActionMap();
        map.put(TransferHandler.getCutAction().getValue(Action.NAME),
                TransferHandler.getCutAction());
        map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
                TransferHandler.getCopyAction());
        map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
                TransferHandler.getPasteAction());

当设置编辑菜单时,您还可以选择添加菜单加速器,以便用户可以输入 Control-C 来启动复制操作,例如。在下面的代码片段中,粗体文本显示了如何为剪切操作设置菜单加速器:

menuItem = new JMenuItem("Cut");
    menuItem.setActionCommand((String)TransferHandler.getCutAction().
             getValue(Action.NAME));
    menuItem.addActionListener(actionListener);
    menuItem.setAccelerator(
      KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK));
    menuItem.setMnemonic(KeyEvent.VK_T);
    mainMenu.add(menuItem);

如果您已为 CCP 操作设置了菜单加速器,则下一步是多余的。如果您尚未设置菜单加速器,则需要将 CCP 绑定添加到输入映射中。以下代码片段显示了如何执行此操作:

// only required if you have not set the menu accelerators
    InputMap imap = this.getInputMap();
    imap.put(KeyStroke.getKeyStroke("ctrl X"),
        TransferHandler.getCutAction().getValue(Action.NAME));
    imap.put(KeyStroke.getKeyStroke("ctrl C"),
        TransferHandler.getCopyAction().getValue(Action.NAME));
    imap.put(KeyStroke.getKeyStroke("ctrl V"),
        TransferHandler.getPasteAction().getValue(Action.NAME));

一旦绑定已安装并且编辑菜单已设置,还有另一个问题需要解决:当用户启动剪切、复制或粘贴时,哪个组件应该接收该操作?在文本组件的情况下,DefaultEditorKit会记住上次焦点所在的组件,并将操作转发给该组件。以下类,TransferActionListener,为非文本 Swing 组件执行相同的功能。这个类可以被放入大多数应用程序中:

public class TransferActionListener implements ActionListener,
                                              PropertyChangeListener {
    private JComponent focusOwner = null;
    public TransferActionListener() {
        KeyboardFocusManager manager = KeyboardFocusManager.
           getCurrentKeyboardFocusManager();
        manager.addPropertyChangeListener("permanentFocusOwner", this);
    }
    public void propertyChange(PropertyChangeEvent e) {
        Object o = e.getNewValue();
        if (o instanceof JComponent) {
            focusOwner = (JComponent)o;
        } else {
            focusOwner = null;
        }
    }
    public void actionPerformed(ActionEvent e) {
        if (focusOwner == null)
            return;
        String action = (String)e.getActionCommand();
        Action a = focusOwner.getActionMap().get(action);
        if (a != null) {
            a.actionPerformed(new ActionEvent(focusOwner,
                                              ActionEvent.ACTION_PERFORMED,
                                              null));
        }
    }
}

最后,您必须决定如何处理粘贴操作。在拖放的情况下,您将数据插入到放置位置。在粘贴的情况下,您没有用户指向所需粘贴位置的好处。您需要决定对您的应用程序来说什么是最合理的解决方案——在当前选择之前还是之后插入数据可能是最好的解决方案。

以下演示,ListCutPaste,展示了如何在一个JList实例中实现 CCP。如您在屏幕截图中所见,有三个列表,您可以在这些列表之间剪切、复制和粘贴。它们还支持拖放。对于这个演示,粘贴的数据将插入到当前选择之后。如果没有当前选择,则数据将附加到列表末尾。



试一试:

  1. 点击“启动”按钮以使用Java™ Web Start运行 ListCutPaste(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
  2. 在其中一个列表中选择一个项目。使用编辑菜单或键盘快捷键从源中剪切或复制列表项。
  3. 选择要粘贴项目的列表项。
  4. 使用菜单或键盘等效方式粘贴文本。项目将在当前选择后粘贴。
  5. 使用拖放执行相同操作。

使用和创建 DataFlavor

原文:docs.oracle.com/javase/tutorial/uiswing/dnd/dataflavor.html

DataFlavor类允许你指定数据的内容类型。在从importData方法中获取数据时,你需要指定一个DataFlavor。有几种预定义的类型供你使用:

  • imageFlavor代表java.awt.Image格式的数据。在拖动图像数据时使用。
  • stringFlavor代表最基本的文本形式数据 — java.lang.String。这是大多数应用程序中最常用的数据类型。
  • javaFileListFlavor代表以java.util.List格式表示的java.io.File对象。这对于拖动文件的应用程序非常有用,比如在顶级拖放课程中讨论的TopLevelTransferHandler示例。

对于大多数应用程序,这就是你需要了解的关于数据类型的全部内容。然而,如果你需要除了这些预定义类型之外的类型,你可以创建自己的类型。如果你创建了一个自定义组件并希望它参与数据传输,你将需要创建一个自定义数据类型。指定数据类型的构造函数是DataFlavor(Class, String)。例如,为java.util.ArrayList类创建一个数据类型:

new DataFlavor(ArrayList.class, "ArrayList");

要为整数数组创建一个数据类型:

new DataFlavor(int[].class, "Integer Array");

使用这种机制传输数据使用了Object序列化,因此你用于传输数据的类必须实现Serializable接口,以及与之一起序列化的任何内容。如果不是所有内容都是可序列化的,你将在拖放或复制到剪贴板时看到NotSerializableException

使用DataFlavor(Class, String)构造函数创建数据类型允许你在应用程序之间传输数据,包括本地应用程序。如果你想创建一个只在应用程序内部传输数据的数据类型,可以使用javaJVMLocalObjectMimeTypeDataFlavor(String)构造函数。例如,要指定一个从JColorChooser仅在你的应用程序内传输颜色的数据类型,你可以使用这段代码:

String colorType = DataFlavor.javaJVMLocalObjectMimeType +
                   ";class=java.awt.Color";
DataFlavor colorFlavor = new DataFlavor(colorType);

为一个只在你的应用程序中起作用的ArrayList创建一个数据类型:

new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
               ";class=java.util.ArrayList");

要为整数数组创建一个数据类型:

new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
               ";class=\"" + int[].class.getName() + "\"");

包含特殊字符的 MIME 类型,比如**[;**,必须将这些字符用引号括起来。

一个Transferable可以被实现以支持多种风味。例如,你可以同时使用本地和序列化风味,或者你可以同时使用两种形式的相同数据,比如ArrayList和整数数组风味,或者你可以创建一个接受不同类型数据的TransferHandler,比如颜色和文本。

当你创建一个DataFlavors数组以从TransferablegetTransferDataFlavors方法返回时,风味应按照首选顺序插入,最首选的风味应出现在数组的元素 0 位置。一般来说,首选顺序是从最丰富或最复杂的数据形式到简单集合的形式 — 最有可能被其他对象理解的形式。

将所有内容整合在一起 - 拖放和剪切复制粘贴

原文:docs.oracle.com/javase/tutorial/uiswing/dnd/together.html

我们已经展示了如何实现拖放支持以及如何实现剪切、复制、粘贴支持。如何在一个组件中同时实现两者?

你需要在TransferHandlerimportData方法中实现这两种功能,就像这样:

if (transferSupport.isDrop()) {
    // put data in transferSupport.getDropLocation()
} else {
    // determine where you want the paste to go (ex: after current selection)
    // put data there
}

在非文本组件中的 CCP 页面上讨论的ListCutPaste示例支持拖放和剪切复制粘贴。这是它的importData方法(用粗体标记了if-else的逻辑):

public boolean importData(TransferHandler.TransferSupport info) {
        String data = null;
        //If we cannot handle the import, bail now.
        if (!canImport(info)) {
            return false;
        }
        JList list = (JList)info.getComponent();
        DefaultListModel model = (DefaultListModel)list.getModel();
        //Fetch the data -- bail if this fails
        try {
            data = (String)info.getTransferable().getTransferData(DataFlavor.stringFlavor);
        } catch (UnsupportedFlavorException ufe) {
            System.out.println("importData: unsupported data flavor");
            return false;
        } catch (IOException ioe) {
            System.out.println("importData: I/O exception");
            return false;
        }
        if (info.isDrop()) { //This is a drop
            JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
            int index = dl.getIndex();
            if (dl.isInsert()) {
                model.add(index, data);
                return true;
            } else {
                model.set(index, data);
                return true;
            }
        } else { //This is a paste
            int index = list.getSelectedIndex();
            // if there is a valid selection,
            // insert data after the selection
            if (index >= 0) {
                model.add(list.getSelectedIndex()+1, data);
            // else append to the end of the list
            } else {
                model.addElement(data);
            }
            return true;
        }
    }

这是唯一需要安装if-else逻辑来区分拖放和剪切复制粘贴的地方。

解决常见数据传输问题

原文:docs.oracle.com/javase/tutorial/uiswing/dnd/problems.html

当使用数据传输时,可能会遇到一些问题。

问题: 我的拖动手势识别器在与表格/列表/树/文本一起使用时无法正常工作。

不要在这些组件上使用自己的拖动手势识别器。使用setDragEnabled(true)TransferHandler

问题: 我无法将数据放置到我的空JTable中。

你需要在表格上调用setFillsViewportHeight(true)。查看空表格拖放获取更多信息。

Java 中文官方教程 2022 版(二十四)(3)https://developer.aliyun.com/article/1486798

相关文章
|
2月前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
4月前
|
Java 开发者 UED
【实战宝典】Java异常处理大师级教程:throws关键字,让异常声明成为你的专属标签!
【实战宝典】Java异常处理大师级教程:throws关键字,让异常声明成为你的专属标签!
62 3
|
23天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
23天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
23天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
|
9天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
10 0
|
2月前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
73 2
|
2月前
|
Java 数据库连接 编译器
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
|
2月前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
本系列教程笔记详细讲解了Kotlin语法,适合希望深入了解Kotlin的开发者。对于需要快速学习Kotlin的小伙伴,推荐查看“简洁”系列教程。本篇笔记重点介绍了Kotlin与Java混编的技巧,包括代码转换、类调用、ProGuard问题、Android库开发建议以及相互调用时的注意事项。
26 3
|
2月前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
22 3
下一篇
无影云桌面