Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java截图捕获-JFrame为第二个&;即使移除了所有组件,也会消失&;重新油漆_Java_Swing_Api_User Interface - Fatal编程技术网

Java截图捕获-JFrame为第二个&;即使移除了所有组件,也会消失&;重新油漆

Java截图捕获-JFrame为第二个&;即使移除了所有组件,也会消失&;重新油漆,java,swing,api,user-interface,Java,Swing,Api,User Interface,在阅读之前,本文将提供以下信息: 您好,我正在开发一个库API,它可以让您捕获屏幕的一个区域,并返回一个类,该类包含ByteArrayInputStream和实用程序方法,如CreateBuffereImage,createFile,等等 基本上,您创建一个引导实例,并将所需的捕获器类型作为依赖项传递(ScreenshotCapturer或GifCapturer): 并且beginCapture方法接收一个实现ScreenCaptureCallback的对象,该对象是捕获的结果将传递给的回调事件

在阅读之前,本文将提供以下信息:

您好,我正在开发一个库API,它可以让您捕获屏幕的一个区域,并返回一个类,该类包含
ByteArrayInputStream
和实用程序方法,如
CreateBuffereImage
createFile
,等等

基本上,您创建一个引导实例,并将所需的捕获器类型作为依赖项传递(ScreenshotCapturer或GifCapturer):

并且
beginCapture
方法接收一个实现
ScreenCaptureCallback
的对象,该对象是捕获的结果将传递给的回调事件

这是一个简短的背景

现在,当您使用
beginCapture
方法时,它所做的基本上是创建
SelectionCamera
的新实例,这基本上就是在拖动鼠标时绘制所选选择区域并更新侦听器的组件

创建实例后,它调用
super.setVisible(true)

调用该方法后,框架将显示,并显示600-500毫秒的旧绘制屏幕,我不太确定,但它消失得太快了

看一看这个活生生的例子:

注意使用视频选项,否则您将看不到我看到的内容,因为gif太慢,无法显示

你可以看到我再次点击屏幕截图后,它显示了旧的选定区域并很快消失。(顺便说一句,你在gif中看到的帧不是应用程序的一部分,只是虚拟的hello world示例用法)

图像捕获的过程

步骤1

beginCapture
被调用:

public void beginCapture(final ScreenCaptureCallback c) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            capturer.setCallback(c);
            capturer.beginSelection();

        }
    });
}
步骤2

在Capturer类中调用
beginSelection
ScreenshotCapturer
extends
Capturer
(摘要)

步骤3

CaptureCamera#startSelection()
被调用

public void startSelection() {
    super.getContentPane().removeAll();
    super.getContentPane().repaint();

    super.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));

    this.selector = new SelectionCamera();
    this.selectionMosueAdapter.updateCamera(this.selector);
    this.selectionMouseMotion.updateCamera(this.selector);

    super.add(this.selector);

    super.setVisible(true);
    super.repaint();
    super.getContentPane().repaint();
}
步骤4

用户选择一个区域,鼠标侦听器和鼠标运动都会侦听该区域(查看鼠标运动):

顺便说一句
这个.selector
SelectorCamera
,它是绘制选择区域的组件。

步骤5

调用CaptureCamera#endSelection()时,此方法从选择摄影机获取x、y、宽度和高度,并将其传递给capturer类,该类使用Robot获取该矩形的屏幕截图,在此之前,它从内容窗格中移除所有组件,重新绘制所有内容,然后将可见性设置为false

public void endSelection() {
    super.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

    int x = this.selector.getCameraX();
    int y = this.selector.getCameraY();
    int w = this.selector.getCameraWidth();
    int h = this.selector.getCameraHeight();

    super.getContentPane().removeAll();
    super.getContentPane().repaint();

    //super.repaint();
    super.setVisible(false);

    this.c.startCapturing(x, y, w, h);

}
基本上这是最后一步,其余步骤对于调试是不必要的,因为它只发回回调

我真的尽了最大的努力解释我的应用程序的过程,我已经试了5个半小时了,但一点运气都没有。我尝试了不同的方法,创建了新的
SelectionCamera
对象,正如你所见,不起作用

它为什么要这样做?是不是和swing core有关

选择摄像头代码:


提前感谢。

将左框设置为-10000,然后将其设置为可见为真,添加计时器2秒(尝试降低到25-100毫秒,只是为了让其稍微暂停以使内容无效),在计时器上:左至0。我认为它之所以能工作是因为缓存和双缓冲。帧显示了它在缓冲区中的内容,缓冲区指向旧图像是因为缓存/延迟重绘


备选方案:
也许在你的节目开始前重新粉刷或失效也会起作用,并且不需要做剩下的-10000。我对ui swing不太在行,只是几年前,我还记得一些类似这样的奇怪事情。

基于这个例子

try {
    final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
    b.beginCapture(new ScreenCaptureCallback() {
        @Override
        public void captureEnded(CapturedImage img) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    b.beginCapture(new ScreenCaptureCallback() {
                        @Override
                        public void captureEnded(CapturedImage img) {
                            System.out.println("...");
                            JFrame frame = new JFrame();
                            frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
                            frame.pack();
                            frame.setVisible(true);
                            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        }
                    });
                }
            });
        }
    });
    System.out.println("Hello");
} catch (AWTException exp) {
    exp.printStackTrace();
}
我不会集中在第一轮的初始阶段,我会集中在第二轮的初始阶段,因为这就是问题所在

b.beginCapture
调用的
this.capturer.beginSelection();
,它调用
super.getCamera().startSelection();
它调用
setVisible(true)
CaptureCamera
已经成为
JFrame

这将立即显示以前在
CaptureCamera
上显示的内容。在此需要注意的是,在此过程中没有创建新的对象实例

现在,我对测试这个的基础做了很多更改,但问题似乎是当第二次显示时框架的恢复。这似乎是窗口透明度支持的问题,因为它似乎恢复了最后一个“已知”状态,而不是立即重新绘制窗口

现在,我尝试在使
CaptureCamera
对no eval不可见之前清除
选择器
,因为在绘制
选择器
之前,窗口似乎不可见

我想出的最后一个解决方案是在
CaptureCamera
上调用
dispose
,这会释放它的本地对等对象,因此会破坏旧的图形上下文,迫使帧在再次可见时重建自身

“一个”问题可能是,当所有的窗口都被释放(并且唯一运行的线程是守护进程线程)时,JVM将退出

在我的测试过程中,这是一个问题,因为我使用
javax.swing.Timer
在第一个和第二个捕获过程之间设置延迟,以便我可以看到问题发生的位置,这导致我的JVM退出(因为计时器使用守护进程线程,我没有打开其他窗口)

我通过在
Capturer
类中创建一个小(1x1)透明窗口来解决这个问题,如果JVM无缘无故地存在,请记住这一点;)

旁注。。。 现在,
SelectionCamera
(扩展了<
@Override
public void mouseDragged(MouseEvent e) {
    Point dragPoint = e.getPoint();
    Point startPoint = this.selector.getStartPoint();

    int x = Math.min(startPoint.x, dragPoint.x);
    int y = Math.min(startPoint.y, dragPoint.y);
    int width = Math.max(startPoint.x - dragPoint.x, dragPoint.x - startPoint.x);
    int height = Math.max(startPoint.y - dragPoint.y, dragPoint.y - startPoint.y);

    this.selector.setCameraDimension(width, height);
    this.selector.setCoordinates(x, y);

    this.camera.repaint(); // important
}
public void endSelection() {
    super.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

    int x = this.selector.getCameraX();
    int y = this.selector.getCameraY();
    int w = this.selector.getCameraWidth();
    int h = this.selector.getCameraHeight();

    super.getContentPane().removeAll();
    super.getContentPane().repaint();

    //super.repaint();
    super.setVisible(false);

    this.c.startCapturing(x, y, w, h);

}
try {
    final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
    b.beginCapture(new ScreenCaptureCallback() {
        @Override
        public void captureEnded(CapturedImage img) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    b.beginCapture(new ScreenCaptureCallback() {
                        @Override
                        public void captureEnded(CapturedImage img) {
                            System.out.println("...");
                            JFrame frame = new JFrame();
                            frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
                            frame.pack();
                            frame.setVisible(true);
                            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        }
                    });
                }
            });
        }
    });
    System.out.println("Hello");
} catch (AWTException exp) {
    exp.printStackTrace();
}
public SelectionCamera() {
    super.setBackground(new Color(0, 0, 0, 0));
    super.setVisible(false);
}
public SelectionCamera() {
    setOpaque(false);
    //super.setBackground(new Color(0, 0, 0, 0));
    super.setVisible(false);
}
@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(new Color(0, 0, 0, 0.5f));
    g.fillRect(this.x, this.y, this.width, this.height);
}