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