Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否需要在事件队列上运行Robot方法?_Java_Swing_Thread Safety_Awtrobot - Fatal编程技术网

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

Java 是否需要在事件队列上运行Robot方法?,java,swing,thread-safety,awtrobot,Java,Swing,Thread Safety,Awtrobot,Robot是AWT库的一部分,但它似乎与库的大多数其他部分有很大的不同。我正在创建一个Swing GUI,它将Swing与Java本机访问(JNA)和Robot混合在一起,以允许Java驱动一些MS Windows/Citrix工作程序。我的直觉是,由于Robot将在“平台的本机输入队列”上排队事件,所以我最不想做的事情就是在EDT上运行它,但另一方面,AWT和Swing库中的大多数类都应该在Swing事件线程上运行。因此,为了让我在脑海中澄清这一点,让我问一个尽可能具体的问题: 机器人方法(特

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

机器人方法(特别是按键和释放、鼠标移动、鼠标按下和释放)是否应该在Swing事件调度线程(EDT)上运行
  • API非常准确地说明了这一点,所以我理解,如果从EDT调用或不调用,则应该忽略该机器人
  • 使用类生成输入事件不同于将事件发布到AWT事件队列或AWT组件,因为事件是在平台的本机输入队列中生成的

    • 我是Java的新手,我的第一次接触是Java1.6.009,然后我无法比较Java1.3中AWT和(出生时)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深思熟虑的回答,并确认他的实证结果,注意各种方法如何委托给
    RobotPeer
    接口的内部实例,其本机实现因平台而异。此外,这些方法是同步的。合成事件全部到达
    事件队列
    ,而不管其来源如何。

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


    如果您在EDT上调用这些方法中的任何一个,而值为
    true
    ,则会引发异常。因此,即使
    isAutoWaitForIdle
    false
    ,也不应从EDT调用这些方法。

    我不知道答案,但问题的答案是+1。Sun/Oracle声称“Swing GUI应该在EDT上创建和更新”,我一直对此感到困惑——为什么这不适用于AWT?我想我不知道这会有多大帮助,但Stephen的这一说法可能会有所帮助,在后台启动与机器人相关的东西。如果被线程锁定,我没有得到最好的体验。sleep(int)@andrewhompson:许多AWT组件方法都是内部同步的。我认为Swing的出现暴露了在从版本4到版本5的转换过程中解决的一些内存模型问题。@trashgod“许多AWT组件方法是内部同步的。”很多,但不是全部?顺便说一句,我认为除非有合同或规范规定AWT组件是内部同步的,否则在生产代码中假设这么多是危险的+1我也认为,如果存在EDT或不存在EDT,从Java1-3发展而来的以前的AWT方法可以忽略,简单的工作,一些具有奇怪延迟的东西,但works在
    mouseDragged()中调用
    createScreenCapture()
    ;它似乎毫不延迟地工作,但每个
    MouseEvent
    都是独立的。Miroslav,Mike应该是英国人…,我的问题是这个控制台是通过Citrix Farm进行远程会话的???(Miroslav):受驱动应用程序(由我的Java程序驱动的应用程序)的性质将取决于位置。如果我在办公室,它将是一个独立的应用程序。如果我在家,通过电脑连接到办公室,它将是Citrix客户端(这大大限制了我与它的交互方式)。
    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");
        }
    }