Java JFrame.setVisible(false)和Robot.createScreenCapture计时

Java JFrame.setVisible(false)和Robot.createScreenCapture计时,java,swing,awt,Java,Swing,Awt,我试图在不包含应用程序窗口的情况下捕获屏幕。为此,我首先调用setVisible(false),然后调用createScreenCapture方法,最后调用setVisible(true)。但这不起作用,我仍然在屏幕截图中看到我的应用程序窗口。如果我添加一个睡眠呼叫,这似乎可以解决问题,但我知道这是一个糟糕的做法。正确的方法是什么 代码: setVisible(false); BufferedImage screen = robot.createScreenCapture(rectScreenS

我试图在不包含应用程序窗口的情况下捕获屏幕。为此,我首先调用setVisible(false),然后调用createScreenCapture方法,最后调用setVisible(true)。但这不起作用,我仍然在屏幕截图中看到我的应用程序窗口。如果我添加一个睡眠呼叫,这似乎可以解决问题,但我知道这是一个糟糕的做法。正确的方法是什么

代码:

setVisible(false);
BufferedImage screen = robot.createScreenCapture(rectScreenSize);
setVisible(true);

您是否尝试过使用SwingUtilities.invokeLater()并在作为参数传递的runnable内部运行捕获?我的猜测是,为删除应用程序而执行的重新绘制是在AWT EventQueue中的当前事件结束之后执行的,因此立即调用调用仍然会捕获您的窗口。通过invokeLater在延迟事件中调用createCapture应该可以解决这个问题。

例如,您必须通过实现来延迟此操作

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;
    private Timer timer1;

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

    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);
        d.addWindowListener(new WindowListener() {

            public void windowOpened(WindowEvent e) {
            }

            public void windowClosing(WindowEvent e) {
                f.setVisible(true);
            }

            public void windowClosed(WindowEvent e) {
            }

            public void windowIconified(WindowEvent e) {
            }

            public void windowDeiconified(WindowEvent e) {
            }

            public void windowActivated(WindowEvent e) {
            }

            public void windowDeactivated(WindowEvent e) {
            }
        });
    }

    private void startTimer() {
        timer1 = new Timer(1000, new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        capture.doClick();
                        f.setVisible(false);
                    }
                });
            }
        });
        timer1.setDelay(500);
        timer1.setRepeats(false);
        timer1.start();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("CaptureScreen")) {
            Dimension dim = 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(dim)); // 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());
        d.setLocation(150, 150);
        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();
            }
        });
    }
}

注意:我已经尝试了JFrame.repaint()和JFrame.validate(),但没有成功。该死!我本来想这么说的。我想我得投票了在代码中,您正在从事件队列中调用Thread.sleep。这正是我想要避免的@Ryan:-)在这个回答之后,我没有兴趣解释为什么它只在以下方面起作用……禁用Windows效果,它会像一个符咒一样工作,甚至不需要调用器。如果你事先不知道是否启用了动画(最小化和最大化窗口),那么你别无选择,只能使用计时器。这是邪恶的,只是因为它冻结了用户的窗口。我不明白。什么是Windows效果以及如何禁用它们?就计时器而言,我也不认为这会有什么帮助。我只需要一种方法来强制事件的绝对顺序,以便在拍摄屏幕截图之前,窗口实际上是隐藏的。Windows效果是在Windows事件发生时由操作系统执行的动画。例如,当您最小化窗口时,操作系统可能会在任务栏中“显示”窗口,而不是简单地隐藏窗口。这可能需要几百毫秒。在Windows上,您可以通过以下方式停用这些效果:右键单击“计算机”-->属性-->“(高级)系统设置”-->单击“性能”面板中的“设置”,并禁用“最小化和最大化时设置窗口动画”。还有一个问题是,您要从屏幕上删除的JFrame背后的内容。后面的应用程序需要重新绘制,以便在JFrame以前所在的位置绘制自身。如果windows将该应用程序换出磁盘,则需要几分钟才能刷新。当然,这是一个极端的情况,但关键是在某些情况下,您希望询问windows是否所有应用程序都已完成刷新/重新绘制。我认为这样的api函数不存在。