【问题标题】:Java search for on-screen text fieldJava 搜索屏幕上的文本字段
【发布时间】:2012-07-31 01:55:57
【问题描述】:

我正在尝试创建一个程序,该程序会自动搜索屏幕上的文本字段并在该文本字段中重复键入一个单词。有没有可以找到文本字段的类?或者有什么方法可以找到文本字段?因为我知道 Robot 类可以输入文本,所以我只需要将光标移到文本字段上并使用 mousePress() 和 mouseRelease() 方法。

谢谢

【问题讨论】:

  • 文本字段的位置。它是在网页上还是在某种基于 Java Swing 的 GUI 上。
  • 文本字段在网页上或操作系统上,文本字段是您可以在屏幕上输入的任何可能的地方
  • 如果它是一个可以使用 selenium 的网页,它确实是一个测试框架,但它可以用于此目的。如果这是一个选项,您可以跳过文本字段并将所有内容放在一起,如果这是您的目标,则直接向服务器发出请求。
  • 如果文本字段在 Java 程序中,那么abbot.sf.net 将帮助您。

标签: java awt awtrobot


【解决方案1】:

我不能直接给你一个解决方案,但我弄乱了一些代码,也许可以为你指出正确的方向。

您可能知道,Java 在 JVM 中运行。这允许它在任何操作环境中执行。每个操作环境(windows、mac 等)都有自己的系统来处理编辑框和将焦点设置到正确的窗口等等。以下示例代码仅适用于 Windows,不符合 Java 语言的精神。正如 Adriaan 所指出的,这种事情还有其他语言,但是(在一定程度上)单独使用 Java 是可能的。

在 Windows 中,您必须了解所有活动窗口的管理方式以及您看到的所有内容(包括编辑框)都将 Windows 操作系统视为“窗口”。我并不真正了解事情在幕后是如何运作的,所以我无法提供比这更多的信息。在 C++ 等本地语言中,Windows 操作系统 API 提供了一些函数,可用于实现您的目标。即EnumWindows()EnumChildWindows()GetClassName()SetForegroundWindow()。您可以通过搜索 MSDN 文档库找到有关如何在本地语言中使用这些函数的文档。

话虽如此,您需要能够从 Java 调用这些函数。在正常情况下,调用这些本地方法是不可能的。但是,有一个库可以帮助您:JNA 库。 JNA 代表 Java Native Access,让您可以使用我之前提到的闪亮的新功能。

因此,为了以母语实现您的目标,通常首先调用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 提供的舒适区,很抱歉,但在如此广泛的范围内,真的没有其他方法可以实现您的目标。

我希望我至少向您展示了实现目标所需的条件,并为您指明了正确的方向。当谈到原生 Windows API 时,我不是上帝,所以我可能在某些地方错了,但是代码确实有效。祝你好运:)

【讨论】:

  • 您对舒适区的看法是对的,我对您上面描述的 Windows 操作系统本机代码类型非常陌生;)我会试一试,应该很有趣,至少我了解您查找编辑框的方法。谢谢你。但是,阅读您的代码,从哪里可以获得 com.sun.jna 包以及代码示例中显示的其余类?
  • @BlH 我认为 JNA 不久前更新并弃用了“示例”包,所以这里是我使用的文件:dl.dropbox.com/u/13849688/jna.zip 只需将它们添加到您的类路径中,示例应该可以工作。
【解决方案2】:

我的朋友,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);

如果您想以任何方式阅读文本或将文本写入浏览器上的文本字段,我建议您使用 selenium。

【讨论】:

    【解决方案3】:

    对于这类问题,AutoIt 比 Java 更简单、更通用。

    【讨论】:

    • 有什么JAVA方式可以做到吗?
    • 当然。您可以使用其中一个 Selenium 驱动程序来自动执行此操作,请参阅 seleniumhq.org/docs/03_webdriver.html
    • @AdriaanKoster 假设作者正在尝试在网络浏览器中编辑屏幕上的文本字段...
    • 我看不出 Selenium 与 Java 文本区域中的自动输入有何关联...
    • 假设您想通过浏览器进行交互,您可以使用任何一种 Selenium 驱动程序,例如:code.google.com/p/selenium/wiki/HtmlUnitDriver
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 2018-10-23
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多