如何在Java中截取非活跃状态下的指定软件窗口截图?
实现非活跃指定窗口的定时截图
要截取非活跃状态的指定窗口,Java标准库的Robot类无法直接获取目标窗口的位置和句柄,需要借助**JNA(Java Native Access)**调用Windows系统API来实现。以下是完整的实现步骤和代码:
1. 引入JNA依赖
如果使用Maven,在pom.xml中添加:
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency>
2. 核心实现代码
步骤说明:
- 通过窗口标题找到目标窗口的句柄(HWND)
- 获取窗口的屏幕坐标和尺寸
- 用
Robot截取对应区域,或调用系统API直接截图(更稳定) - 定时执行截图任务
import com.sun.jna.Native; import com.sun.jna.platform.win32.*; import com.sun.jna.win32.W32APIOptions; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; // 定义JNA接口,调用Windows API interface User32 extends StdCallLibrary { User32 INSTANCE = Native.load("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS); HWND FindWindow(String lpClassName, String lpWindowName); boolean GetWindowRect(HWND hWnd, WinUser.RECT rect); } interface GDI32 extends StdCallLibrary { GDI32 INSTANCE = Native.load("gdi32", GDI32.class); HDC GetDC(HWND hWnd); HDC CreateCompatibleDC(HDC hdc); HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight); HBITMAP SelectObject(HDC hdc, HBITMAP hBitmap); boolean BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, int dwRop); boolean DeleteObject(HBITMAP hBitmap); int ReleaseDC(HWND hWnd, HDC hdc); boolean DeleteDC(HDC hdc); } public class WindowCapture { // 目标窗口标题(替换成你要截图的窗口标题) private static final String TARGET_WINDOW_TITLE = "记事本"; // 截图保存路径 private static final String SAVE_PATH = "C:\\Users\\Public\\Documents\\tessdata\\window_capture_"; // 定时间隔(单位:秒) private static final long INTERVAL = 10; public static void main(String[] args) { // 启动定时任务 ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleAtFixedRate(WindowCapture::captureTargetWindow, 0, INTERVAL, TimeUnit.SECONDS); } private static void captureTargetWindow() { // 1. 找到目标窗口句柄 HWND hwnd = User32.INSTANCE.FindWindow(null, TARGET_WINDOW_TITLE); if (hwnd == null || hwnd.equals(WinDef.NULL)) { System.err.println("未找到目标窗口:" + TARGET_WINDOW_TITLE); return; } // 2. 获取窗口的屏幕坐标和尺寸 WinUser.RECT rect = new WinUser.RECT(); if (!User32.INSTANCE.GetWindowRect(hwnd, rect)) { System.err.println("获取窗口位置失败"); return; } int width = rect.right - rect.left; int height = rect.bottom - rect.top; // 方法一:用Robot截取指定区域(简单,但窗口被遮挡时会截取到遮挡内容) try { Robot robot = new Robot(); BufferedImage image = robot.createScreenCapture(new Rectangle(rect.left, rect.top, width, height)); String fileName = SAVE_PATH + System.currentTimeMillis() + ".png"; ImageIO.write(image, "png", new File(fileName)); System.out.println("截图保存成功:" + fileName); } catch (Exception e) { e.printStackTrace(); } // 方法二:调用Windows API直接截取窗口(即使被遮挡也能截到窗口内容,更稳定) // 注释掉方法一,取消注释以下代码即可使用 /* HDC hdcSrc = GDI32.INSTANCE.GetDC(hwnd); HDC hdcDest = GDI32.INSTANCE.CreateCompatibleDC(hdcSrc); HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcSrc, width, height); HBITMAP hOldBitmap = GDI32.INSTANCE.SelectObject(hdcDest, hBitmap); // 复制窗口图像到兼容DC GDI32.INSTANCE.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, WinGDIOptions.SRCCOPY); // 将HBITMAP转换为BufferedImage BufferedImage image = WinGDI.HBITMAPToBufferedImage(hBitmap); // 释放资源 GDI32.INSTANCE.SelectObject(hdcDest, hOldBitmap); GDI32.INSTANCE.DeleteObject(hBitmap); GDI32.INSTANCE.DeleteDC(hdcDest); GDI32.INSTANCE.ReleaseDC(hwnd, hdcSrc); try { String fileName = SAVE_PATH + System.currentTimeMillis() + ".png"; ImageIO.write(image, "png", new File(fileName)); System.out.println("截图保存成功:" + fileName); } catch (Exception e) { e.printStackTrace(); } */ } }
注意事项
- 替换
TARGET_WINDOW_TITLE为你要截图的窗口的准确标题(可以用Spy++工具查看窗口标题) - 方法一简单易实现,但如果窗口被其他窗口遮挡,会截取到遮挡的内容;方法二直接从窗口的DC获取图像,即使窗口被遮挡或最小化(需先恢复窗口)也能截取到窗口内容
- 确保程序有文件写入权限,保存路径存在
- 如果是最小化的窗口,需要先调用
User32.INSTANCE.ShowWindow(hwnd, WinUser.SW_RESTORE)恢复窗口再截图
内容的提问来源于stack exchange,提问作者Hussin Tsouli
相关产品推荐
相关产品推荐

