2012-05-06 11 views
18

Robot es parte de la biblioteca AWT, pero parece bastante diferente de la mayoría del resto de la biblioteca. Estoy creando una GUI de Swing 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, dado que Robot pondrá en cola eventos en la "cola de entrada nativa de la plataforma", lo último que quiero hacer es ejecutarlo en el EDT, pero por otro lado, la mayoría de las clases en las bibliotecas AWT y Swing se debe ejecutar en el hilo del evento Swing. Así que para intentar aclarar esto en mi mente, permítanme hacer una pregunta lo más específica posible:¿Deben ejecutarse los métodos de Robot en la cola de eventos?

Deberían ejecutarse o desactivarse los métodos del robot (en particular las pulsaciones de teclas y liberaciones, movimientos del mouse, pulsaciones del mouse y lanzamientos). Swing tema de envío del evento (el EDT)?

+1

No sé la respuesta, pero +1 para la pregunta. Siempre me ha confundido la afirmación de Sun/Oracle de que "** las GUI de ** Swing deben ser creadas y actualizadas en el EDT" pensando: ¿por qué este *** *** no se aplica a AWT? –

+1

Aquí, supongo que no sé, cuánto ayudará esto, pero esa [respuesta] (http://groups.google.com/group/jfxtras-dev/browse_thread/thread/d0521de3af5e3ded) de Stephen podría ayudar a un poco, comenzando cosas relacionadas con Robot en el fondo. –

+0

Andrew y Kindly Udders, gracias por su información útil. Si algo más viene a ti, ¡por favor comparte! –

Respuesta

10

Los métodos Robot que mencionó deberían no ejecutar en el EDT. Echando un vistazo al código fuente reveló que cada uno de estos métodos "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 se llama a cualquiera de estos métodos en la EDT mientras Robot.isAutoWaitForIdle es true, se lanzará una excepción. Es lógico que incluso si isAutoWaitForIdle es false, estos métodos no se deben llamar desde el EDT.

+0

¡Eso es todo! ¡Gracias! –

6
  • API bastante exactamente conversaciones, entonces yo soy entender que ese robot debe ignorar si se invoca desde EDT o no

Utilización de la clase para generar eventos de entrada difiere de publicar eventos a la Cola de eventos AWT o componentes AWT en que los eventos se generan en la cola de entrada nativa de la plataforma.

  • estoy rellative nuevo en Java, mi primer contacto fue Java1.6.009, entonces no puedo comparar los cambios de AWT y Swing (al nacer) en Java1.3 y descansar 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(); 
      } 
     }); 
    } 
} 
+0

Gracias como siempre mKorbel (¿cuál es tu nombre por cierto?). Déjame estudiar esto más tarde y responderte. –

+0

Miroslav, Mike debería ser inglés ..., mi pregunta es: ¿esta consola es sesión remota a través de Citrix Farm? – mKorbel

+0

(Miroslav): la naturaleza de la aplicación dirigida (la que está siendo impulsada por mi programa Java) dependerá de la ubicación. Si estoy en la oficina, será una aplicación independiente. Si estoy en casa y conectado a la oficina a través de una computadora, será un cliente Citrix (lo que limita en gran medida la forma en que puedo interactuar con él). –

6

Amplificar el @ respuesta reflexiva de mKorbel, y confirmando su resultado empírico, tenga en cuenta cómo los distintos métodos de delegado Robot a una instancia interna de la RobotPeer interfaz, cuya implementación nativa varía según la plataforma. Además, los métodos están sincronizados. Todos los eventos sintéticos llegan al EventQueue, independientemente de la fuente.

+0

Creo que para la captura de pantalla recurrente requiere romper todos los hilos por Thread.sleep (int); +1 y también creo que los antiguos métodos AWT que se convirtieron de Java1-3 pueden ignorar bastante si hay EDT o no, funciona de manera simple, algo con retraso extraño pero funciona – mKorbel

+0

['Zoom'] (http://stackoverflow.com/ a/3742841/230513) invoca 'createScreenCapture()' en 'mouseDragged()'; parece que funciona sin demora, pero cada 'MouseEvent' está separado. – trashgod

+0

Gracias como siempre ¡basura! –

Cuestiones relacionadas