如果不是SwingUtilities,Java剪贴板将忽略用户副本

如果不是SwingUtilities,Java剪贴板将忽略用户副本,java,swing,awt,clipboard,Java,Swing,Awt,Clipboard,问题:以编程方式在Java中设置剪贴板内容,然后获取剪贴板文本永远不会反映手动剪贴板内容更改。但是,将通过SwingUtilities.invokeLater()获取剪贴板文本的时间推迟到所有Swing事件处理完毕,这确实反映了当前和以后手动剪贴板内容的更改。再次以编程方式设置剪贴板内容将返回到中断行为 问题:这是为什么?这是一个Java错误/未记录的和有意的吗 复制:更改为摆动线程。按程序设置剪贴板内容。重复打印剪贴板内容,以验证是否未反映用户的手动复制操作。再次重复打印,但通过额外的Swin

问题:以编程方式在Java中设置剪贴板内容,然后获取剪贴板文本永远不会反映手动剪贴板内容更改。但是,将通过SwingUtilities.invokeLater()获取剪贴板文本的时间推迟到所有Swing事件处理完毕,这确实反映了当前和以后手动剪贴板内容的更改。再次以编程方式设置剪贴板内容将返回到中断行为

问题:这是为什么?这是一个Java错误/未记录的和有意的吗

复制:更改为摆动线程。按程序设置剪贴板内容。重复打印剪贴板内容,以验证是否未反映用户的手动复制操作。再次重复打印,但通过额外的SwingUtilities.invokeLater()调用推迟打印。下面的代码连续执行这两次

Windows和Java版本:
Microsoft Windows[版本10.0.14393]
java版本“1.8.0_74”
Java(TM)SE运行时环境(build 1.8.0_74-b02)
Java HotSpot(TM)64位服务器虚拟机(构建25.74-b02,混合模式)


当我发表这篇文章时,W&J的版本是2017年1月。
该漏洞在2017年9月仍在Java中。
Microsoft Windows[版本10.0.15063]
java版本“1.8.0_144”
Java(TM)SE运行时环境(build 1.8.0_144-b01)
Java HotSpot(TM)64位服务器虚拟机(构建25.144-b01,混合模式)
)

SSCCE:

package com.potentialjavabug;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Arrays;

final public class OMFGClipboardProblems {

    final private static int PRINTLOOPCOUNT = 10;

    public static void main(final String[] args) {


        SwingUtilities.invokeLater(() -> {


            printClipboardContent();


            pause();
            pause();
            System.err.println("You just saw the clipboard content this program started with. Now follows a loop with programmatically set clipboard text.");
            pause();
            pause();


            setClipboardText("Try to copy text anywhere in your system to the clipboard while this loop runs " + PRINTLOOPCOUNT + " times. You will see that this is ignored!");
            printClipboardContentAFewTimes();
            setClipboardText("And programmatically setting the clipboard still works.");
            printClipboardContent();


            pause();
            pause();
            System.err.println("\n\n\n\nOk, now let's do this again: I'm NOT gonna set the clipboard text like I did before, and I will print out the current clipboard content just like before. But I'm gonna do it after all currently pending Swing events have been processed! You will notice that your copy actions DO have effect now.");
            pause();
            pause();


            SwingUtilities.invokeLater(() -> {


                printClipboardContentAFewTimes();


                pause();
                pause();
                setClipboardText("THIS IS NEW text set programmatically. Try to copy any other text to the clipboard. You'll see that it again does not work.");
                printClipboardContentAFewTimes();
                pause();
                pause();


                System.err.println("\n\n\n\nAnd now, the SwingUtilities.invokeLater trick again. Try to copy, and you'll see that this text indeed changes.");
                pause();
                pause();


                SwingUtilities.invokeLater(OMFGClipboardProblems::printClipboardContentAFewTimes);

            });

        });


    }


    private static void printClipboardContentAFewTimes() {

        for (int i = 0; i < PRINTLOOPCOUNT; i++) {
            pause();
            printClipboardContent();
        }
    }


    private static void printClipboardContent() {

        System.err.print("\nCURRENT CLIPBOARD CONTENT:");
        System.err.println(getClipboardText());
    }


    private static void pause() {

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    private static void setClipboardText(final String text) {

        final Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
        final StringSelection data = new StringSelection(text);
        c.setContents(data, data);
    }


    private static String getClipboardText() {

        final Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
        final DataFlavor[] availableDataFlavors = c.getAvailableDataFlavors();

        final String flavorPrefixString = "***DATA FLAVORS: " + Arrays.toString(availableDataFlavors) + "***\n";

        if (!c.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
            return flavorPrefixString;
        }
        try {
            final Object data = c.getData(DataFlavor.stringFlavor);
            final String ret = (String) data;
            return flavorPrefixString + ret;
        } catch (UnsupportedFlavorException | IOException ex) {
            ex.printStackTrace(); // Shouldn't happen since we explicitly checked.
        }
        return "error";
    }


}
package com.potentialjavabug;
导入javax.swing.*;
导入java.awt.*;
导入java.awt.datatransfer.Clipboard;
导入java.awt.datatransfer.DataFlavor;
导入java.awt.datatransfer.StringSelection;
导入java.awt.datatransfer.UnsupportedFlavorException;
导入java.io.IOException;
导入java.util.array;
最终公共类OMFGClipboardProblems{
最终私有静态int PRINTLOOPCOUNT=10;
公共静态void main(最终字符串[]args){
SwingUtilities.invokeLater(()->{
printClipboardContent();
暂停();
暂停();
System.err.println(“您刚刚看到了这个程序开始时使用的剪贴板内容。现在使用编程设置的剪贴板文本进行循环。”);
暂停();
暂停();
setClipboardText(“当此循环运行“+PRINTLOOPCOUNT+”次时,尝试将系统中任何位置的文本复制到剪贴板。您将看到此操作被忽略!”);
printClipboardContentAFewTimes();
setClipboardText(“并且以编程方式设置剪贴板仍然有效。”);
printClipboardContent();
暂停();
暂停();
System.err.println(“\n\n\n\nOk,现在让我们再做一次:我不会像以前那样设置剪贴板文本,我会像以前一样打印当前剪贴板内容。但我会在处理完所有当前挂起的Swing事件后执行此操作!您会注意到您的复制操作现在确实生效。”);
暂停();
暂停();
SwingUtilities.invokeLater(()->{
printClipboardContentAFewTimes();
暂停();
暂停();
setClipboardText(“这是以编程方式设置的新文本。尝试将任何其他文本复制到剪贴板。您将再次看到它不起作用。”);
printClipboardContentAFewTimes();
暂停();
暂停();
System.err.println(“\n\n\n\n现在,SwingUtilities.invokeLater技巧再次出现。尝试复制,您将看到此文本确实发生了更改。”);
暂停();
暂停();
调用器(OMFGClipboardProblems::printClipboardContentAFewTimes);
});
});
}
私有静态void printClipboardContentAFewTimes(){
对于(int i=0;i