Text识别技术
对于一些较旧的技术开发的Windows应用程序,CukeTest对控件对象识别的支持可能有限。但通过GuiText插件,CukeTest增强了对使用Windows GDI绘图机制在屏幕上显示文本的控件的识别能力。
如果控件中的特定文本位置无法被识别为控件,那么可以通过使用文字对象(GuiText)和文字表格对象(TextTable)来解决这个问题。
文字对象(GuiText)
文字对象(GuiText)允许您将界面上的文本视为可操作的对象,便于实现对特定文本的精确控制和操作。其实现原理是从图形渲染的底层机制入手,通过定位文本位置,在已有的控件树上实现更精确的定位。
添加文字对象
与其他测试对象一样,文字对象也需要在模型管理器中进行侦测、识别和管理。打开模型文件或模型管理器后,点击“添加文字对象”(位于“添加Windows对象”按钮的下拉列表中)来侦测和添加文字对象。
编辑属性
文字对象目前只有一个标识属性——text
。该属性支持使用正则表达式进行匹配,详情请参考修改匹配模式。
编辑父节点
在编辑文字对象的父节点时需谨慎,因为文字对象对其直接容器控件有特定要求。如果删除文字对象最近的容器控件(如Pane、Window、Tree、Menu等),可能会导致文字对象无法被正确识别。
文字对象的API
类型定义
export interface IGuiTextControl {
click(x?: number, y?: number, mousekey?: number): Promise<void>;
dblClick(x?: number, y?: number, mousekey?: number): Promise<void>;
exists(seconds?: number): Promise<boolean>;
highlight(duration?: number);
moveMouse(x?: number, y?: number, seconds?: number): Promise<void>;
rect(): Promise<Rect>;
text(): Promise<string>;
takeScreenshot(filePath?: string): Promise<string>;
modelImage(options?: {encoding: 'buffer' | 'base64'}): Promise<string | Buffer>; //base64 is the default
modelProperties(all?: boolean): {[x: string]: any};
}
class GuiTextControl(ControlBase):
def click(x: Optional[int]=None, y: Optional[int]=None, mousekey: Optional[int]=None) -> None
def dblClick(x: Optional[int]=None, y: Optional[int]=None, mousekey: Optional[int]=None) -> None
def exists(seconds: Optional[int]=None) -> bool
def highlight(duration: Optional[int]=None) -> None
def moveMouse(x: Optional[int]=None, y: Optional[int]=None, seconds: Optional[int]=None) -> None
def rect() -> Rect
def text() -> str
def takeScreenshot(filePath: Optional[str]=None) -> str
def modelImage(encoding: Optional[str]=None) -> Union[str, bytearray]
def modelProperties(all: Optional[bool]=None) -> TypedDict
操作方法
- click(x, y, mousekey)
- dblClick(x, y, mousekey)
- takeScreenshot(filePath)
- moveMouse(x, y)
- highlight(miliseconds?: number)
- modelProperties()
- modelImage(options?: {encoding: 'buffer' | 'base64'})
- exists(time)
属性方法
需要注意的控件的属性方法都是异步的,在调用后CukeTest会与目标控件通信,获取控件当前的属性,即实时属性,而不是模型对象中的识别属性。下面列出的属性所有控件都支持,但不一定都有值,可以根据建议尝试类似的属性方法来获取目标属性。
文字表格对象(TextTable)
当您需要操作位于同一控件下的多个文本对象时,文字表格对象(TextTable)提供了一种高效的解决方案。如果在目标Windows控件下识别到多个同级的文字对象,CukeTest会在识别结果中提供一个特殊的节点——文字表格对象(TextTable)。通过将这个对象添加到控件树中,您可以像操作表格一样使用它,实现对多个文本对象的集中管理和操作。
添加文字表格对象
在模型管理器中识别到多个同级文字对象时,CukeTest会自动提供添加文字表格对象的选项。选择“添加文字表格对象”后,CukeTest将这些同级文字对象组织成一个表格结构,便于您后续的测试操作。
通过这种方式,您可以避免单独操作每个文本对象,而是通过行列的方式直接访问所需的内容。例如:
- 点击特定单元格。
- 获取单元格的文本内容。
- 验证单元格文本的正确性。
- 在表格中搜索和比较数据。
表头设置
在处理表格数据时,表格的第一行有时用于显示列标题(表头),而非实际的数据内容。为了让 CukeTest 正确识别表格结构,您可以使用 header
属性进行配置:
header: false
(默认行为):第一行会被视为普通的数据行。这意味着所有行都被当作数据来处理,索引从第一行开始计算。header: true
(启用表头):将表格的第一行识别为表头(列标题),实际的数据从第二行开始。这种设置下:data()
方法:仅返回数据行,不包含表头行。这使得您可以直接对实际数据进行操作,而无需手动跳过表头。- 操作方法(如
clickCell()
、cellValue()
和rowData()
):这些方法在使用行索引时,会以数据的第一行作为索引的起点,表头行不会被包含在索引计算中。例如,如果表头存在,数据的第一行对应索引0
,表头不占用任何索引位置。
裁剪识别区域
在使用 TextTable 时,您可能只需要处理表格中的某些部分数据。裁剪识别区域 功能可以帮助您通过设置 clip
属性,精准指定需要识别的表格范围,从而专注于关心的部分。
如何使用 clip
属性
您可以为 clip
属性传入一个对象,并根据需要设置以下参数之一或多个,以控制识别区域的边界:
left
:目标识别区域左边距表格左侧的像素数。top
:目标识别区域顶部距离表格顶部的像素数。right
:目标识别区域右边距表格左侧的像素数。bottom
:目标识别区域底部距离表格顶部的像素数。
注意:裁剪区域是从表格的左上角(原点)开始计算的。
left
和top
定义了裁剪区域的左上角起点,right
和bottom
定义了右下角的边界。裁剪得到的区域取决于应用内文本实际宽度,可能会因文本内容变化而导致裁剪区域的变化。因此,在实际操作时,您可能需要根据实际情况调整裁剪区域的大小,以确保能够完全识别需要的内容。
通过同时设置这些参数,您可以定义一个矩形区域,仅识别该区域内的内容。
示例说明
裁剪右下角的内容
{ left: 147, top: 98 }
解释:该设置表示识别区域的左边距表格左侧 147 像素,顶部距表格顶部 98 像素。这样只会保留右下角的部分,忽略其他区域。
裁剪左侧内容
{ right: 147 }
解释:该设置表示识别区域的右边距表格左侧 147 像素。这样只会保留左侧部分,忽略右侧内容。
定义一个矩形区域
{ left: 100, top: 70, right: 200, bottom: 140 }
解释:该设置定义了一个矩形识别区域:
- 左边距表格左侧 100 像素
- 顶部距表格顶部 70 像素
- 右边距表格左侧 200 像素
底部距表格顶部 140 像素
这样,只有位于该矩形区域内的内容会被识别。
编辑父节点
在编辑文字表格对象的父节点时需谨慎,因为文字表格对象对其直接容器控件有特定要求。如果删除文字表格对象最近的容器控件(如Pane、Window、Tree、Menu等),可能会导致对象无法被正确识别。
使用示例
假设您正在测试一个包含多个联系人信息的应用,每个联系人的信息(如姓名、电话、邮箱等)以列表形式显示。通过添加文字表格对象,您可以轻松地验证列表中每一行的联系人信息,或者查找特定联系人的信息。
(async function() {
let textTable = await model.getTextTable("ContactsList");
let contactInfo = await textTable.getCellText(1, 2); // 获取第1行第2列(假设为电话号码)的文本
console.log(`联系人电话: ${contactInfo}`);
// 执行其他文本验证或操作...
})();
文字表格对象的API
类型定义
export interface ITextTable extends ITextGuiText {
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 TextTableControl(ControlBase):
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', '小红', '女']
]