为什么在Linux平台上的JFrame窗口中,BufferedImage输出与屏幕上的不同?

时间:2016-08-09 19:29:33

标签: java linux swing jframe bufferedimage

我正在开发一个需要捕获屏幕GUI(例如JFrame)图像数据的项目。不知何故,我的应用程序适用于Windows和Mac OS,但对于Linux,它不提供与屏幕GUI相同的图像输出。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.File;

class jframeExample {

public static BufferedImage getImageData(
        Component component) {

    BufferedImage image = new BufferedImage(
            component.getWidth(),
            component.getHeight(),
            BufferedImage.TYPE_INT_RGB
    );
    component.printAll( image.createGraphics() );
    return image;
}

public static void main(String[] args){

    Runnable r = new Runnable() {
        public void run() {
            final JFrame f = new JFrame("JFrame Border");
            f.setLayout(new BorderLayout());
            f.setLocation(500,300);
            f.setSize(560, 420);
            f.getContentPane().setBackground(Color.BLUE);

            JMenuItem screenshot =
                    new JMenuItem("TakeSnapshot");
            screenshot.addActionListener(
                    new ActionListener(){
                        public void actionPerformed(ActionEvent ae) {
                            BufferedImage imageOutput = getImageData(f);
                            try {
                                // write the image as a PNG
                                ImageIO.write(
                                        imageOutput,
                                        "png",
                                        new File("CapturedImage.png"));
                            } catch(Exception e) {
                                e.printStackTrace();
                            }
                        }
                    } );
            JMenu menu = new JMenu("Menu");
            menu.add(screenshot);
            JMenuBar menuBar = new JMenuBar();
            menuBar.add(menu);
            f.setJMenuBar(menuBar);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setVisible(true);

        }
    };
    SwingUtilities.invokeLater(r);
 }
}

上面的代码将为GUI提供Menu选项,将其捕获为图像输出。您可以将屏幕上的GUI和图像输出视为附加文件。生成的图像与屏幕GUI略有不同。查看JFrame边框的左/右边缘,它与contentPane蓝色重叠。

如何获得与屏幕GUI完全相同的图像或调整左/右边框以使其不与contentPane区域重叠?我使用LookAndFeel类尝试了几个选项,但还没有取得任何成功。任何帮助/建议将不胜感激。

On-Screen GUI
CapturedImage

2 个答案:

答案 0 :(得分:1)

Swing没有画出整个画面。框架是操作系统的小部件。

尝试使用Screen Image

当将帧指定为组件时,它将使用Robot类来拍摄图像。否则将使用Swing画。

答案 1 :(得分:0)

快速修复

尝试更改......

BufferedImage imageOutput = getImageData(f); 

BufferedImage imageOutput = getImageData(f.getContentPane());

这也可能适用于Linux(我目前无法测试),并且可以轻松解决您的问题。

解决方案

或者,您可以使用Robot课程。 Robot具有更兼容的屏幕捕获功能,但这意味着对您的代码进行了严格的更改。您可以在我的答案的最底部找到代码。让我解释所有变化的原因......

  1. Robot是执行屏幕截图所需的类。它可以捕获完整的桌面或部分屏幕。在这种情况下,我们将通过在桌面上找到相应的XY坐标来捕获应用程序的蓝色部分。在这种情况下,Robot需要是静态的,因为您尝试通过main()方法访问它。因此,Robot变量必须在main()方法之外,以便JMenuItem的{​​{1}}可以访问它。

  2. 如果您通过菜单执行屏幕捕获,菜单将出现在屏幕捕获中,因为您没有给菜单时间消失。结果,需要添加延迟。同时,这个延迟需要在一个单独的线程中发生,否则你的菜单就会冻结......我创建新线程的方式称为Lambda表达式。这只是一种轻松创建立即启动的新线程的简单方法,就是这样。它的工作原理如下:ActionListener

  3. 接下来是找到屏幕蓝色部分的坐标。这是框架的上下文窗格(或您希望捕获的任何组件)上的简单new Thread(() -> { /* Do something */ }.start();

  4. 现在可以通过getLocationOnScreen()创建屏幕截图,并使用之前的代码保存到文件中。
  5. 这就是全部!如果您有任何问题,请发表评论,我会稍后再回来查看。


    代码

    Robot