【问题标题】:Is it possible to detect window occlusion是否可以检测窗口遮挡
【发布时间】:2014-01-25 07:43:42
【问题描述】:

使用 AWT,我想像 flash 一样通过在窗口隐藏时停止对屏幕的绘制来节省资源。但首先,我需要一种方法来检测框架是否完全被一个或多个其他窗口覆盖。可能不是来自同一个应用程序的 Windows,所以我不能只总结它们的形状。

那么问题来了,是否有可能检测到窗口是否被其他应用程序的其他窗口覆盖?

【问题讨论】:

  • Java-2D 应该自动完成。
  • 我的测试表明,渲染速度/成本不受窗口是否被覆盖的影响。
  • 您的渲染效果如何? MCVE 在这里可能会有所帮助。
  • 目前,我通过渲染到缓冲图像或易失性图像来绘制到屏幕,这取决于我是否需要低级像素操作,然后将图像绘制到窗口。我通过将分辨率设置为最大值并在以 10.7hz 播放动画时查看计算机的 CPU 使用情况进行监控。
  • Java-2D 只会保存绘制最终图像的一部分!这(你会发现)几乎不需要时间,也不是瓶颈。

标签: java window drawing awt java-2d


【解决方案1】:

一切都是可能的,只是你需要一些创造力和努力:)

我希望您知道 Java 可以调用本机 Windows API(这不会是非常性能的虎钳,但我们只有这种方式),为此我们可以使用 JNA lib 这将使我们能够访问本机共享库.

我已经做了一些快速概念检查,此代码仅检查活动窗口是否完全覆盖 Java 应用程序窗口,但您也可以遍历可见窗口并计算面积,JNA 也提供该访问权限。

对于我的演示项目,我使用了这些 JNA 依赖项:

compile("net.java.dev.jna", "jna", "4.5.0")
compile("net.java.dev.jna", "jna-platform", "4.5.0")

我的主要课程:

package com.sauliuxx.inc;

import com.sauliuxx.inc.workers.ActiveWindowChecker;
import com.sun.jna.platform.win32.WinDef;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * The type App.
 */
public class App extends Frame implements ActionListener {

    private final String title = "Demo123";
    private Label sizeLabel;
    private Label positionLabel;
    private Label visibleLabel;

    BlockingQueue<WinDef.RECT> q =
            new LinkedBlockingQueue<>();

    private App() {
        this.setTitle(title);
        this.setLayout(new BorderLayout());
        this.setSize(500, 500);
        Panel infoPanel = new Panel();
        sizeLabel = new Label(this.getSize().height + " X " + this.getSize().width);
        infoPanel.add(sizeLabel);
        positionLabel = new Label("X: " + this.getLocation().getX() + " Y: " + this.getLocation().getY());
        infoPanel.add(positionLabel);
        visibleLabel = new Label(this.isVisible() ? "true" : "false");
        infoPanel.add(visibleLabel);
        this.add(infoPanel, BorderLayout.PAGE_END);

        Timer timer = new Timer(250, this);
        timer.start();

        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        this.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent componentEvent) {
                sizeLabel.setText(componentEvent.getComponent().getSize().height + " X " + componentEvent.getComponent().getSize().width);
            }

            @Override
            public void componentMoved(ComponentEvent componentEvent) {
                positionLabel.setText("X: " + componentEvent.getComponent().getLocation().getX() + " Y: " + componentEvent.getComponent().getLocation().getY());
            }

            @Override
            public void componentShown(ComponentEvent componentEvent) {
                visibleLabel.setText("true");
            }

            @Override
            public void componentHidden(ComponentEvent componentEvent) {
                visibleLabel.setText("false");
            }
        });

        ActiveWindowChecker awcDeamon = new ActiveWindowChecker(q);
        awcDeamon.setDaemon(true);
        awcDeamon.start();

    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {

        WinDef.RECT rect = null;

        try {
            rect = q.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (this.isActive()) {
            System.out.println("action");
        } else {
            //System.out.println("rect = " + (rect != null ? rect : ""));
            //System.out.println("frame = [(" + (int)this.getLocation().getX() + "," + (int)this.getLocation().getY() + ") (" + this.getSize().width + "," + this.getSize().height + ")]");

            // x and y windows to compare top left point
            int rxTop = rect == null ? 0: rect.left;
            int ryTop = rect == null ? 0:rect.top;
            int fxTop = (int) this.getLocation().getX();
            int fyTop = (int) this.getLocation().getY();

            // bottom right points
            int rxBottom = rect == null ? 0: rect.right;
            int ryBottom = rect == null ? 0: rect.bottom;
            int fxBottom = fxTop + this.getSize().width;
            int fyBottom = fyTop + this.getSize().height;

            if ((rxTop >= fxTop || ryTop >= fyTop) || (rxBottom <= fxBottom || ryBottom <= fyBottom))
            {
                System.out.println("Not covered by active window.");
            }
            else{
                System.out.println("Covered by active window.");
            }
        }
    }

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     */
    public static void main(String... args) {

        if (!System.getProperty("os.name").contains("Windows")) {
            System.err.println("ERROR: Only implemented on Windows");
            System.exit(1);
        }

        java.awt.EventQueue.invokeLater(() -> new App().setVisible(true));
    }
}

我的工人阶级:

package com.sauliuxx.inc.workers;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;

import java.util.concurrent.BlockingQueue;

/**
 * The type Active window checker.
 */
public class ActiveWindowChecker extends Thread {

    private static final int MAX_TITLE_LENGTH = 1024;

    private final BlockingQueue<WinDef.RECT> queue;

    /**
     * Instantiates a new Active window checker.
     *
     * @param q the q
     */
    public ActiveWindowChecker(BlockingQueue<WinDef.RECT> q) {
        this.queue = q;
    }

    @Override
    public void run() {
        Exception ex = null;
        while (ex == null) {
            char[] buffer = new char[MAX_TITLE_LENGTH * 2];
            WinDef.HWND hwnd = User32.INSTANCE.GetForegroundWindow();
            User32.INSTANCE.GetWindowText(hwnd, buffer, MAX_TITLE_LENGTH);
            System.out.println("Active window title: " + Native.toString(buffer));
            WinDef.RECT rect = new WinDef.RECT();
            User32.INSTANCE.GetWindowRect(hwnd, rect);
            try {
                queue.put(rect);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                ex = e;
            }
        }
    }
}

【讨论】:

  • 很有创意,但不太适合我的目的,因为我至少需要支持 Windows、Linux 和 OS X。我相信在这些平台上也可以做到这一点,但我觉得很难激励为多个平台维护它。
  • 我相信你有两个挑战:构建可以在所有系统上运行的应用程序,Java 是不错的选择,你也可以使用在 JVM 上运行的其他语言,第二个应用程序应该与所有这些操作系统平台交互,这是地狱。
猜你喜欢
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-14
相关资源
最近更新 更多