to iterate the sub menu item using pywinauto

Viewed 1092

I am new to pywinauto and have just started learning. I need to find all the items present in the menubar. I have a code to open the 7-zip application and I am trying to fetch all the menu item present in it.

if (os.path.exists(r"C:/Program Files/7-Zip/7zFM.exe")):
app = Application(backend='uia').start(r"C:/Program Files/7-Zip/7zFM.exe")

win = app.window()

app.top_window().descendants(control_type="MenuBar")
menu = app.top_window().descendants(control_type="MenuBar")[1]

for main_item in menu.children():
    main_item.invoke()
    subitems_level_1 = app.top_window().descendants(control_type="MenuItem")
    print([i.window_text() for i in subitems_level_1])
# iterate expanded items (level 1)
for item in subitems_level_1:
        if item.legacy_properties()[u'DefaultAction'] == u'Open':
            # it has submenu
            item.invoke()
            subitems_level_2 = app.window(control_type="Menu", found_index=0).children()
            print([i.window_text() for i in subitems_level_2])
            time.sleep(3)

It is throwing error :

Traceback (most recent call last):
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\application.py", line 250, in __resolve_control
    ctrl = wait_until_passes(
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\timings.py", line 458, in wait_until_passes
    raise err
pywinauto.timings.TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/40011212/PycharmProjects/winapp/examples/7zip.py", line 33, in <module>
    subitems_level_2 = app.window(control_type="Menu", found_index=0).children()
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\application.py", line 396, in __getattribute__
    ctrls = self.__resolve_control(self.criteria)
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\application.py", line 261, in __resolve_control
    raise e.original_exception
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\timings.py", line 436, in wait_until_passes
    func_val = func(*args, **kwargs)
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\application.py", line 204, in __get_ctrl
    dialog = self.backend.generic_wrapper_class(findwindows.find_element(**criteria[0]))
  File "C:\Users\40011212\PycharmProjects\winapp\venv\lib\site-packages\pywinauto\findwindows.py", line 87, in find_element
    raise ElementNotFoundError(kwargs)
pywinauto.findwindows.ElementNotFoundError: {'control_type': 'Menu', 'found_index': 0, 'backend': 'uia', 'process': 14956}
1 Answers

I have tried writing a recursive function to do this... you can refer below code... This code will work fine for 7z but for other application it may or may not... it depends on how the menu were designed during application development...

import time
import os
from pywinauto.application import Application

def printFormatedString(inString, rightSpacing):
    string_length = len(inString) + rightSpacing
    string_revised = inString.rjust(string_length)
    print(string_revised)

def printMenuItems(menu_item, mainWindow, menuName, spacing):
    # Open the Menu
    menu_item.invoke()
    time.sleep(0.5)
    #Access the menubar via application
    menu = mainWindow.child_window(title="Application", auto_id="MenuBar", control_type="MenuBar")
    # Access current Titled "title" menu item
    curMenu = menu.child_window(title = menuName, control_type = "Menu")

    # iterate over the menu Items
    for menuItem in curMenu.children():
        # Get Menu Name from legacy properties
        menuName = menuItem.legacy_properties().get(u'Name')
        # Print formatted String based upon spacing
        printFormatedString(inString = menuName, rightSpacing = spacing*2)
        # If this is a submenu and recusively call this function
        if menuItem.legacy_properties().get(u'ChildId') == 0:
            # recursive call
            printMenuItems(menu_item = menuItem, mainWindow = mainWindow, menuName = menuName, spacing = spacing*2)
            # press ESC to remove the menu
            mainWindow.type_keys("{ESC}")

def main():
    if (os.path.exists(r"C:/Program Files/7-Zip/7zFM.exe")):
        wpfApp = Application(backend='uia').start(r"C:/Program Files/7-Zip/7zFM.exe")
        # access main Window of applications just started
        wind = wpfApp.windows()
        #Get Application Window Title
        title = wind[0].get_properties()[u'texts'][0]
        print("Started Application {}".format(title))
        # Get Main Window
        mainWindow = wpfApp.window(title = title)
        # Get menu
        menu = mainWindow.child_window(title="Application", auto_id="MenuBar", control_type="MenuBar")
        print("No of Main Menu in App = len(menu.children()) - {}\n".format(len(menu.children())))
        spacing = 3
        #Iterate over all the menu in menubar
        for menu_item in menu.children():
            if menu_item.get_expand_state() == 0:
                #Get Menu Names
                menuName = menu_item.window_text()
                # Print formatted String based upon spacing
                printFormatedString(menuName, spacing)
                # call function
                printMenuItems(menu_item = menu_item, mainWindow = mainWindow, menuName = menuName, spacing = spacing)
                # press ESC to remove the menu
                mainWindow.type_keys("{ESC}")

if __name__ == "__main__":
    main()

-------- OUTPUT -----------------

Started Application 7-Zip
No of Main Menu in App = len(menu.children()) - 6

   File
      Open  Enter
      Open Inside   Ctrl+PgDn
      Open Inside *
      Open Inside #
      Open Outside  Shift+Enter
      View  F3
      Edit  F4
      Rename    F2
      Copy To...    F5
      Move To...    F6
      Delete    Del
      Split file...
      Combine files...
      Properties    Alt+Enter
      Comment...    Ctrl+Z
      CRC
            CRC-32
            CRC-64
            SHA-1
            SHA-256
            *
      Create Folder F7
      Create File   Ctrl+N
      Link...
      Alternate streams
      Exit  Alt+F4
   Edit
      Select All    Shift+[Grey +]
      Deselect All  Shift+[Grey -]
      Invert Selection  Grey *
      Select... Grey +
      Deselect...   Grey -
      Select by Type    Alt+[Grey+]
      Deselect by Type  Alt+[Grey -]
   View
      Large Icons   Ctrl+1
      Small Icons   Ctrl+2
      List  Ctrl+3
      Details   Ctrl+4
      Name  Ctrl+F3
      Type  Ctrl+F4
      Date  Ctrl+F5
      Size  Ctrl+F6
      Unsorted  Ctrl+F7
      Flat View
      2 Panels  F9
      2021-04-28
            2021-04-28
            2021-04-28 11:08
            2021-04-28 11:08:54
            2021-04-28 11:08:54.1341867
      Toolbars
            Archive Toolbar
            Standard Toolbar
            Large Buttons
            Show Buttons Text
      Open Root Folder  \
      Up One Level  Backspace
      Folders History...    Alt+F12
      Refresh   Ctrl+R
      Auto Refresh
   Favorites
      Add folder to Favorites as
            Bookmark 0  Alt+Shift+0
            Bookmark 1  Alt+Shift+1
            Bookmark 2  Alt+Shift+2
            Bookmark 3  Alt+Shift+3
            Bookmark 4  Alt+Shift+4
            Bookmark 5  Alt+Shift+5
            Bookmark 6  Alt+Shift+6
            Bookmark 7  Alt+Shift+7
            Bookmark 8  Alt+Shift+8
            Bookmark 9  Alt+Shift+9
      - Alt+0
      - Alt+1
      - Alt+2
      - Alt+3
      - Alt+4
      - Alt+5
      - Alt+6
      - Alt+7
      - Alt+8
      - Alt+9
   Tools
      Options...
      Benchmark
   Help
      Contents...   F1
      About 7-Zip...
Related