如何判断一个JFrame的绘图状态?

How to determine the drawing state of a JFrame?

我想截图JavaJFrame

有时候帧渲染没有完成,但是截图操作完成了。但是有时候他不会出现这种情况,好像跟根电脑性能有一定的关系!

Situation screenshots <--- 情况截图

我觉得可以Thread.sleep()延迟截图,但是无法确定sleep()的时间长度

Java代码:

package com.richardtang.apktesttool;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Test2 {

    public static Robot robot;

    static {
        try {
            robot = new Robot();
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        JPanel jPanel = new JPanel();
        for (int i = 1; i < 1000; i++) {
            jPanel.add(new JLabel(String.valueOf(i)));
        }

        JFrame jFrame = new JFrame();
        jFrame.setSize(500, 500);
        jFrame.setContentPane(jPanel);
        jFrame.setVisible(true);

        BufferedImage img = captureFrame(jFrame);
        try {
            ImageIO.write(img, "png", new File("/tmp/1.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage captureFrame(JFrame window) {
        window.setAlwaysOnTop(true);
        Point windowPoint = window.getLocation();
        Dimension windowSize = window.getSize();
        Rectangle rectangle = new Rectangle(
                (int) windowPoint.getX(),
                (int) windowPoint.getY(),
                windowSize.width,
                windowSize.height
        );
        return robot.createScreenCapture(rectangle);
    }
}

您可以使用 SwingUtilities invokeLater。根据文档,invokeLater 导致 doRun.run() 在 AWT 事件调度线程上异步执行。这将在处理完所有未决 AWT 事件后发生。因此,将在 frame/panel 绘制完成后进行屏幕截图。

更新

正如@camickr 正确指出的那样,确保您的 GUI 也以类似的方式创建,即在 AWT 事件调度线程 (EDT) 上创建。示例如下。

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ScreenCapture {
    JFrame jFrame = null;

    public void createGUI() {
        JPanel jPanel = new JPanel();
        for (int i = 1; i < 1000; i++) {
            jPanel.add(new JLabel(String.valueOf(i)));
        }

        jFrame = new JFrame();
        jFrame.setSize(500, 500);
        jFrame.setContentPane(jPanel);
        jFrame.setVisible(true);
    }

    public void capture() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    BufferedImage img = captureFrame(jFrame);
                    ImageIO.write(img, "png", new File("tmp/1.png"));
                } catch (AWTException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static void main(String[] args) {
        ScreenCapture sc = new ScreenCapture();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                sc.createGUI();
                sc.capture();
            }
        });
    }

    public static BufferedImage captureFrame(JFrame window) throws AWTException {
        Robot robot = new Robot();
        window.setAlwaysOnTop(true);
        Point windowPoint = window.getLocation();
        Dimension windowSize = window.getSize();
        Rectangle rectangle = new Rectangle((int) windowPoint.getX(), (int) windowPoint.getY(), windowSize.width,
                windowSize.height);
        return robot.createScreenCapture(rectangle);
    }
}