2012-08-02 26 views
1

我正在嘗試創建一個程序,該程序會自動搜索屏幕上的文本字段,並在該文本字段中重複鍵入一個單詞。有沒有可以找到文本字段的類?或者有什麼方法可以找到文本字段?因爲我知道Robot類可以鍵入文本,所以我只需要將光標移到文本字段上並使用mousePress()和mouseRelease()方法。Java搜索屏幕上的文本字段

感謝

+3

位於哪裏的文本字段。它是在一個網頁上還是某種基於Java Swing的GUI。 – 2012-08-02 05:45:26

+0

文本字段在網頁上或類似的操作系統,文本字段是任何可能的地方,你可以在屏幕上鍵入 – 2012-08-02 06:05:25

+0

如果它是一個網頁,你可以使用硒,它是一個真正的測試框架,但它可以是用於此。如果這是一個選項,您可以跳過文本框並將所有內容放在一起,如果這是您的目標,請直接向服務器發送請求。 – 2012-08-02 07:10:33

回答

1

我不能直接給你一個解決方案,但我搞砸了一些代碼,並可能能夠指出你在正確的方向。

正如您所知,Java運行在JVM中。這允許它在任何操作環境中執行。每個操作環境(Windows,Mac等)都有自己的系統來處理編輯框,並將焦點設置到正確的窗口以及什麼。以下示例代碼僅用於Windows,它不符合Java語言的精神。正如阿德里安指出的那樣,這種事情還有其他的語言,但它可能(在某種程度上)只用Java來完成。

在Windows中,您必須瞭解如何管理所有活動窗口,以及您看到的所有內容(包括編輯框)是否都被Windows操作系統視爲「窗口」。我並不真正瞭解事情是如何運作的,所以我不能提供比這更多的信息。在諸如C++之類的本地語言中,Windows OS API提供了一些功能,可用於實現您的目標。即,EnumWindows(),EnumChildWindows(),GetClassName()SetForegroundWindow()。通過搜索MSDN文檔庫,您可以找到有關如何在本地語言中使用這些功能的文檔。

所以說,你需要能夠從Java調用這些函數。在正常情況下,調用這些本地方法是不可能的。但是,有一個圖書館可以幫助你:JNA圖書館。 JNA代表Java本地訪問,並允許您使用前面提到的有趣的新功能。

因此,要用本地語言實現您的目標,通常會先致電EnumWindows()以返回操作系統知道的所有父窗口的列表。此列表將包含父窗口的窗口句柄 - 標題爲「MSN」,「Eclipse」,「Microsoft Office」等的窗口。這些窗口中的每一個作爲父項都具有子項。在這個孩子的名單中,你會發現你正在尋找的「控制」:一個Edit控制。現在,許多應用程序對文本框使用不同的庫和非標準東西 - 比如Pidgin,我測試了一些相關代碼的消息傳遞應用程序,每個控件都有一個名爲「gdkWindowChild」的控件,它並不完全告訴我們哪個控件實際上是一個EditBox或否則就是讓我們輸入文字的地方。這是你想法的主要問題。你不能總是確切地告訴你想要關注的控件,以便輸入文本。無論如何,我們將繼續:

在找到與EnumWindows()相關的父窗口之後,調用EnumChildWindows()將爲我們提供屬於的所有子窗口和其他「控件」(包括潛在的編輯框)父母。 EnumChildWindows()爲它找到的每個子窗口調用一個回調函數,因此很容易通過子窗口列表「搜索」 - 使用GetClassName()來查找控件的名稱 - 可能找到控件的HWND(窗口句柄)你要。

一旦找到編輯框的正確HWND(當然,在你的問題的一般範圍內是困難的部分),簡單的調用SetForegroundWindow(targetHWND)應該把控制權移到前面並設置你的光標在一個準備好型的編輯框中。

這是我寫的一些工作示例代碼,以幫助您入門。此代碼將使用EnumWindows()遍歷所有活動窗口,然後在每個父級上調用EnumChildWindows(),打印出找到的所有控件。請注意,此代碼需要運行JNA庫。

import com.sun.jna.Native; 
import com.sun.jna.Pointer; 
import com.sun.jna.examples.win32.W32API.HWND; 
import com.sun.jna.examples.win32.W32API.LPARAM; 
import com.sun.jna.win32.StdCallLibrary; 
import com.sun.jna.win32.W32APIOptions; 


public class IterateChildWindows { 
    public interface User32 extends StdCallLibrary { 
     User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS); 

     HWND FindWindow(String lpClassName, String lpWindowName); 
     int GetWindowRect(HWND handle, int[] rect); 
     int SendMessage(HWND hWnd, int msg, int wParam, byte[] lParam); 
     HWND FindWindowEx(HWND parent, HWND child, String className, String window); 

     boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg); 
     boolean EnumChildWindows(HWND parent, WNDENUMPROC callback, LPARAM info); 

     interface WNDENUMPROC extends StdCallCallback { 
      boolean callback(HWND hWnd, Pointer arg); 
     } 

     int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount); 
     long GetWindowLong(HWND hWnd, int index); 
     boolean SetForegroundWindow(HWND in); 
     int GetClassNameA(HWND in, byte[] lpString, int size); 
    } 

    public static void main(String[] args) {   
     User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() { 
      public boolean callback(HWND hWnd, Pointer userData) { // this will be called for each parent window found by EnumWindows(). the hWnd parameter is the HWND of the window that was found. 
       byte[] textBuffer = new byte[512]; 
       User32.INSTANCE.GetWindowTextA(hWnd, textBuffer, 512); 
       String wText = Native.toString(textBuffer); 
       System.out.println("Window found: " + wText); 

       // now call EnumChildWindows() giving the previously found parent window as the first parameter 
       User32.INSTANCE.EnumChildWindows(hWnd, new User32.WNDENUMPROC() { 
        public boolean callback(HWND hWnd, Pointer userData) { // this is called for each child window that EnumChildWindows() finds - just like before with EnumWindows(). 
         byte[] textBuffer = new byte[512]; 
         User32.INSTANCE.GetClassNameA(hWnd, textBuffer, 512); 
         System.out.println(" - Found sub window/control class: " + new String(textBuffer).trim()); 
         return true; 
        } 
       }, null); 
       return true; 
      } 
     }, null); 
    } 
} 

這裏是由該代碼提供的輸出的摘錄:

Window found: Pidgin 
- Found sub window/control class: gdkWindowChild 
- Found sub window/control class: gdkWindowChild 
- Found sub window/control class: gdkWindowChild 
- Found sub window/control class: gdkWindowChild 
Window found: Malwarebytes Anti-Malware 
- Found sub window/control class: Static 
- Found sub window/control class: Static 
- Found sub window/control class: Button 
- Found sub window/control class: Button 
- Found sub window/control class: Button 

經由PostMessage()SendMessage()直接將消息發送到的控制HWND,例如到的Malwarebytes Button類,將觸發按鈕按下程序本身,與SetForegroundWindow()應該如何將編輯框樣式控件帶到前面讓您能夠輸入相似。有趣的東西玩:)

如果你想直觀地表達我的意思,當我說「家長」和「孩子」和「控制」,你可能會發現這個程序有幫助:Control Viewer。它可以向您顯示每個控件,並在應用程序窗口中突出顯示它,以及更多 - 非常有用的工具。

對不起,如果這篇文章離開了java提供的舒適區,但真的沒有其他方式在這樣的一般範圍內實現您的目標。

我希望我至少能告訴你什麼是實現你的目標所必需的,並指出你在正確的方向。當談到本機窗口API時,我不是上帝,所以我可能在某些地方是錯誤的,但是代碼確實工作。祝你好運:)

+0

你對舒適區的事情是正確的,我對你上面描述的Windows操作系統本地代碼的類型很陌生;)我會給它一個鏡頭,它應該是有趣,至少我瞭解你的方法找到編輯框。謝謝。然而,讀取你的代碼,在哪裏可以獲得com.sun.jna包,以及代碼示例中顯示的其餘類? – 2012-08-02 10:57:23

+0

@BlH我認爲JNA剛剛更新,並棄用了「examples」包,因此以下是我使用的文件:https://dl.dropbox.com/u/13849688/jna.zip只需將它們添加到您的類路徑中這個例子應該工作。 – 2012-08-02 11:09:24

-1

對於這種類型的問題AutoIt更容易,比Java更靈活。

+0

有沒有JAVA的方法來做到這一點?當然是 – 2012-08-02 06:16:31

+0

。您可以使用其中一個Selenium驅動程序來自動執行此操作,請參閱http://seleniumhq.org/docs/03_webdriver.html – 2012-08-02 06:22:05

+1

@AdriaanKoster假設作者正試圖編輯Web瀏覽器中的屏幕文本字段... – 2012-08-02 06:30:34

1

我的朋友,Robot類可以模擬寫文字。

private static void typeOut(String s,Robot bot) 
{ 
try 
{ 
char [] chars = s.toCharArray(); 
for (char c : chars) 
{ 
bot.keyPress((int)c); 
bot.keyRelease((int)c); 
} 
} 
catch (Exception e) 
{ 
System.out.println(e.getMessage()); 
} 
} 

,您可以通過

Robot bot=new Robot();  
typeOut("WWW.GOOGLE.COM", bot); 

,如果你想讀的文本或在瀏覽器上我會建議你使用硒寫文本到文本框的任何方式使用此方法。