1
\$\begingroup\$

Checklist from FAQ for proper posting.

Does my question contain code? 
   - YES
Did I write that code?
   - YES
Is it actual code from a project rather than pseudo-code or example code?
   - Strait from actual code, minus a few functions that do not apply to the Q
To the best of my knowledge, does the code work?
   - To the best of my knowledge it works most of the time, other times it 
     fails to do what I ask of it but produces no runtime errors. 
Do I want feedback about any or all facets of the code?
   - Just about how to reliably wait for the clipboard to be set and 
     reliably set it while I am waiting.

I am trying to reliably set the system clipboard text in my program but keep coming back with confusing results. Those results being it sometimes setting the text and sometimes not setting it. Here is where I create a thread of type ClipSetThread and tell it to set the system clipboard and also set a global variable called waitForMe in the main Application.

public void setClip(String arg) // Starts a clip setting thread
{
    CLUtilCompact.waitForMe = true;
    ClipSetThread set = new ClipSetThread(theApp);
    set.arg = arg;
    set.start();
    while(CLUtilCompact.waitForMe){}
}

And here is the class ClipSetThread

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;

public class ClipSetThread extends Thread
{
String arg = "";
Clipboard sysClip = null;
CLUtilCompact theApp = null;
public ClipSetThread(CLUtilCompact app)
{
    theApp = app;
    theApp.updateOutput("Set Clip ID:" + this.getId() + "|CREATED");
    sysClip = Toolkit.getDefaultToolkit().getSystemClipboard();
}
public void run()
{
    setClip2(arg);
    CLUtilCompact.waitForMe = false;
    return;
}
public void setClip2(String arg)
{
    while(true) 
    {
        try
        {
            sysClip.setContents(new StringSelection(arg), null);
        }
        catch(Exception e)
        {
            try {Thread.sleep(20);} catch (InterruptedException e1) {}
            continue;
        }
        break;
    }
    return;
}
}

It seems that even with the while loop to wait for the waitForMe flag the setClip function will return and allow the application to try and continue what it is doing even though the clipboard is not set.

After the clipboard is set I almost always try to paste what is there; I usually call Thread.sleep(1000) between a call to setClip and my call to paste(). (Paste simply simulates ctrl+V with the java Robot class)

\$\endgroup\$
3
  • \$\begingroup\$ Please define 'reliably set', as it's probably setting the copied value eventually. Your first major problem is that you're limited by the fact that you're using a global variable. What is it you're actually trying to accomplish - why are you attempting to transfer data this way? You should be implementing Runnable, not extending Thread, and submitting it with the swing worker thread. There's also a Swing class which should help out, DefaultEditorKit.CopyAction \$\endgroup\$ Feb 5, 2013 at 22:40
  • \$\begingroup\$ Hmm, you might solve all my problems with this CopyAction. It looks like it has to be in a menu item to work though as per this link (java2s.com/Code/Java/Swing-JFC/SimpleEditorDemo.htm). If you have worked with it do you know how I could submit a string to "the action"? I feel it is ingrained in swing, and would be up to swing to find which Object we wish to copy, namely the object on the screen with focus? (Could that be a clue to submit a string to the action I need to give it a StringSelection object?) \$\endgroup\$
    – KDecker
    Feb 5, 2013 at 23:16
  • \$\begingroup\$ I have a feeling that you're supposed to pass a serializable object in the ActionEvent (as the source parameter). But other than that, I don't know off hand. To get that object, you're going to have to have some sort of 'picking', regardless of using Swing or the AWT version. \$\endgroup\$ Feb 6, 2013 at 0:12

1 Answer 1

1
\$\begingroup\$

This code is quite confusing. Do you know about parallel threads mechanisms?

CLUtilCompact.waitForMe = true;
set.start();

A new thread is started now and executes the run method from the interface. It is not defined when the thread is run, how fast and when he will execute any statements (and can not, the OS is responsible for this, not the JVM)

So, sometimes, this lines is called first:

while(CLUtilCompact.waitForMe){}

Sometimes this line is called first:

CLUtilCompact.waitForMe = false;

Even if the second line is called first, nobody knows when the field update will propagate to the other thread.

What we can do about this? In general, nothing. This is the (desired) behavior of threads.
For your problem, you can either block the application until the job is done, or hope that it is done fast enough asynchronously. You could implement some logic, which will display some error message after a given time. But this is quite a bad solution for slow system or systems under heavy load.

If you want to do something after the run method has finished, try SwingWorker (read the java documentation).


Some more things:

ClipSetThread set = new ClipSetThread(theApp);
set.arg = arg;

Use the constructor, add a second argument.


while(true) 
{
    try
    {
        sysClip.setContents(new StringSelection(arg), null);
    }
    catch(Exception e)
    {
        try {Thread.sleep(20);} catch (InterruptedException e1) {}
        continue;
    }
    break;
}
return;

Without discussing the pattern, this could be more readable:

boolean isSuccessful = false;
while(!isSuccessful) {
    try {
        sysClip.setContents(new StringSelection(arg), null);
        isSuccessful = true;
    }
    catch(Exception e) {
        try {Thread.sleep(20);} catch (InterruptedException e1) {} //you could use a method wait(seconds) for this
    }
}
return;

And you should, if possible, document inside the catch block why you are doing nothing there.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.