创建虚拟控件
虚拟控件是对界面中某一特定区域进行逻辑定义,使其在自动化测试中可以像普通控件一样进行操作。通过定义虚拟控件,您可以:
- 精确点击:将界面中的任意图形元素定义成可点击区域。
- OCR文字识别:对界面区域进行文字识别,获取其中的文本内容,或在其中基于文本进行点击操作。
- 图像操作:截取虚拟控件对应的区域进行截图、图像对比。
- 更好的维护性:对于自定义绘制的按钮或特殊界面元素(无法被传统对象识别方法找到的控件),可以使用虚拟控件替代坐标点击,从而提高代码的可读性与适应性。当窗体大小可调整时,虚拟控件也能通过设置“对齐方式”自动适应宽高变化,避免坐标偏移问题。
简言之,虚拟控件通过将界面中的特定区域“封装”成可直接操作的对象,让您的自动化测试更灵活、更可靠、更易维护。
如何定义虚拟控件
在模型管理器中定义虚拟控件主要有两种途径:
直接在截屏上创建虚拟控件
在模型管理器中选中某个已识别的控件后,进入控件截屏页的工具栏中选择“创建虚拟控件”,然后在控件截屏区域中拖拽鼠标,即可绘制出一个虚拟控件区域。通过虚拟控件高级编辑器批量创建和调整
点击“编辑虚拟控件”选项,打开虚拟控件编辑窗口。在这里可以一次性添加、修改多个虚拟控件,并为每个虚拟控件设置名称、对齐方式等属性,批量完成更复杂的编辑需求。
示例场景
下图展示了一个名为 appchooser 的 Qt 应用中的图标界面。当用户点击某个图标时,该图标会放大并居中显示。为了实现该界面的自动化操作,我们可以按照以下步骤进行配置:
- 识别窗体控件:首先识别整个窗体控件(例如此窗体为
Custom
类型)。 编辑虚拟控件:在模型管理器中右击已识别出的窗体对象,选择“编辑虚拟控件”,打开虚拟控件对话框。
在虚拟控件对话框中,执行以下操作:
添加虚拟控件
添加四个虚拟控件,分别命名为Camera
、Glass
、Ball
和Book
。定义控件区域
使用鼠标在图像中框选对应图标的区域,确定每个虚拟控件的定位区域。设置对齐方式
为每个虚拟控件设置对齐方式。例如,将Book
控件设置为右下对齐,这样即使窗体大小发生变化,该控件仍能准确定位到右下角的“Book”图标区域。
完成上述设置后,点击“确定”按钮保存虚拟控件配置。返回模型管理器时,可以看到新增的虚拟控件已归属于父控件,并在对象结构中显示。
通过这种方式,我们可以在脚本中直接调用这些虚拟控件,无需重复计算坐标或处理复杂的自定义控件识别。以下是示例代码:
await model.getVirtual("Camera").click();
model.getVirtual("Camera").click()
这样,当脚本执行到上述代码时,系统会自动识别并点击对应的虚拟控件,无需手动干预,简化了自动化操作流程。
虚拟控件的多种使用方式
定义完成虚拟控件后,在编写测试脚本时有多种方式来获取和使用它们。
从模型中直接获取
在模型中定义好虚拟控件后,可通过model.getVirtual("虚拟控件名称")
的方式获取,然后直接调用其方法完成点击、OCR识别、截图等操作。
详情参考虚拟控件API。通过描述模式创建
无需在模型中提前定义,也可以在代码中使用描述式编程的方式,通过指定区域或特征临时创建虚拟控件。
详情请参考描述模式。不带参数的 getVirtual() 用法
调用getVirtual()
而不传入名称时,会返回一个与父对象控件区域相同大小的虚拟控件对象。这通常用于对整个控件进行图像识别或OCR操作。例如,在Win10计算器中获得数字面板的虚拟控件,然后基于OCR来点击数字:
let numPad = model.getGeneric("Number pad").getVirtual();
await numPad.clickVisualText('4');
numPad = model.getGeneric("Number pad").getVirtual()
numPad.clickVisualText('4')
在这里,“Number pad”是计算器的数字面板控件,通过 getVirtual()
获得与其等大区域的虚拟控件,然后 clickVisualText('4')
会对数字“4”进行OCR识别并点击。
注意:针对不同版本的操作系统或应用,控件名称或呈现方式可能不同,需根据实际情况调整。
更多使用细节与API请参考:虚拟控件API。
虚拟表格对象(virtualTable)
当您需要操作位于同一虚拟控件下的多个文本数据时,虚拟表格对象(virtualTable)提供了一种高效的解决方案。通过虚拟表格对象,您可以像操作表格一样使用它。
添加虚拟表格对象
在模型管理器中创建虚控件之后,找到对象属性标签栏,点击添加属性,添加objectType
属性,属性值选择Table
,点击添加,就添加成功了。
还可以在创建虚拟控件时,绘制虚拟控件完成后选中表格图标再点击打勾图标,完成虚拟表格的创建。
返回控件操作标签栏就能调用virtualTable相关API。
通过这种方式,您可以避免单独操作每个文本对象,而是通过行列的方式直接访问所需的内容。例如:
- 点击特定单元格。
- 获取单元格的文本内容。
- 验证单元格文本的正确性。
- 在表格中搜索和比较数据。
使用示例
假设您正在测试一个包含多个联系人信息的应用,每个联系人的信息(如姓名、电话、邮箱等)以列表形式显示。通过添加文字表格对象,您可以轻松地验证列表中每一行的联系人信息,或者查找特定联系人的信息。
let virtualTable = await model.getVirtual("ContactsList");
let contactInfo = await virtualTable.cellValue(1, 2); // 获取第1行第2列(假设为电话号码)的文本
console.log(`联系人电话: ${contactInfo}`);
// 执行其他文本验证或操作...
virtualTable = model.getVirtual("ContactsList")
contactInfo = virtualTable.cellValue(1, 2) # 获取第1行第2列(假设为电话号码)的文本
print(f"联系人电话: {contactInfo}")
# 执行其他文本验证或操作...
虚拟表格对象的API
类型定义
export interface Virtual {
clickCell(rowIndex: number, columnNameOrIndex: string | number): Promise<void>;
cellValue(rowIndex: number, columnNameOrIndex: string | number): Promise<string>;
columnName(index: number): Promise<string>;
columnHeaders(): Promise<string[]>;
columnCount(): Promise<number>;
data(): Promise<string[][]>;
rowCount(): Promise<number>;
rowData(rowIndex: number): Promise<string[]>;
}
class Virtual(SyncBase):
def clickCell(rowIndex: int, columnNameOrIndex: Union[str, int]) -> None
def cellValue(rowIndex: int, columnNameOrIndex: Union[str, int]) -> str
def columnName(index: int) -> str
def columnHeaders() -> List[str]
def columnCount() -> int
def data() -> List[List[str]]
def rowCount() -> int
def rowData(rowIndex: int) -> List[str]
操作方法
- clickCell(rowIndex: number, columnNameOrIndex: string | number)
- cellValue(rowIndex: number, columnNameOrIndex: string | number)
- columnName(index: number)
- columnHeaders()
- columnCount()
- data()
- rowCount()
- rowData(rowIndex: number)
data(): Promise<string[][]>
获取表格中的所有内容,并以二维数组的形式返回。
- 返回值:
Promise<string[][]>
类型,即二维的字符串数组。
假如表格数据如下:
学号 | 姓名 | 性别 |
---|---|---|
0001 | 小王 | 男 |
0002 | 小明 | 男 |
0003 | 小红 | 女 |
那么data()
方法返回的数组如下:
[
['0001', '小王', '男'],
['0002', '小明', '男'],
['0003', '小红', '女']
]