pywinauto(Win32)需手动点击才识别Edit控件,如何强制加载隐藏控件?
问题描述
使用pywinauto的Win32后端对遗留Win32应用进行自动化操作时,遇到以下问题:
- 导出控件树时,可见面板中明确存在名为
Edit62的Edit控件,但直接访问时会抛出ElementNotFoundError - 仅当手动点击或通过TAB切换到其父控件后,
panel.Edit62才能被pywinauto识别
复现代码
from pywinauto import Application # 连接到运行中的应用 app = Application(backend="win32").connect(title_re="Domínio Folha.*") main_win = app.window(title_re="Domínio Folha.*") # 定位“Cadastro de Empregados”面板 panel = main_win.child_window( title="Cadastro de Empregados", class_name="FNWND3190" ) # 打印深度为3的控件标识符 panel.print_control_identifiers(depth=3)
控件树输出片段
| pbdw190 - '' (L491, T266, R1449, B344) | ['|<pbdw19035', 'pbdw19036'] | child_window(class_name="pbdw190") | | | | Edit - '' (L491, T266, R491, B266) | | ['Edit62'] | | child_window(class_name="Edit") | | | | Edit - '' (L491, T266, R491, B266) | | ['Edit63'] | | child_window(class_name="Edit") | | | | PBEDIT190 - '928' (L401, T249, R491, B267) | | ['928', '928PBEDIT190', 'PBEDIT190139'] | | child_window(title="928", class_name="PBEDIT190")
报错代码
# 执行此代码会抛出ElementNotFoundError panel.Edit62.wait('exists ready', timeout=5)
已尝试无效的方法
- 调用
panel.set_focus()或Win32的SetForegroundWindow - 增加超时时间
- 调用
wrapper.invalidate_cache()
解决方案
针对这类动态加载的Win32控件,可通过以下几种方式强制触发控件初始化,无需手动交互:
1. 发送Win32消息触发控件激活与重绘
给Edit62的直接父控件(pbdw190)发送激活和重绘消息,强制其加载子控件:
from pywinauto import Application app = Application(backend="win32").connect(title_re="Domínio Folha.*") main_win = app.window(title_re="Domínio Folha.*") panel = main_win.child_window(title="Cadastro de Empregados", class_name="FNWND3190") # 获取父控件pbdw190 pbdw_ctrl = panel.child_window(class_name="pbdw190") # 发送WM_ACTIVATE消息激活控件(WA_ACTIVE = 1) pbdw_ctrl.send_message(0x0006, 1, 0) # 发送WM_PAINT消息触发重绘 pbdw_ctrl.send_message(0x000F) # 刷新控件缓存 panel.invalidate_cache() # 现在可正常访问Edit62 panel.Edit62.wait('exists ready', timeout=5)
2. 模拟鼠标点击父控件区域
通过模拟点击父控件的交互区域,触发控件的初始化逻辑:
import time from pywinauto import Application app = Application(backend="win32").connect(title_re="Domínio Folha.*") main_win = app.window(title_re="Domínio Folha.*") panel = main_win.child_window(title="Cadastro de Empregados", class_name="FNWND3190") pbdw_ctrl = panel.child_window(class_name="pbdw190") # 模拟点击父控件的中心位置 pbdw_ctrl.click_input() # 等待控件加载完成(按需调整时长) time.sleep(0.5) panel.invalidate_cache() panel.Edit62.wait('exists ready', timeout=5)
3. 直接枚举子控件绕过缓存机制
不依赖pywinauto的控件标识符缓存,直接枚举父控件下的所有子控件,定位目标Edit控件:
from pywinauto import Application app = Application(backend="win32").connect(title_re="Domínio Folha.*") main_win = app.window(title_re="Domínio Folha.*") panel = main_win.child_window(title="Cadastro de Empregados", class_name="FNWND3190") pbdw_ctrl = panel.child_window(class_name="pbdw190") # 枚举父控件下所有Edit类控件 edit_controls = pbdw_ctrl.find_elements(class_name="Edit") # 根据控件树输出,Edit62是第一个Edit控件 edit62 = edit_controls[0] # 直接操作控件,例如设置文本 edit62.set_text("测试内容")
4. 调用Win32 API强制刷新控件
使用win32api直接强制父控件重绘并更新:
import win32api import win32gui from pywinauto import Application, win32structures app = Application(backend="win32").connect(title_re="Domínio Folha.*") main_win = app.window(title_re="Domínio Folha.*") panel = main_win.child_window(title="Cadastro de Empregados", class_name="FNWND3190") pbdw_handle = panel.child_window(class_name="pbdw190").handle # 获取控件矩形区域 rect = win32structures.RECT() win32gui.GetWindowRect(pbdw_handle, rect) # 强制无效化控件区域并更新 win32gui.InvalidateRect(pbdw_handle, None, True) win32gui.UpdateWindow(pbdw_handle) panel.invalidate_cache() panel.Edit62.wait('exists ready', timeout=5)
内容的提问来源于stack exchange,提问作者Joo Victor de Morais Godoi San
相关产品推荐
相关产品推荐

