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