cancel java swing thread-safety awtrobot

java - cancel - swingworker



¿Deben ejecutarse los métodos de robot en la cola de eventos? (3)

Ampliando la cuidadosa respuesta de @ mKorbel y confirmando su resultado empírico, observe cómo los diversos métodos de Robot delegan en una instancia interna de la interfaz de RobotPeer , cuya implementación nativa varía según la plataforma. Además, los métodos están sincronizados. Todos los eventos sintéticos llegan a EventQueue , independientemente de la fuente.

El robot es parte de la biblioteca de AWT, pero parece bastante diferente de la mayoría del resto de la biblioteca. Estoy creando una Swing GUI que combina Swing con Java Native Access (JNA) y Robot para permitir que Java conduzca algunos programas de trabajo de MS Windows / Citrix. Mi intuición es que, como Robot pondrá en cola los eventos en la "cola de entrada nativa de la plataforma", lo último que quiero hacer es ejecutarlo en la EDT, pero por otro lado, la mayoría de las clases en las bibliotecas de AWT y Swing debe ejecutarse en el hilo del evento Swing. Así que para intentar aclarar esto en mi mente, permítame hacer una pregunta lo más específica posible:

¿Deben ejecutarse los métodos de robot (en particular las pulsaciones y liberaciones de teclas, los movimientos del mouse, las pulsaciones y las liberaciones del mouse) dentro o fuera del subproceso de envío del evento Swing (EDT)?


Los métodos de Robot que mencionó no deben ejecutarse en el EDT. Mirar el código fuente reveló que cada uno de estos métodos de "evento" tiene una cosa en común (la llamada 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"); } }

Si llama a alguno de estos métodos en la EDT mientras que Robot.isAutoWaitForIdle es true , se Robot.isAutoWaitForIdle una excepción. Esto es lógico porque incluso si isAutoWaitForIdle es false , estos métodos no deberían llamarse desde la EDT.


  • La API habla exactamente, entonces entiendo que ese Robot debe ignorarse si se invoca desde EDT o no

El uso de la clase para generar eventos de entrada difiere de la publicación de eventos en la cola de eventos de AWT o los componentes de AWT en que los eventos se generan en la cola de entrada nativa de la plataforma.

  • Soy relativamente nuevo en Java, mi primer toque fue Java1.6.009, luego no puedo comparar los cambios para AWT y (cuando nací) Swing en Java1.3 y resto en Java1.4

mi ejemplo

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