Java:重复调用 paintAll 挂起程序

标签 java awt paint

我通过创建 BufferedImage 在 Java 程序中实现视频捕获s 以用户定义的间隔(对于我的测试,100 毫秒),然后使用这些图像制作电影文件。 JFrame我试图记录的内容包括一个类似仪表板的界面,由 JLayeredPane 包含. JFrame还有两个Canvas3D秒。我把这三件事都告诉了 renderpaint融入自己LinkedBlockingDeque<BufferedImage> ,我稍后将它们组合起来。仪表板设置为仅呈现每个 dashboardFrameRepaintFrequency帧。

Thread captureThread = new Thread(new Runnable() {
    public void run() {
        final Object LOCK = new Object();
            final Thread captureDashboard = new Thread(new Runnable() {
                public void run() {
                    while (m_isCapturingMovie) {
                        synchronized (LOCK) {
                            try {
                                LOCK.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } finally {
                                System.err.println("Calling getDashboardImage");
                                m_unsavedDash.add(getDashboardImage(m_dashboard.getWidth(), m_dashboard.getHeight(), BufferedImage.TYPE_INT_ARGB));
                                System.err.println("captureDashboard returned from calling m_unsavedDash.add...");
                            }
                        }
                    }
                }
            });
            captureDashboard.start();

            while (m_isCapturingMovie) {
                startTime = System.currentTimeMillis();
                captureCanvases();
                if (++frameCount > dashboardFrameRepaintFrequency) {
                    frameCount = 0;
                    synchronized (LOCK) {
                        LOCK.notify();
                    }
            }
            endTime = System.currentTimeMillis();
            millisToSleep = captureDelayInMillis - (endTime - startTime);
            if (millisToSleep > 0) {
                try {
                    Thread.sleep(millisToSleep);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        synchronized (captureDashboard) {
        captureDashboard.notify();
        }
    }
});

我发现在 15-20 notify() 之后s,程序锁定 - 它停止记录 Canvas ,停止响应键盘输入。我仍然可以更改哪个窗口具有焦点,并且按钮(例如关闭窗口的 X 按钮)仍然会因鼠标悬停而改变视觉状态或点击,但他们不执行他们的命令。

从控制台输出来看,captureDashboard 线程似乎在 15-20 次迭代之后没有从 getDashboardImage 返回。方法:

private BufferedImage getDashboardImage(int width, int height, int type) {
    BufferedImage dashImg = new BufferedImage(m_dashboard.getWidth(), m_dashboard.getHeight(), type);
    Graphics2D g = dashImg.createGraphics();
    m_dashboard.paintAll(g);
    g.dispose();

    return getScaledImage(width, height, dashImg);
}

private BufferedImage getScaledImage(int width, int height, BufferedImage original) {
    BufferedImage scaled = new BufferedImage(width, height, original.getType());

    AffineTransform at = new AffineTransform();
    at.scale((double) scaled.getWidth() / original.getWidth(), (double) scaled.getHeight() / original.getHeight());
    AffineTransformOp scaleOp;
    if (at.getScaleX() + at.getScaleY() > 2.0) {
        scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC); // Better quality for enlargement
    } else {
        scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); // Better quality for ensmallment
    }

    scaled = scaleOp.filter(original, scaled);
    original.flush();
    return scaled;
}

有什么想法吗?我已经为此工作了几天,但我很困惑。

最佳答案

问题是我需要从 AWT 调度线程调用 paintAll

所以代替:

m_dashboard.paintAll(g);

我需要:

final Graphics2D g = dashImg.createGraphics();

EventQueue.invokeLater(new Runnable() {
    public void run () {
        m_dashboard.paintAll(g);
    }
});

但是,这导致我的程序“超前”并在绘制之前返回 BufferedImage,但前提是程序负载很重。为了说明这一点,我刚刚添加了以下内容:

final Graphics2D g = dashImg.createGraphics();
final SyncObj LOCK = new SyncObj();

EventQueue.invokeLater(new Runnable() {
    public void run () {
        m_dashboard.paintAll(g);
        LOCK.doNotify();
    }
});

LOCK.doWait();
g.dispose();

其中 SyncObj 只是一个简单的:

class SyncObj {
    private boolean condition = false;
    private Object obj = new Object();

    public void doWait() {
        synchronized (obj) {
            while (!condition) {
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            condition = false;
        }
    }

    public void doNotify() {
        synchronized (obj) {
            condition = true;
            obj.notify();
        }
    }
}

关于Java:重复调用 paintAll 挂起程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17750753/

相关文章:

java - 循环中增加变量,意外结果

java - 当我使用 <h :outputText/>? 时,为什么 Oracle ADF 不为我转义引号

java - 如何从 jsonarray 读取值?

java Graphics2D - 生成动态图像

java - 使用 super.paint() 不会显示任何内容

java - 重画并不总是有效

Java - 子类中的绘制方法不起作用

java - 正确从 C# 运行 Java 应用程序

Java - Swing/AWT ComponentListener 意外行为

java - 使我的输出( Canvas )仅显示 [0,1] 之间的值(Java)