【问题标题】:JFrame won't disappear in time for screenshot to be takenJFrame 不会及时消失以便截取屏幕截图
【发布时间】:2015-04-20 00:42:34
【问题描述】:

此实用程序应用程序通过按下 JFrame 上的按钮来截取多个监视器的屏幕截图。该方法的预期逻辑如下:

  • 创建新的 Rectangle 来表示所有监视器边界的联合
  • 使用 InvokeAndWait 隐藏到 JFrame,并确保在进一步处理之前将其隐藏
  • 使用机器人类截取屏幕截图
  • 再次将框架设置为可见并返回图像

即使最后的“将框架返回可见”步骤从代码中注释掉,执行后我在屏幕上看不到任何框架,但该框架在屏幕截图中是可见的。我不知道为什么。

使用 print 语句,我已经确定在截取屏幕截图之前触发使 JFrame 不可见的方法确实会运行。我还尝试使用 if 语句在截屏之前检查 JFrame 是否可见,并且从未触发过 if 语句。

解决办法是什么?

public Image capture(ArrayList<Monitor> monitors) {

    Rectangle bounds = new Rectangle();
    monitors.stream().forEach(a -> Rectangle.union(bounds, a.getBounds(), bounds) );

    Image image = null;

    try {

        EventQueue.invokeAndWait(() ->  {
            frame.setVisible(false);
            System.out.println("Set frame invisible");
        });

    } catch (Exception ex) {
        ex.printStackTrace();
    }

    try {

        image = new Image(new Robot().createScreenCapture(bounds));

    } catch (Exception ex) {
        ex.printStackTrace();           
    }

    //frame.setVisible(true);
    return image;
}

【问题讨论】:

    标签: java swing


    【解决方案1】:

    这不是一个确定的答案,但也许它会为您指明正确的方向。

    我遇到了类似的问题,需要 JFrame 在使用 OpenGL 的 3D 应用程序上全屏显示。

    我假设正在发生的是 frame.setVisible() 与操作系统窗口管理器对话,请求隐藏(或显示)窗口。一旦发出并确认请求,方法调用就不再阻塞,invokeAndWait() 中的线程现在已完成调用和等待。

    您的代码继续截取屏幕截图,但不能保证操作系统实际处理了最小化窗口的请求。在您的情况下,似乎不是。

    解决方案(也许?): 看起来 Java 有一个名为 WindowEvent doc here 的类。您应该能够在等待状态更新的屏幕截图调用之前创建侦听器和/或循环。请注意文档特别说明:

    窗口停用事件类型。当窗口不再是活动窗口时,将传递此事件。只有 Frame 或 Dialog 可以是活动窗口。 本机窗口系统可能表示活动窗口或其具有特殊装饰的子窗口,例如突出显示的标题栏。活动窗口始终是焦点窗口,或者是焦点窗口所有者的第一个框架或对话框。

    我怀疑等待 WINDOW_DEACTIVATED 和/或 WINDOW_LOST_FOCUS 可能是操作系统窗口管理器是否已最小化窗口的实际指标。

    再次,我基于几个月前从事的一个几乎不相关的项目,但希望其中一些会有所帮助。

    更新

    OP 实现的解决方案如下:

    public Image capture(ArrayList<Monitor> monitors) 
    {
    
        Rectangle bounds = new Rectangle();
        monitors.stream().forEach(a -> Rectangle.union(bounds, a.getBounds(), bounds) );
    
        Image image = null;
    
        try 
        {
    
            EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.ICONIFIED));
    
            while (frame.getExtendedState() != Frame.ICONIFIED) { }
            image = new Image(new Robot().createScreenCapture(bounds));
    
        } 
        catch (Exception ex) 
        {
            ex.printStackTrace();           
        }
    
        EventQueue.invokeLater(() -> frame.setExtendedState(Frame.NORMAL));
    
        return image;
    }
    

    【讨论】:

    • 好主意。非常感谢。简单地最小化窗口,截取屏幕截图,然后最大化窗口工作如此之快,以至于不需要“检查”,尽管我最终放在那里只是为了安全。请在您的答案中包含我的最终代码,以便未来的观众可以从中受益。然后我会将您的答案标记为正确。谢谢你。工作代码:pastebin.com/xGCnF6ve
    • 完成!很高兴我能帮忙:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 2012-03-10
    • 1970-01-01
    相关资源
    最近更新 更多