Java应用自动化
我们的Java自动化依赖于Java Access Bridge。在进行Java自动化之前,请先在启用Java Access Bridge,启用的方法如下。
启用Java Access Bridge
默认情况下,Java Access Bridge未被启用。通过命令行或Windows控制面板启用它。通过运行使用Accessibility API的Java应用程序对其进行测试。
通过控制面板启用
通过轻松访问中心的控制面板启用Java Access Bridge。
- 单击“开始”,选择“控制面板”,然后选择“轻松访问”,然后选择“轻松访问中心”。或者,按Windows徽标键 + U访问“轻松访问中心”。
- 选择“使用不带显示屏的计算机”。
- 在“安装的其他程序”部分中,选中“启用Java Access Bridge”复选框(您可能需要向下滚动)。
Win10系统的Java Access Bridge设置位于“全部程序”→“Windows 系统”→“控制面板”→“轻松使用”→“轻松使用设置中心”中。 ;
通过命令行启用
通过jabswitch
命令启用Java Access Bridge,首先需要将工作路径切换至jabswitch.exe
可执行文件所处的路径。其中%JRE_HOME%
是您的jre目录,默认安装路径是C:\Program Files\Java\jre\
:
cd %JRE_HOME%\bin\
jabswitch -enable
侦测Java控件
在模型管理器上,从工具栏中选择“侦测Java控件”:
然后,您可以从Java应用程序中选择一个控件。从Java应用程序中单击控件后,将显示侦测对话框,然后可以单击“添加”按钮将其添加到模型中。
您可能会注意到Java对象的图标颜色是橙色,与Windows控件(绿色)不同。
Java模型的引用脚本
由于Java控件的自动化API与普通的Windows控件API实现的方法有所不同,因此加载模型文件的方式也不太一样。这里推荐使用模型管理器代码生成和运行一节中生成模型代码的第二中方式:
模型管理器中,点击右边“控件操作” ,切换到方法面板,点击下图的按钮,自动将全局加载代码方法拷贝到粘贴板。
打开代码编辑器,粘贴代码。
复制生成的代码应为如下样式:
const { JavaModel, JavaAuto } = require("leanpro.java");
var model = JavaModel.loadModel("absDir\\model1.tmodel");
调用Java自动化APIs.
为Java控件生成自动化代码的方式类似于Windows控件。
Java容器API
容器API是用于获取对象的API,如下所示:
interface IJContainer {
parent: IJContainer;
getJWindow(...conditions: ConditionFilter[]): IJWindow;
getJButton(...conditions: ConditionFilter[]): IJButton;
getJCheckBox(...conditions: ConditionFilter[]): IJCheckBox;
getRadioButton(...conditions: ConditionFilter[]): IJRadioButton;
getJEdit(...conditions: ConditionFilter[]): IJEdit;
getJCustom(...conditions: ConditionFilter[]): IJControl;
getJList(...conditions: ConditionFilter[]): IJList;
getJMenu(...conditions: ConditionFilter[]): IJMenu;
getJLabel(...conditions: ConditionFilter[]): IJLabel;
// 可以参考下下节——《动态获取控件的方法:getControls》的介绍
getControls(...conditions:ConditionFilter[]):IJControl[];
}
Java对象成员
默认控件: JControl
所有的Java对象继承于IJControl
类,而IJControl
又继承自上述提到的IJContainer
也就是Java容器类:
interface IJControl extends IJContainer {
click(x?: number, y?: number, mousekey?: number): Promise<void>;
dblClick(x?: number, y?: number, mousekey?: number): Promise<void>;
moveMouse(x?: number, y?: number): Promise<void>;
pressKeys(keys:string):Promise<void>;
takeScreenshot(filePath?:string):Promise<string>;
name():Promise<string>;
}
而每个特定的对象可能都有自己的控制方法和属性,例如:
单选框控件:RatioButton
interface IJRadioButton extends IJControl {
check(): Promise<void>;
// 获取选中状态
checked(): Promise<boolean>
}
复选框控件: JCheckBox
interface IJCheckBox extends IJControl {
checkState(): Promise<boolean>
toggleCheck(checkState: boolean): Promise<void>
}
输入框控件: JEdit
interface IJEdit extends IJControl {
set(value: string): Promise<void>;
value(): Promise<string>;
}
列表控件: JList
interface IJList extends IJControl {
getItem(itemIndex:number):Promise<string>;
itemCount():Promise<itemCount>;
}
菜单控件: JMenu
interface IJMenu extends IJControl {
}
需要特别注意的是上面的这个JMenu
控件,即菜单控件,通常工具栏中展开的菜单都属于JMenu
控件。由于菜单通常需要点击或悬停以后才会弹出,因此在侦测这类控件时我们需要注意两个技巧:
- 按住
Ctrl
键恢复普通点击:在侦测时点击控件会自动的将控件添加到模型管理器中,在识别时按住键盘的Ctrl
键可以恢复成正常的点击,此时点击就可以展开菜单了; - 侦测时稍微等待:在侦测菜单控件的时候,偶尔会发生侦测到的控件不正确的情况,通常发生在鼠标指向的菜单选项会跳转到新界面、关闭窗口等改变应用模型结构的场景下。对此,目前的解决方案是,在侦测菜单控件时,按住左键识别到控件后不要松开,直到侦测器跳出,这样就可以正确的识别到目标菜单控件了。
表格控件: JTable
interface IJTable extends IJControl {
clickCell(rowIndex: number, columnToFind: string | number);
cellValue(rowIndex: number, columnNameOrIndex: number | string): Promise<string>;
data(): Promise<string[][]>;
setCellValue(rowIndex: number, columnToFind: string | number, value: string);
columnCount(): Promise<number>;
columnHeaders(): Promise<string[]>;
rowCount(): Promise<number>;
}
clickCell
方法会执行双击目标单元格的操作,如果该单元格可编辑则会进入编辑状态,此时可以使用pressKeys
方法输入指定的内容(或者直接使用setCellValue
设定目标单元格的内容,如果单元格无法编辑则无效)。
动态获取控件的方法:getControls
提供了一种不依赖模型管理器,直接匹配符合筛选条件的多个控件的方法。getControls
方法的使用方式与Windows自动化中的一致,可以参考Windows中的getControls。getControls
方法接收的参数与其它get[ControlType]
方法类似,比如:
运行时的识别属性
在代码运行时,不仅可以通过对象名称来匹配模型管理器中的操作对象,还可以通过使用识别属性,从应用中动态的匹配满足识别属性的控件。这样的好处是对于一些动态变化、但可预测的控件,添加了识别属性可以增加匹配的精度,不需要预先添加到模型管理器中也可以在自动化脚本中执行操作。下面是几个使用识别属性的示例代码:
await model.getJButton("button1").name(); // 假设button1是按钮控件,并且name属性为“Press Me”
// 下面两行代码能够匹配到与上一行一样的控件
await model.getJButton({name: "Press Me"}); // 只会返回一个符合条件的JButton控件,如果匹配到多个也只返回第一个
await model.getControls({name: "Press Me", type:"JButton"}); // 返回由所有符合条件的控件对象组成的数组
识别属性介绍
搜索指示属性:search
在代码运行时,会根据操作对象的属性从应用中匹配控件。并且由于匹配的方向是从最上层控件向下一层一层匹配控件的,也就是在匹配一个控件时,它的所有父节点控件都会提高匹配精度。而这带来了一个问题,窗口控件通常作为最上层节点,这导致了它的识别精度最低。搜索指示属性search
提供了一种指定匹配方向指示的功能,比如指示匹配方向向上,就可以反过来将某个控件作为起点,向上层匹配该控件所在的窗口(JWindow)、容器(Panel)。
假设此时运行环境中存在多个窗口,如果试图将登录窗口关闭,可以使用如下脚本:
let button = model.getJButton("Login"); // 登录窗口独有的登录按钮
await button.getJWindow("JWindow",{search:"up"}).close(); // 登录按钮所在的窗口即为登录窗口
简单的Java样例代码
以下是调用Java对象的示例:
样例 1:
const { JavaModel } = require('leanpro.win');
const model = JavaModel.loadModel(__dirname + '/java_model.tmodel');
(async function () {
try {
await model.getJEdit("text1").set('some content');
} catch(err) {
console.log('err', err)
}
})();
为了从模型中获取Java控件,您应该从“model”开始调用,该模型将返回根IJContainer
”`对象,后者又可以从模型中获取其他Java对象。
当您在Java对象上调用成员,Java对象无法找到匹配的控件时,它将引发“找不到对象”异常。
如果“ text1”对象可以找到编辑框控件,则它将其内容设置为“some content”。
样例 2:
以下是一个示例片段,它获取复选框的是否选中状态,并切换其状态为选中。
(async function () {
let checkbox = model.getJCheckBox('checkbox-0'); // 假设此时为未选中False
console.log('checked state', await checkbox.checkState());
await checkbox.toggleCheck(true);
let checkbox = model.getJCheckBox('checkbox-0'); // 那么此时为选中True
})();