Windows System Menu in Python - python

I am trying to create a new item in the Windows System Menu for my app and have an action performed when it is click.
I have worked out the frist part using the below code.
import win32con
import win32gui
hwnd = win32gui.GetForegroundWindow ()
hmenu = win32gui.GetSystemMenu (hwnd, False)
win32gui.AppendMenu(hmenu, win32con.MF_SEPARATOR, 0, '')
win32gui.AppendMenu(hmenu, win32con.MF_STRING, 100, 'New Menu Item')
I can not work out how link a function to the button? So that an action is performed when it is click
Any help would be great.
Thanks.
Donald.
p.s. Using Python 2.6.5 and Windows XP

You have to hook into the windows procedure of the menu and handle the messages being sent. See e.g. http://wiki.wxpython.org/HookingTheWndProc

Related

How to update PyQT5 application for both Windows and macOS?

I have an application built with PyQT5 for both Windows and macOS. Currently, the user checks for updates by clicking the button and when there is a new update available I am redirecting them to the browser to my server to download the latest .exe (Windows) or .pkg (macOS). The issue is for say if the user downloads and installs the latest version in a different location than the previous one which will result in two instances of the same application.
I want to improve the user experience and make an auto-updater like all the established applications. When the user clicks the updates the application should download the new updates without making any hassles for the users and update the application for both the OS.
For Windows, I am using Pyinstaller to make the .exe file and then Inno Setup to make it executable. Moreover, for macOS I am using setuptools to make the .app and macOS packages app to make it executable.
It would be really great if someone could help me to implement an update feature for my PyQT5 application.
Hi there I have made a program where it can update itself, I was using tkinter, but it should work for PyQT5 if the same widgets are there. We are using GitHub for the program to download from there. Also I am on windows so I don't know if this works on mac. Here is my code:
import tkinter as tk #for you it is pyqt5
from tkinter import * #MessageBox and Button
import requests #pip install requests
import os #part of standard library
import sys #part of standard library
VERSION = 4
b1 = Button(frame, text = "Back", command = homepage)
b1.pack(ipadx= 10, ipady = 10, fill = X, expand = False, side = TOP)
checkupdate = Label(frame, text = "Looking for updates", font = ("Arial", 14))
checkupdate.pack()
try:
link = "https://raw.githubusercontent.com/SomeUser/SomeRepo/main/SomeFolder/version.txt"
check = requests.get(link)
if float(VERSION) < float(check.text):
mb1 = messagebox.askyesno('Update Available', 'There is an update available. Click yes to update.')
if mb1 is True:
filename = os.path.basename(sys.argv[0])
for file in os.listdir():
if file == filename:
pass
else:
os.remove(file)
exename = f'NameOfYourApp{float(check.text)}.exe'
code = requests.get("https://raw.githubusercontent.com/SomeUser/SomeRepo/main/SomeFolder/NewUpdate.exe", allow_redirects = True)
open(exename, 'wb').write(code.content)
root.destroy()
os.remove(sys.argv[0])
sys.exit()
elif mb1 == 'No':
pass
else:
messagebox.showinfo('Updates Not Available', 'No updates are available')
except Exception as e:
pass
Make sure you convert all the tkinter code to PyQt5 widgets. Also this is windows change the "https://raw.githubusercontent.com/SomeUser/SomeRepo/main/SomeFolder/NewUpdate.exe" to "https://raw.githubusercontent.com/SomeUser/SomeRepo/main/SomeFolder/NewUpdate.app" for mac. If this does not work comment and I will try my best to convert this to PyQt5.

Handling Context Menu of the taskbar icon with pywinauto

I am trying to automate the exiting operation on one of the apps. The app's icon is located in the taskbar. I was successfull in opening that icon's context menu with the modified code that I have found on stackoverflow:
import pywinauto
from pywinauto.application import Application
import time
app= "Service is enabled."
app = Application(backend="uia").connect(path="explorer.exe")
st = app.window(class_name="Shell_TrayWnd")
t = st.child_window(title="Notification Chevron").wrapper_object()
t.click()
time.sleep(1)
list_box = Application(backend="uia").connect(class_name="NotifyIconOverflowWindow")
list_box_win = list_box.window(class_name="NotifyIconOverflowWindow")
list_box_win.wait('visible', timeout=30, retry_interval=3)
# time.sleep(1)
appOpened= list_box_win.child_window(title = app)
appOpened.click_input(button = "right")
After the execution of the code above I get to the point when the context menu is opened:
The next thing that I want to do is to click on Exit, I have tried doing it by specifying the mouse click coordinates, but I have noticed that the position of the parent icon is changing from time to time.
What I would like to do is to get the handle on the Exit button and send click automatically.
------Edit-------
The icon is located in the hidden icons
So you want to access to the right click context menu. As said in this answer, you can do something like :
listbox.PopupMenu["Exit"].set_focus().click_input()

How to close two windows of the same application using python?

I'm working on an automation program in python, I've two windows of cmd open on my screen. I want my code to only close the first window, and leave the second window as it is. How will I make my code determine which window to close?
To close the window I'm using the keyboard package in python, the code writes exit in the cmd window and generates an enter key press to exit the window.
keyboard.write("exit") # closes main cmd window
keyboard.press_and_release("enter") # window closes
If you use Windows OS, you can use the pywin32 and win32gui libraries which contain the modules win32gui and win32con which will help search through windows matching a certain name and getting the window handle number (hwnd). Given a hwnd, you can then close the first window that was opened.
You will first need to install pywin32 and wind32gui:
pip install win32gui
pip install pywin32
Here's the code to close the first command prompt window:
import win32gui
import win32con
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
def return_window_hwnd(window_name):
'''Return list window handles of that match a given window name'''
windows = []
win32gui.EnumWindows(windowEnumerationHandler, windows)
print(windows) #[(67084, 'Command Prompt'), (65868, ''), (722426, 'Command Prompt'), ...]
hwnds = []
for wind in windows:
if window_name in wind[1] or window_name == wind[1]:
hwnds.append(wind[0])
return hwnds
# search for Command Prompt windows and return the list of hwnd
command_hwnd_arr = return_window_hwnd('Command Prompt')
# if more than 1 is window open, close the first opened window
if len(command_hwnd_arr) > 1:
window_handle_to_close = command_hwnd_arr[1]
win32gui.PostMessage(window_handle_to_close, win32con.WM_CLOSE, 0, 0)

Python - How to interact with system tray popup

I want to autologin to an app via its system tray icon.
I use the pywinauto module to interact with the tray icon to launch the app and now I have a popup who ask me to log on.
But... I don't know how to interact with it !
This is my icon :
Tray Icon
Here, an extract of my code (works fine) :
_pApp = Application().connect(path='my_app_dir')
taskbar.ClickSystemTrayIcon(1)
_pApp.PopupMenu.menu_item('submenu').click_input()
_pApp.PopupMenu.menu_item('another_submenu').click_input()
How can I interact with the popup authentication window below ?
Popup window
Thanks for your help.
I finally found a solution with pywinauto.keyboard. I don't know if it's clean but it works.
from pywinauto.keyboard import *
[...]
send_keys(_user)
send_keys("{VK_TAB}")
send_keys(_pass)
send_keys("{ENTER}")
Finally, I found exactly the expected behavior :)
Thank you Vasily Ryabov ! Your method is very helpful !
I do not use 'send_keys' anymore.
from tkinter.messagebox import *
from pywinauto import taskbar
from pywinauto.application import Application
[...]
_user = "TOTO"
_pass = "TOTOPASS"
app_dir = r'C:\Program Files\Common Files\App\App.exe'
icon_list = list()
# Getting the name of the icons in the sys tray
for i in range(0, 13):
app_sti = taskbar.SystemTrayIcons.wrapper_object()
app_stv = pulse_sti.button(i).info.text
icon_list.append(app_stv)
# Looking for my app name
try:
if "App_name" in str(icon_list):
app = Application().connect(path=app_dir)
taskbar.ClickSystemTrayIcon("App name")
app.PopupMenu.menu_item('menu').click_input()
app.PopupMenu.menu_item('menu -> submenu').click_input()
app_auth = Application(backend="uia").connect(title_re="Title*", timeout=5)
app_auth_window = app_auth.window(title_re="Title*")
app_auth_window.child_window(title="User :", control_type="Edit").set_text(_user)
app_auth_window.child_window(title="Password :", control_type="Edit").set_text(_pass)
app_auth_window.child_window(title="Connect", control_type="Button").click()
except Exception as error:
showwarning("Error", "App not found !")
Currently, I re-write a part of my code :
from pywinauto import taskbar
from pywinauto.application import Application
from pywinauto.keyboard import *
from tkinter.messagebox import *
[...]
app_dir = r'C:\Program Files\Common Files\App\App.exe'
_user = "TOTO"
_pass = "TOTOPASS"
# Check if my app has its system tray icon in the taskbar
for i in range(0, 10):
tsIcon = taskbar.SystemTrayIcons.wrapper_object()
tsValue = tsIcon.button(i).info.text
# If I find it, the code click on it and its menu until the popup auth window come
if "App_name" in tsValue:
_pApp = Application().connect(path=app_dir)
taskbar.ClickSystemTrayIcon(i)
_pApp.PopupMenu.menu_item('menu').click_input()
_pApp.PopupMenu.menu_item('menu->submenu').click_input()
time.sleep(2)
# When the popup window comes out, I run 'send_keys'
send_keys(_user)
send_keys("{VK_TAB}")
send_keys(_pass)
send_keys("{ENTER}")
else:
showwarning("Error", "App not found !")
[...]
My code seems good ? There is another "most clean" method ?
Thanks

How to get count of icons in tray using pywinauto

I have an app which sits in tray when I click on .exe file.
I am unable click on my app which sit in system tray. Because it doesn't have class_name or id or anything when I inspect using inspector.exe. So I decided to click this using index of icon. As I am not sure how many icons sit in tray when I run this particular program. So I wanted to get the count of the icon before I click the .exe file. If the count is x then I can click index x icon after clicking the .exe which actually clicks on my desired icon.
Can any one help me in getting the count of the icons. I tried multiple times using child_window(class_name="") but it returned just an object instead of list.
Below is my code:
from pywinauto.application import Application
import time
app = Application(backend="uia").connect(path="explorer.exe")
st = app.window(class_name="Shell_TrayWnd")
t = st.child_window(title="Notification Chevron").wrapper_object()
t.click()
time.sleep(1)
list_box = Application(backend="uia").connect(class_name="NotifyIconOverflowWindow")
list_box_win = list_box.window(class_name="NotifyIconOverflowWindow")
list_box_win.wait('visible', timeout=30, retry_interval=3)
list_box_win.child_window(class_name="", found_index=x).click_input()
Your help will be much appreciated :)
This is not giving the count and do the required job.
The following code will loop through the apps available in the system tray and clicks on the desired app by checking its name.
from pywinauto.application import Application
import time
app = Application(backend="uia").connect(path="explorer.exe")
taskBar = app.window(class_name='Shell_TrayWnd')
trayIcon = taskBar["Notification Chevron"].wrapper_object()
trayIcon.click()
time.sleep(0.25)
trayWindowContainer = Application(backend="uia").connect(class_name="NotifyIconOverflowWindow")
trayWindow = trayWindowContainer.window(class_name="NotifyIconOverflowWindow")
trayWindow.wait('visible', timeout=30, retry_interval=3)
breakLoop: bool = False
for notification_area in trayWindow.children():
for app_in_tray in notification_area.children():
if "<App_name>" in str(app_in_tray):
app_in_tray.click_input()
breakLoop = True
break
if breakLoop:
break

Categories

Resources