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 毫秒)。我所知道的所有屏幕截图工具都使用可配置的延迟。