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