是否需要在事件队列上运行Robot方法?

机器人是AWT库的一部分,但它似乎与大多数库的其余部分完全不同。 我正在创建一个Swing GUI,它将Swing与Java Native Access(JNA)和Robot混合在一起,以允许Java驱动某些MS Windows / Citrix工作程序。 我的直觉是,因为Robot会在“平台的本机输入队列”上排队事件,我想要做的最后一件事是在EDT上运行它,但另一方面,AWT和Swing库中的大多数类应该在Swing事件线程运行。 因此,为了让我在脑海中澄清这一点,请让我尽可能具体地问一个问题:

机器人方法(特别是按键和释放,鼠标移动,鼠标按下和释放)是否应该在Swing事件调度线程(EDT)上运行?

你提到的Robot方法应该在EDT上运行。 看一下源代码,发现这些“事件”方法中的每一个都有一个共同点( afterEvent调用):

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

如果在Robot.isAutoWaitForIdletrue时在EDT上调用这些方法中的任何一个,则会抛出exception。 这是有道理的,即使isAutoWaitForIdlefalse ,也不应该从EDT调用这些方法。

  • API非常精确地说话,然后我明白如果从EDT调用那个机器人应该被忽略

使用类生成输入事件不同于将事件发布到AWT事件队列或AWT组件,因为事件是在平台的本机输入队列中生成的。

  • 我是Java的新人,我的第一个接触是Java1.6.009,然后我无法比较AWT的变化和(出生时)Java1.3中的Swing和Java1.4中的rest

我的例子

 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的深思熟虑的答案,并确认他的实证结果,注意各种Robot方法如何委托给RobotPeer接口的内部实例,其本机实现因平台而异。 而且,这些方法是同步的。 无论来源如何,合成事件都会到达EventQueue