to iterate the sub menu item using pywinauto - python-3.x

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}

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

How can I get a Windows 11 Context Menu item to work with my PyQt6 application

I have a python script that I would like to run from the Windows 11/10 Right Click Context Menu in my documents folder
"C:\\Users\\me\\Documents\\PythonScripts\\main.py"
from PyQt6.QtWidgets import QApplication, QWidget
app = QApplication([])
window = QWidget()
window.setWindowTitle('My PyQt6 Application')
window.resize(400, 300)
window.move(100, 100)
window.show()
app.exec()
I created a python script that adds an item to the Right Click Context Menu in Windows 11 via registry.
But, The problem I am having is that when I try to click on "My Python Script" in the context menu, a pyqt6 window should pop up.
I tried running the exact command in terminal window
C:\Users\me\AppData\Local\Programs\Python\Python311\python.exe C:\Users\me\Documents\PythonScripts\main.py "%V"which works with no issues.
import winreg
menu_name = "My Python Script"
icon_path = "%SystemRoot%\\system32\\imageres.dll,3"
python = "C:\\Users\\me\\AppData\\Local\\Programs\\Python\\Python311\\python.exe"
command = f"{python} C:\\Users\\me\\Documents\\PythonScripts\\main.py \"%V\""
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT,
r"Directory\Background\shell",
0, winreg.KEY_WRITE)
menu_key = winreg.CreateKey(key, menu_name)
winreg.SetValueEx(menu_key, "Icon", 0, winreg.REG_SZ, icon_path)
winreg.SetValueEx(menu_key, "command", 0, winreg.REG_SZ, command)
winreg.CloseKey(menu_key)
winreg.CloseKey(key)
I found where the issue resided. I was adding the command key incorrectly. I needed to use command_key = winreg.CreateKey(menu_key, "command") for the command. Then add the value winreg.SetValueEx(command_key, "", 0, winreg.REG_SZ, command).
import winreg
# Name that will appear in the context menu
menu_name = "My Python Script"
# Path to the icon file
icon_path = "%SystemRoot%\\system32\\imageres.dll,3"
python = "C:\\Users\\me\\AppData\\Local\\Programs\\Python\\Python311\\python.exe"
# Path to the Python script and any command-line arguments
command = f"{python} C:\\Users\\me\\Documents\\PythonScripts\\main.py \"%V\""
# Open the registry key
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT,
r"Directory\Background\shell",
0, winreg.KEY_WRITE)
# Create a new key for our menu item
menu_key = winreg.CreateKey(key, menu_name)
command_key = winreg.CreateKey(menu_key, "command")
# Set the menu item's icon
winreg.SetValueEx(menu_key, "Icon", 0, winreg.REG_SZ, icon_path)
# Create a new key for our menu item
winreg.SetValueEx(command_key, "", 0, winreg.REG_SZ, command)
# Close the keys
winreg.CloseKey(menu_key)
winreg.CloseKey(command_key)
winreg.CloseKey(key)

The windows application automating using pywinauto does not detect elements inside a TreeView, despite the elements have there own characteristic

The application I am automating is a win32 supported backend application and using inspect.exe to detect the elements
Below is my code trying to click on sales receipt element, on execution I get error
code:screenshot of the treeview in inspect.exe while application image in background
app = Application(backend="win32").connect(process=5468)
app.windows()
dlg = app['TFMenuG.UnicodeClass']
handle = dlg.child_window(control_id='UIA_ButtonControlTypeId (0xC350)').draw_outline()
error:
Traceback (most recent call last):
File "c:\..\pythonDemo\notepad.py", line 62, in <module>
handle = dlg.child_window(control_id='UIA_ButtonControlTypeId (0xC350)').draw_outline()
File "C:\..\AppData\Local\Programs\Python\Python39-32\lib\site-packages\pywinauto\application.py", line 379, in __getattribute__
ctrls = self.__resolve_control(self.criteria)
File "C:\..\AppData\Local\Programs\Python\Python39-32\lib\site-packages\pywinauto\application.py", line 261, in __resolve_control
raise e.original_exception
File "C:\..\AppData\Local\Programs\Python\Python39-32\lib\site-packages\pywinauto\timings.py", line 436, in wait_until_passes
func_val = func(*args, **kwargs)
File "C:\..\AppData\Local\Programs\Python\Python39-32\lib\site-packages\pywinauto\application.py", line 222, in __get_ctrl
ctrl = self.backend.generic_wrapper_class(findwindows.find_element(**ctrl_criteria))
File "C:\..\AppData\Local\Programs\Python\Python39-32\lib\site-packages\pywinauto\findwindows.py", line 87, in find_element
raise ElementNotFoundError(kwargs)
pywinauto.findwindows.ElementNotFoundError: {'control_id': 'UIA_ButtonControlTypeId (0xC350)', 'top_level_only': False, 'parent': <win32_element_info.HwndElementInfo - '', TFMenuG.UnicodeClass, 196780>, 'backend': 'win32'}
Please help me a way to identify the elements. I am doubting the elements are not recognised because of win32 backend
First, if you use Inspect.exe you must use Application(backend="uia"). If you want to check the application compatibility with older "win32" backend, you need Spy++ which is included into Visual Studio.
Second control_id is integer ID from Spy++ and it can be inconsistent from run to run. I would recommend printing top level window texts by print([w.window_text() for w in app.windows()]) and use necessary text to identify top level window and dump child identifiers:
app.window(title="Main Window Title").dump_tree() # or use title_re for regular expression
app.window(title="Main Window Title").child_window(title="Sales Receipts", control_type="TreeItem").draw_outline().click_input()
# or get .wrapper_object() and discover all available methods,
# wrapper methods can be chained as above
P.S. If Inspect.exe doesn't show property "NativeWindowHandle", it means the element is not visible to "win32" backend.
EDIT1:
Try this code for the "win32" TreeView which is not automatically detected as TreeViewWrapper:
from pywinauto import Application
from pywinauto.controls.common_controls import TreeViewWrapper
app = Application(backend="win32").connect(class_name="TFMenuG.UnicodeClass")
dlg = app['TFMenuG.UnicodeClass']
handle = dlg.child_window(class_name='THTreeView.UnicodeClass').wrapper_object().handle
tree_view = TreeViewWrapper(handle)
print(dir(tree_view)) # list all available methods
tree_view.get_item("Sales Receipts").expand()
tree_view.get_item(r"Sales Receipts\Reports").click(where="text")
When you see all available methods, try documented methods for "win32" TreeView: https://pywinauto.readthedocs.io/en/latest/code/pywinauto.controls.common_controls.html#pywinauto.controls.common_controls.TreeViewWrapper Please note that _treeview_element object returned by get_item(...) represents specific item without window handle, but it's usable.

notimplementederror: can't perform this operation for unregistered loader type python : trying to convert py to .exe using cx_freeze

I'm trying to convert a pygame project to an executable and it works fine on launch but when I clicked the play button it produces this error and I'm not sure how to fix it would be obliged if anyone could help me
import cx_Freeze
executables = [cx_Freeze.Executable("Consumo V25.py")]
cx_Freeze.setup(
name = "Consumo",
options ={"build_exe": {"packages":["pygame",_init_.py],
"include_files":["Blowfish.png", "dojo.png", "Rice_fresh.png", "rottenapple.png", "rottenfish.png", "rottenrice.png", "gameover.png", "Apple .png", "Fish.png","sumo .png","character.png"]}},
executables = executables
)
Here is the button function that is in my source code:
def button(msg,x,y,w,h,c,action=None):#passes the parameters by value
mouse = pygame.mouse.get_pos()#this gets the postion of the mouse
click = pygame.mouse.get_pressed()#checks to see where the mouse has been clicked
pygame.draw.rect(gameDisplay, c,(x,y,w,h))#draws a rectangle with on the game display with the parameters given
if x+w > mouse[0] >x and y+h > mouse[1] > y:#checks to see if the mouse has been clicked anywhere in the button
if click[0] == 1 and action != None:#if the mouse has been clicked performed an action
action()
smallText = pygame.font.SysFont("comicsansMS",20)
textSurf , textRect = textObjects(msg ,smallText)
#sets the message of the button
textRect.center = ((x+(w/2),(y+(h/2))))#centers the text on screen
gameDisplay.blit(textSurf, textRect)#puts the button on screen with the
here is where I'm running the function:
def menuScreen():
screenOn = True
while screenOn ==True:
for event in pygame.event.get():
if event.type == pygame.QUIT:#allows user to quit the game
quit()
gameDisplay.blit(dojoBackDrop,(0,0))#sets the image to the size of the screen
button("Play Game",850,340,120,50,blue,gameLoop)#Puts theree button on the screen
button("Leaderboard",850,440,120,50,blue)
button("Quit game",850,540,120,50,blue,quitGame)
pygame.display.update()#updates the screen so things can appear on it
The full error is :
File "C:\Users\Jackj\AppData\Local\Programs\Python\Python36\lib\site-packages\pygame\pkgdata.py", line 50, in getResource
if resource_exists(pkgname, identifier):
File "C:\Users\Jackj\AppData\Local\Programs\Python\Python36\lib\site-packages\pkg_resources\__init__.py", line 1191, in resource_exists
return get_provider(package_or_requirement).has_resource(resource_name)
File "C:\Users\Jackj\AppData\Local\Programs\Python\Python36\lib\site-packages\pkg_resources\__init__.py", line 1459, in has_resource
return self._has(self._fn(self.module_path, resource_name))
File "C:\Users\Jackj\AppData\Local\Programs\Python\Python36\lib\site-packages\pkg_resources\__init__.py", line 1509, in _has
"Can't perform this operation for unregistered loader type"
NotImplementedError: Can't perform this operation for unregistered loader type
You could try to find out which resource is causing the exception by replacing the lines 50 to 51 of C:\Users\Jackj\AppData\Local\Programs\Python\Python36\lib\site-packages\pygame\pkgdata.py with:
try:
if resource_exists(pkgname, identifier):
return resource_stream(pkgname, identifier)
except Exception as e:
print(pkgname, identifier)
raise e

Error using checkmouse

I'm trying to use checkmouse in order to undraw something from my window. When someone clicks the button it should undraw the text and write something else. I'm using checkMouse and getX() and getY() to do this but i keep receiving this error that states:
File "C:\Users\User\Documents\python\project2.py", line 71, in panel
if (clicknew.getX()>90 and clicknew.getX()<210) and (clicknew.getY()>35 and clicknew.getY() < 0):
AttributeError: 'NoneType' object has no attribute 'getX'
this code that i have done so far is as follows:
from graphics import *
#creating the game panel window
def panel():
#grey window, with coordinates flipped, with banners etc
win = GraphWin("Start Panel", 300,200)
win.setCoords(0,0,300,200)
win.setBackground("light grey")
#drawing the BoilerMazer banner with text
boilermazer = Rectangle(Point(0,200),Point(300,160))
boilermazer.setFill("white")
boilermazer.draw(win)
#text inside
banner1 = Text(Point(150,180),"BoilerMazer")
banner1.setStyle("bold")
banner1.setSize(20)
banner1.draw(win)
#initial game panel is going to have two buttons and a top scores object
#top score "screen"
toprec = Rectangle(Point(60,140),Point(240,50))
toprec.setFill("white")
toprec.draw(win)
#text inside toprec
topscores = Text(Point(150,130),"TOP SCORES")
topscores.setSize(8)
topscores.draw(win)
border = Text(Point(150,120),"======")
border.draw(win)
bigmac = Text(Point(150,110),"Big Mac 21")
bigmac.setSize(8)
bigmac.draw(win)
tt = Text(Point(150,90),"T.T 23")
tt.setSize(8)
tt.draw(win)
cshell = Text(Point(150,75),"C-Shell 25")
cshell.setSize(8)
cshell.draw(win)
macmac = Text(Point(150,55),"MacMac 27")
macmac.setSize(8)
macmac.draw(win)
#new player button that will eventually be clicked
new1 = Point(90,35)
new2 = Point(210,0)
newrec = Rectangle(new1,new2)
newrec.setFill("chartreuse2")
newrec.draw(win)
#new player button text
newplayer = Text(Point(150,18),"NEW PLAYER")
newplayer.draw(win)
#reset button
resetrec = Rectangle(Point(240,35),Point(300,0))
resetrec.setFill("red")
resetrec.draw(win)
#resettext
reset = Text(Point(270,18),"RESET")
reset.draw(win)
#secondary panel window is the game panel after they click new player
#set up points that we check between for the new player button first
#setting up the checkmouse
clicknew = win.checkMouse()
if (clicknew.getX()>90 and clicknew.getX()<210) and (clicknew.getY()>35 and clicknew.getY() < 0):
newplayer.undraw()
you can find the graphics window here:http://mcsp.wartburg.edu/zelle/python/graphics.py
I don't understand what I'm doing wrong, is there some other method that I'm supposed to be using? Thanks for your help
According to the docs, checkMouse() returns None if no mouse click has been detected priorly. So that seems to be the case.
You could put a loop around the call to checkMouse and keep checking if clicknew is not None and only in that case go on in your program. But maybe there's a better way...
UPDATE:
Example:
while True:
clicknew = win.getMouse()
if clicknew:
break
else:
time.sleep(0.1) # avoid busy waiting
# clicknew is set now => use it

add keyboard shortcuts to GIo.Menu

I am trying to add accelgroup (keyboard shortcuts) to the Gio.Menu items.
But I have not found a way to do this. Like, in this example, I want to open file with <Ctrl>+o
filemenu = Gio.Menu()
filemenu.append("Open","win.open")
accelgroup=Gtk.AccelGroup()
self.add_accel_group(accelgroup)
# Open menu
open_action = Gio.SimpleAction(name="open")
# this line is problematic
open_action.add_accelerator("activate". Gdk._keyval_from_name("O"))
open_action.connect("activate", self.MenuElem.file_open_clicked)
self.add_action(open_action)
How can I do this?
You don't add keybindings to the Gio.Action itself you add them to a Widget or Application for example:
app = # My Gtk.Application instance
window = # My Gtk.ApplicationWindow instance
action = Gio.SimpleAction.new('open', None)
window.add_action(action)
app.add_accelerator('<Primary>o', 'win.open', None)
# The 'win.' prefix is because it was added to a Gtk.ApplicationWindow

Resources