如何快速判断客户端元素是否可见
评论
收藏

如何快速判断客户端元素是否可见

经验分享
果冻
2024-08-08 09:58·浏览量:1253
果冻
发布于 2024-08-08 09:581253浏览

问题背景

影刀在桌面自动化中缺少判断元素是否可见的指令,使得在桌面自动化中遇到需要滚动的页面判断元素是否已经出现,只能多次测试设置每次滚动的次数,导致开发出的流程不通用。


解决思路

在编码版中我们可以通过调用 Win32Element 对象的 get_bounding() 方法获取win元素的位置信息,get_bounding()方法的说明如下:

get_bounding(self, to96dpi=True, relative_to='screen') -> 'tuple'
获取win32元素相对于屏幕或元素所在窗口左上角的位置
● @param to96dpi, 是否将获取的到元素边框信息转换为96dpi下的值, 默认值为 True 需要转换
● @param relative_to, 获取元素相对于屏幕或所在窗口的位置信息, 默认相对于屏幕
● 'screen' , 相对于屏幕左上角
● 'window' , 相对于元素所在窗口左上角
● @return tuple , 返回win32元素位置信息, 如('x', 'y', 'width', 'height')


在部分场景还会遇到一类问题,需要判断是否可见的元素被上层元素遮挡,此时调用get_bounding() 会返回元素坐标,但是元素被遮挡无法点击,这种遮挡一般发生在页面的上方和下方。

这里以千牛客户端举例,千牛订单管理页面中,需要点击的元素可能被悬浮的元素遮挡,导致元素无法点击,如下图所示

这里我们将需要判断是否可见的元素叫目标元素,将所有目标元素在UI树中的最短公共祖先元素叫背景元素

获取背景元素左上角和右下角的坐标确定背景元素在桌面上的显示范围,并分别给背景元素设置上下左右四个偏置值,缩小背景元素的判定范围,然后获取目标元素的中心点坐标,如果目标元素的中心点坐标落在判断范范围内就认为目标元素是可见的。

编码实现

使用指令也能实现上面的功能,但是指令获取元素左上角和右下角坐标比较麻烦所以这里我使用编码版实现,代码如下:

from xbot.selector import Selector
from xbot.win32.window import Win32Window
from xbot.win32.window import Win32Element

class WindowElementVisibilityChecker:
    def __init__(self, windows: Win32Window, backgroundElementSelector: Selector,\
                 topBias=0, bottomBias=0, leftBias=0, rightBias=0) -> None:
        self.__windwos = windows
        backgroundElement = self.__windwos.find(backgroundElementSelector)
        bounding = backgroundElement.get_bounding()
        self.__backgroundXMin = bounding[0] + leftBias
        self.__backgroundYMin = bounding[1] + topBias
        self.__backgroundXMax = bounding[0] + bounding[2] - rightBias
        self.__backgroundYMax = bounding[1] + bounding[3] - bottomBias
    
    def is_displayed(self, targetElement: Win32Element) -> bool:
        bounding = targetElement.get_bounding()
        
        # 判断元素是否可见
        if bounding == (0, 0, 0, 0):
            return False
        
        # 判断元素在规定范围内是否可见
        targetElementCenterX = bounding[0] + bounding[2]//2    # 计算目标元素中心点的x坐标
        targetElementCenterY = bounding[1] + bounding[3]//2    # 计算目标元素中心点的y坐标
        if self.__backgroundXMin < targetElementCenterX < self.__backgroundXMax and \
           self.__backgroundYMin < targetElementCenterY < self.__backgroundYMax:
           return True
        else:
            return False

封装成指令

然后我们可以将上面的代码封装成两个简单的自定义指令,获取检查器对象检查元素是否可见,如下图:

运行效果

我们就以千牛判断客服图标是否可见为例子,流程如下:

千牛界面如下:

运行结果如下,千牛一页有15个订单,我们可以看到订单1的客服中心图标被遮挡不可见,只有订单2-4的客服中心图标是可见的。

到这我们就能实现通用的循环点击每个订单客服中心的操作了

收藏4
全部评论1
最新
发布评论
评论