Java clipboard ignores user copy unless SwingUtilities.invokeLater ()

Problem: Setting the contents of the clipboard in Java programmatically and then retrieving the clipboard text never reflects changes to the contents of the manual clipboard. But delaying retrieving the clipboard text via SwingUtilities.invokeLater () until all Swing events have been processed will be reflected in the current and subsequent manual changes to the clipboard content. Setting clipboard contents programmatically reverts back to the broken behavior again.

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

Playback: Edit on Swing thread. Set the contents of the clipboard by the program. Print the contents of the clipboard repeatedly to make sure manual copy operations are not displayed. Reprint again, but defer this via an additional call to SwingUtilities.invokeLater (). The following code does this twice in a row.

Windows and 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)

(
This W&J version was in January 2017 when I made this post.
Bug 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 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";
    }


}

      

+3


source to share





All Articles