Java 机器人从 Windows 系统托盘启动
Java Robot launched from Windows System Tray
我希望我的程序从系统托盘菜单执行屏幕捕获。
我让它工作了,但 MenuItem 本身隐藏得不够快,并且与屏幕的其余部分一起被捕获。
这是一个 MCVE,基于 Java 教程的 TrayIconDemo 示例的精简版:
(编辑:由于 Holger 的评论而变得更小)
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TrayCapture {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGUI();
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
private static void createAndShowGUI() throws Exception {
//Check the SystemTray support
if (!SystemTray.isSupported()) {
System.err.println("SystemTray is not supported");
return;
}
final PopupMenu popup = new PopupMenu();
final TrayIcon trayIcon = new TrayIcon(ImageIO.read(new URL("https://i.stack.imgur.com/wCF8S.png")));
trayIcon.setImageAutoSize(true);
// Create a popup menu components
MenuItem captureItem = new MenuItem("Capture");
MenuItem exitItem = new MenuItem("Exit");
//Add components to popup menu
popup.add(captureItem);
popup.add(exitItem);
trayIcon.setPopupMenu(popup);
SystemTray.getSystemTray().add(trayIcon);
captureItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
File outputFile = new File("capture.png");
ImageIO.write(new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())),
"png",
outputFile);
JOptionPane.showMessageDialog(null, "Screenshot saved to: " + outputFile.getAbsolutePath());
}
catch (AWTException | IOException ex) {
ex.printStackTrace();
}
}
});
exitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SystemTray.getSystemTray().remove(trayIcon);
System.exit(0);
}
});
}
}
这是捕获结果。
如您所见,PopupMenu 已关闭,但“Capture”MenuItem 在 Robot 进行捕获时仍然可见,并且是捕获图像的一部分。
有没有办法强制重新绘制以隐藏 MenuItem 或在它隐藏时收到通知,以便我可以确保机器人不会拾取它?我宁愿避免任意 Thread.sleep() 因为它只是一个盲目的竞争条件...
韩国,维克纳
这不是您的 Java 应用程序的产物,因为它是所选菜单项的 Windows 特定动画,在弹出菜单已关闭时继续播放。
据我所知,没有办法从 Java 端监控动画进度(除了捕获屏幕并查看工件是否仍然存在)。
最好的选择是在执行屏幕截图之前有一个可配置的延迟(合理的默认值,例如 300 毫秒)。我所知道的所有屏幕截图工具都使用可配置的延迟。
我希望我的程序从系统托盘菜单执行屏幕捕获。
我让它工作了,但 MenuItem 本身隐藏得不够快,并且与屏幕的其余部分一起被捕获。
这是一个 MCVE,基于 Java 教程的 TrayIconDemo 示例的精简版: (编辑:由于 Holger 的评论而变得更小)
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TrayCapture {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGUI();
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
private static void createAndShowGUI() throws Exception {
//Check the SystemTray support
if (!SystemTray.isSupported()) {
System.err.println("SystemTray is not supported");
return;
}
final PopupMenu popup = new PopupMenu();
final TrayIcon trayIcon = new TrayIcon(ImageIO.read(new URL("https://i.stack.imgur.com/wCF8S.png")));
trayIcon.setImageAutoSize(true);
// Create a popup menu components
MenuItem captureItem = new MenuItem("Capture");
MenuItem exitItem = new MenuItem("Exit");
//Add components to popup menu
popup.add(captureItem);
popup.add(exitItem);
trayIcon.setPopupMenu(popup);
SystemTray.getSystemTray().add(trayIcon);
captureItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
File outputFile = new File("capture.png");
ImageIO.write(new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())),
"png",
outputFile);
JOptionPane.showMessageDialog(null, "Screenshot saved to: " + outputFile.getAbsolutePath());
}
catch (AWTException | IOException ex) {
ex.printStackTrace();
}
}
});
exitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SystemTray.getSystemTray().remove(trayIcon);
System.exit(0);
}
});
}
}
这是捕获结果。
如您所见,PopupMenu 已关闭,但“Capture”MenuItem 在 Robot 进行捕获时仍然可见,并且是捕获图像的一部分。
有没有办法强制重新绘制以隐藏 MenuItem 或在它隐藏时收到通知,以便我可以确保机器人不会拾取它?我宁愿避免任意 Thread.sleep() 因为它只是一个盲目的竞争条件...
韩国,维克纳
这不是您的 Java 应用程序的产物,因为它是所选菜单项的 Windows 特定动画,在弹出菜单已关闭时继续播放。
据我所知,没有办法从 Java 端监控动画进度(除了捕获屏幕并查看工件是否仍然存在)。
最好的选择是在执行屏幕截图之前有一个可配置的延迟(合理的默认值,例如 300 毫秒)。我所知道的所有屏幕截图工具都使用可配置的延迟。