14

Robot is part of the AWT library, but it seems quite different from most all the rest of the library. I am creating a Swing GUI that mixes Swing with Java Native Access (JNA) and Robot to allow Java to drive some MS Windows/Citrix work programs. My gut feeling is that since Robot will queue events on the "platform's native input queue" that the last thing I want to do is to run it on the EDT, but on the other hand, most of the classes in the AWT and Swing libraries should be run on the Swing event thread. So to try clarify this in my mind for me let me ask as specific a question as possible:

Should Robot methods (in particular key presses and releases, mouse moves, mouse presses and releases) be run on or off of the Swing event dispatch thread (the EDT)?

Roman C
  • 49,761
  • 33
  • 66
  • 176
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    I don't know the answer, but +1 for the question. I had always been confused by Sun/Oracle's claim that "**Swing** GUIs should be created & updated on the EDT" thinking - why does this ***not*** apply to AWT? – Andrew Thompson May 06 '12 at 05:49
  • 1
    Here, I guess don't know, how much this will help, but that [answer](http://groups.google.com/group/jfxtras-dev/browse_thread/thread/d0521de3af5e3ded) by Stephen might can help a bit, starting Robot related stuff in the background. – nIcE cOw May 06 '12 at 05:52
  • not I have got the best experiences if is locked by Thread.sleep(int) – mKorbel May 06 '12 at 06:37
  • @AndrewThompson: Many AWT component methods are synchronized internally. I think the advent of Swing exposed some of the memory model problems addressed in the transition from version 4 to 5. – trashgod May 06 '12 at 09:40
  • @trashgod *"Many AWT component methods are synchronized internally."* Many, but not all? BTW - I think that unless there is some contract or specification that states AWT components are internally synchronized, it would be dangerous to presume as much in production code. – Andrew Thompson May 06 '12 at 09:49

3 Answers3

10

The Robot methods you mentioned should not be run on the EDT. Taking a look at the source code revealed that each one of these "event" methods has one thing in common (the afterEvent call):

public synchronized void keyPress(int keycode) {
    checkKeycodeArgument(keycode);
    peer.keyPress(keycode);
    afterEvent();
}

public synchronized void mousePress(int buttons) {
    checkButtonsArgument(buttons);
    peer.mousePress(buttons);
    afterEvent();
}

// etc

private void afterEvent() {
    autoWaitForIdle();
    autoDelay();
}

private void autoWaitForIdle() {
    if (isAutoWaitForIdle) {
        waitForIdle();
    }
}

public synchronized void waitForIdle() {
    checkNotDispatchThread();
    /* snip */
}

private void checkNotDispatchThread() {
    if (EventQueue.isDispatchThread()) {
        throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
    }
}

If you call any of these methods on the EDT while Robot.isAutoWaitForIdle is true, an exception will be thrown. This stands to reason that even if isAutoWaitForIdle is false, these methods shouldn't be called from the EDT.

Jeffrey
  • 44,417
  • 8
  • 90
  • 141
6
  • API quite exactly talks, then I'm understand that that Robot should be ignore if is invoked from EDT or not

Using the class to generate input events differs from posting events to the AWT event queue or AWT components in that the events are generated in the platform's native input queue.

  • I'm rellative new in Java, my first touch was Java1.6.009, then I can't compare changes for AWT and (when born) Swing in Java1.3 and rest in Java1.4

my example

import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;

public class CaptureScreen implements ActionListener {

    private JFrame f = new JFrame("Screen Capture");
    private JPanel pane = new JPanel();
    private JButton capture = new JButton("Capture");
    private JDialog d = new JDialog();
    private JScrollPane scrollPane = new JScrollPane();
    private JLabel l = new JLabel();
    private Point location;

    public CaptureScreen() {
        capture.setActionCommand("CaptureScreen");
        capture.setFocusPainted(false);
        capture.addActionListener(this);
        capture.setPreferredSize(new Dimension(300, 50));
        pane.add(capture);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(pane);
        f.setLocation(100, 100);
        f.pack();
        f.setVisible(true);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                createPicContainer();
            }
        });
    }

    private void createPicContainer() {
        l.setPreferredSize(new Dimension(700, 500));
        scrollPane = new JScrollPane(l,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setBackground(Color.white);
        scrollPane.getViewport().setBackground(Color.white);
        d.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
        d.add(scrollPane);
        d.pack();
        d.setVisible(false);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("CaptureScreen")) {
            Dimension d1 = Toolkit.getDefaultToolkit().getScreenSize(); // gets the screen size
            Robot r;
            BufferedImage bI;
            try {
                r = new Robot(); // creates robot not sure exactly how it works
                Thread.sleep(1000); // waits 1 second before capture
                bI = r.createScreenCapture(new Rectangle(d1)); // tells robot to capture the screen
                showPic(bI);
                saveImage(bI);
            } catch (AWTException e1) {
                e1.printStackTrace();
            } catch (InterruptedException e2) {
                e2.printStackTrace();
            }
        }
    }

    private void saveImage(BufferedImage bI) {
        try {
            ImageIO.write(bI, "JPG", new File("screenShot.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void showPic(BufferedImage bI) {
        ImageIcon pic = new ImageIcon(bI);
        l.setIcon(pic);
        l.revalidate();
        l.repaint();
        d.setVisible(false);
        location = f.getLocationOnScreen();
        int x = location.x;
        int y = location.y;
        d.setLocation(x, y + f.getHeight());
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                d.setVisible(true);
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                CaptureScreen cs = new CaptureScreen();
            }
        });
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Miroslav, Mike should be English ..., my question this console is Remote Session via Citrix Farm??? – mKorbel May 06 '12 at 16:02
  • (Miroslav): The nature of the driven application (the one being driven by my Java program) will depend on the location. If I'm at the office, it will be a stand-alone application. If I'm at home and connected to the office via computer, it will be a Citrix client (which greatly limits how I can interact with it). – Hovercraft Full Of Eels May 06 '12 at 16:11
6

Amplifying on @mKorbel's thoughtful answer, and confirming his empirical result, note how the various Robot methods delegate to an internal instance of the RobotPeer interface, the native implementation of which varies by platform. Moreover, the methods are synchronized. The synthetic events all arrive on the EventQueue, irrespective of the source.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I'm think that for recurring screenshot required breaking all threads by Thread.sleep(int); +1 and I think too that former AWT methods that became from Java1-3 can pretty ignore if is there EDT or not, simple working, somethines with strange delay but works – mKorbel May 06 '12 at 08:40
  • [`Zoom`](http://stackoverflow.com/a/3742841/230513) invokes `createScreenCapture()` in `mouseDragged()`; it seems to work without any delay, but each `MouseEvent` is separate. – trashgod May 06 '12 at 08:48