Java clipboard ignores user copy if not SwingUtili

2020-06-25 04:32发布

Problem: Setting clipboard content in Java programmatically and then getting clipboard text never reflects manual clipboard content changes. But postponing getting of clipboard text via SwingUtilities.invokeLater() until all Swing events have been dealt with does reflect current and later manual clipboard content changes. Setting clipboard content programmatically again returns to broken behavior.

Question: Why is this? Is this a Java bug / undocumented&intended?

Reproduction: Change to Swing thread. Set clipboard content by program. Repeatedly print clipboard content to verify that user's manual copy operations are not reflected. Again repeatedly print, but postpone this via additional SwingUtilities.invokeLater() call. The code below does all this twice in a row.

Windows&Java version:
Microsoft Windows [Version 10.0.14393]
java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

(
That W&J-version was January 2017, when I made this post.
The bug's still in Java in September 2017.
Microsoft Windows [Version 10.0.15063]
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
)

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";
    }


}

0条回答
登录 后发表回答