1

我正在尝试使用 PyWinAuto 进行一些 Tkinter GUI 测试。我有一个用 Tk 编写的简单应用程序,看起来像这样。 问题是 - 我无法让 PyWinAuto 识别和使用我的应用程序中的按钮/条目。我已经尝试过 >>> app.Prototype.PrintControlIdentifiers() ,但它什么也没返回,或者:

>>> app.Prototype.print_control_identifiers()
Control Identifiers:
TkChild - ''   (L308, T81, R1108, B681)
    '' '0' '1' 'TkChild' 'TkChild0' 'TkChild1'
Button - ''   (L763, T86, R878, B112)
    '2' 'Button' 'Button0' 'Button1'
Button - ''   (L613, T86, R728, B112)
    '3' 'Button2'
Button - ''   (L463, T86, R578, B112)
    '4' 'Button3'
Button - ''   (L313, T86, R428, B112)
    '5' 'Button4'
TkChild - ''   (L613, T171, R737, B198)
    '6' 'TkChild2'
TkChild - ''   (L463, T171, R587, B198)
    '7' 'TkChild3'
TkChild - ''   (L313, T171, R437, B198)
    '8' 'TkChild4'
Static - ''   (L613, T141, R949, B170)
    '9' 'Static' 'Static0' 'Static1'
Static - ''   (L463, T141, R799, B170)
    '10' 'Static2'
Static - ''   (L313, T141, R649, B170)
    '11' 'Static3'

应用程序窗口名称为 Prototype(Tkinter 标题 Prototype-GUI)。我也尝试过设置_namename小部件,如下所示:

param_range = Entry(wrapper, self.basicEntrySett, name="entryrange")

或者:

param_range = Entry(wrapper, self.basicEntrySett, _name="entryrange")

但它所做的只是:

print param_range.winfo_name()
entryrange

并且打印 PrintControlIdentifiers 输出没有改变。我想以人类可读的方式命名它们。

4

1 回答 1

0

我对此有点挣扎,并找到了解决方法。这可能不被视为答案,但对我自动化 Python(基于 Tkinter)应用程序的 GUI 测试有很大帮助。

所以,这是我到目前为止所学到的:

Tk 小部件对象中提供的 name 属性仅供参考,而不是用于 windows 组件的实际名称。

在仔细观察了解行为命名之后。如果应用程序加载为backend="win32",我可以为我的应用程序找到三种类型的元素TkChildButtonStatic

如果应用程序加载为backend="uia",我可以为我的应用程序找到三种类型的元素PaneButtonImage

这里我用过uia,现在不知道要不要用win32。但uia为我工作,因此,我继续前进。

解决方法

我已经创建了我的应用程序中使用的小部件对象的名称列表。现在这个列表的规则是每当添加一个新的小部件时,它就会在索引 0 处添加。现有的小部件被推下列表。例如,如果应用程序有一个带有 tk.Frame 的窗口并且该框架包含一个文本字段和两个按钮,那么我可以通过以下方式访问它pywinauto

pane_list = ["MyTxtInput", "", "MyFrame"]
button_list = ["MySecondButton", "","MyFirstButton"]
      
def update_text(main_window, text_box_name, text):
    index = pane_list.index[text_box_name]
    pane_id = "Pane{}".format(str(index))
    text_box = main_window[pane_id]
    text_box.type_keys(text)
    
def click_button(main_window, button_name):
    index = button_list.index[button_name]
    button_id = "Button{}".format(str(index))
    button = main_window[button_id]
    button.click_input()

# Here is how to use this
def test_my_app()
    app = Application(backend="uia").connect(title="My Application")
    main_window = app.window(title="My Application")
    main_window.dump_tree()
    # Update text in the input
    update_text(main_window, "MyTxtInput", "This is added in the text input")
    # click button
    click_button(main_window, "MyFirstButton")

现在,如果您的应用程序布局是动态的,您是否可以添加另一个带有两个按钮的框架,列表将如下所示。

pane_list = ["NewFrame", "", "MyTxtInput", "MyFrame"]
button_list = ["NewFrame_SecondButton", "", "NewFrame_FirstButton", "MySecondButton", "MyFirstButton"]

在上面的列表中,索引 1 处的元素设置为空白,这是因为,我发现 0 和第一个元素始终相同。

注意:我使用SWAPY工具来理解这种行为。虽然这个工具已经过时并且不再维护,但它帮助我理解了这种行为。

于 2021-11-01T12:13:36.743 回答