2014-01-25 54 views
9

使用AWT,我想通過在窗口隱藏時停止繪製到屏幕來節省資源,如閃存。但首先,我需要一種方法來檢測Frame是否完全被一個或多個其他窗口覆蓋。 Windows可能不是來自同一個應用程序,所以我不能總結他們的形狀。是否有可能檢測窗口遮擋

所以問題是,是否有可能檢測窗口是否被其他應用程序的其他窗口覆蓋?

+0

Java的2D應該做的自動。 –

+0

我的測試表明,如果窗口被覆蓋或不覆蓋,渲染速度/成本不受影響。 – warren

+1

你到底有多渲染? [MCVE](http://stackoverflow.com/help/mcve)可能對此有所幫助。 –

回答

2

一切都是可能只是你需要一些創造力和辛勤工作:)

我希望你知道,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; 
      } 
     } 
    } 
} 
+0

具有創造性,但對我而言並不理想,因爲我需要至少支持Windows,Linux和OS X.我相信在這些平臺上可以完成相同的任務,但是我發現很難激勵爲多個平臺維護此功能。 – Dolda2000

+1

我相信你有兩個挑戰:構建可以在所有系統上工作的應用程序,並且Java是不錯的選擇,你也可以使用在JVM上運行的其他語言,第二個應用程序應該與所有這些操作系統平臺交互,而這真是太糟糕了。 –

相關問題