i have got a problem that i have done a small project which can shutdown , restart, hibernate,sleep the pc by buttons using tkinter and OS modules but when trying to convert .py to .exe using pyinstaller it displays the output as completed successfully but when click the executed the executable it says that the Application is non executable.
below I have attached my code .
from tkinter import *
import os
from os import system as sys
from tkinter import messagebox as msg
screen = Tk()
screen.title("System - Properties")
screen.geometry("500x500")
screen.resizable(False,False)
screen.configure(background="powderblue")
screen.iconbitmap("LOGO.ico")
canvas1 = Canvas(screen,height=100,width=480,bg="red",bd=5,relief="groove").place(x = 3,y = 0)
Header = Label(canvas1,text="SYSTEM CONTROL",fg="black",bg="tomato",
font=("Courier New",30,"bold")).place(x = 85,y = 30)
canvas2 = Canvas(screen,height=260,width=470,bg="teal",bd=10,relief="sunken").place(x = 3,y = 120)
# button function starts
def shutdown():
sys("shutdown /s /t 1")
def restart():
sys("shutdown /r /t 1")
def logoff():
sys("shutdown /l /t 1")
def hibernate():
sys("shutdown /h /t 1")
def help():
content = "This app helps to perform some simple actions \nJust click the button according to your use. \n\n\tDO NOT PLAY WITH THIS"
msg.showinfo("HELP",content)
def about():
content= "Author : John Arthur\nDate : 19/07/2021 \nProgramming Language : Python"
msg.showinfo("ABOUT",content)
# button starts
shutdown = Button(canvas2,text="SHUTDOWN",bd = 2,relief="sunken",command=shutdown,bg="black",fg="white",
font=("Bell MT",15,"italic")).place(x = 40,y=175)
restart = Button(canvas2,text="RESTART",bd = 2,relief="sunken",command=restart,bg="black",fg="white",
font=("Bell MT",15,"italic")).place(x = 190,y=175)
logoff = Button(canvas2,text="LOG-OFF",bd = 2,relief="sunken",command=logoff,bg="black",fg="white",
font=("Bell MT",15,"italic")).place(x = 340,y = 175)
hibernate = Button(canvas2,text="HIBERNATE",bd = 2,relief="sunken",command=hibernate,bg="black",fg="white",
font=("Bell MT",15,"italic")).place(x = 40,y=250)
help = Button(canvas2,text="HELP",bd = 2,relief="sunken",command=help,bg="black",fg="white",width=9,
font=("Bell MT",15,"italic")).place(x = 190,y=250)
about = Button(canvas2,text="ABOUT",bd = 2,relief="sunken",command=about,bg="black",fg="white",
font=("Bell MT",15,"italic")).place(x = 340,y=250)
# function button over
canvas3 = Canvas(screen,height=70,width=480,bg="black",bd=5,relief="groove").place(x=3,y=410)
# control button starts
quit = Button(canvas3,text="exit",bd = 2,relief="sunken",command=exit,bg="orange",fg="black",width=15,
font=("Arial",20,"bold")).place(x = 110,y=425)
# control button ends
screen.mainloop()
Can someone help me to solve this problem please .
Related
i'm currently need help of my python system. i made a simple GUI that insist of a simple GUI with buttons that calls out other python scripts and print it to the geometry. however, i have an issue where i could not get the system to print anything out of the GUI or input anything on the tkinter geometry when the python script needed of any input from the User. the GUI fully works when there are no input needed from the users.
from the code below, i shown my full GUI system that calls out the 2 python scripts whenever button is pressed. i would like to make the tkinter geometry to accept inputs directly to the tkinter geometry and send its input to the python script and display its output back again to the tkinter geometry. How do i improve this system or address this problem?
GUI.py
from tkinter import *
from subprocess import *
from threading import *
import time
import subprocess
#text1.insert(END, your stuff here) to put output to GUI
#GUI
root = Tk()
root.title('System 1')
root.geometry('1000x900')
root.configure(background='black')
text1 = Text(root, width= 100, height = 40)
text1.pack()
#command list
def command():
try:
child = Popen(['python', '-u', 'CMDping.py'], stdout=PIPE)
text1.delete("1.0", END)
for line in iter(child.stdout.readline, ''):
text1.insert(INSERT, line)
text1.see(END)
text1.update_idletasks()
child.stdout.close()
child.wait()
except CalledProcessError:
text1.insert(END, "File Not Found!")
def command1():
try:
bttn1.destroy()
pythonfile1 = 'python NetworkCommands.py'
p1 = subprocess.Popen(pythonfile1, shell=True)
out, err = p1.communicate()
except CalledProcessError:
text1.insert(END, "File Not Found!")
#Threading for command Function
def Threading():
t1=Thread(target=command)
t1.start()
root.update()
def Threading1():
t1=Thread(target=command1)
t1.start()
root.update()
#buttons
bttn= Button(root,bg="black",fg="white",highlightcolor="white", text="Diagnose", command=Threading)
bttn.pack(side=LEFT, padx=5,pady=0)
bttn1= Button(root,bg="black",fg="white",highlightcolor="white", text="Flush_DNS", command=Threading1)
bttn1.pack(side=LEFT, padx=5,pady=0)
#Clock
class Clock:
def __init__(self):
self.time1 = ''
self.time2 = time.strftime('%H:%M:%S')
self.mFrame = Frame()
self.mFrame.pack(side=TOP,expand=YES,fill=X)
self.watch = Label(self.mFrame, text=self.time2, font=('times',12,'bold'))
self.watch.pack()
self.changeLabel() #first call it manually
def changeLabel(self):
self.time2 = time.strftime('%H:%M:%S')
self.watch.configure(text=self.time2)
self.mFrame.after(200, self.changeLabel) #it'll call itself continuously
obj1 = Clock()
root.mainloop()
CMDping.py
import subprocess
def ping():
command = input("Enter IP Address to ping: ")
time.sleep(2)
os.system("ping " + command)
ping()
import tkinter as tk
from tkinter import *
import time
def centertitle(e):
w = int(root.winfo_width() / 3.5)
s = 'Installation Wizard v1.0'.rjust(w//2)
root.title(s)
def textbox():
textbox=Text(root.canvas, width = 62, height = 25, state=DISABLED)
textbox.pack()
textbox.insert(constants.INSERT,'You text goes here')
#Configure tkinter window and title
root = Tk()
root.canvas = Canvas(root, width = 500, height = 404, bg="#3D3D3D", highlightthickness=0)
root.canvas.pack(expand=True, fill=BOTH)
root.iconbitmap(default='transparent.ico')
root.bind("<Configure>", centertitle)
root.resizable(False, False)
#Buttons
btn = tk.Button(root, text='Start Install', height = 2, width = 15)
btn['command'] = lambda b=btn:[b.pack_forget(), b.place_forget(), textbox()]
btn.pack(fill=BOTH)
btn.place(x=190, y=181)
root.mainloop()
What im trying to create, is a simple "install" gui, which i was gonna pack into an exe. all i really want is a button, that starts another python file (the one that installs everything) and when it calls print, i want it sent to the text box in the gui... its hard to explain but i hope you get what i mean
could someone help me im really confused with guis
code from other .py:
import os
import sys
import shutil
import subprocess;
from pathlib import Path
import psutil
import time
def startProgram(program):
SW_HIDE = 0
info = subprocess.STARTUPINFO()
info.dwFlags = subprocess.STARTF_USESHOWWINDOW
info.wShowWindow = SW_HIDE
subprocess.Popen(program, startupinfo=info)
def terminateProgram(processName):
for proc in psutil.process_iter():
if processName.lower() in proc.name().lower():
proc.terminate()
def checkIfProcessRunning(processName):
for proc in psutil.process_iter():
try:
if processName.lower() in proc.name().lower():
return True
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return False;
st_inf = subprocess.STARTUPINFO()
st_inf.dwFlags = st_inf.dwFlags | subprocess.STARTF_USESHOWWINDOW
user_profile = os.environ['USERPROFILE']
appdata_local = os.environ['LOCALAPPDATA']
FolderDictionary = [(user_profile + '\spicetify-cli'), (user_profile + '\.spicetify'), (appdata_local + '\spotify')]
for x in FolderDictionary:
try:
shutil.rmtree(x)
print('"%s", has been deleted.\n' % x)
except OSError as e :
print('"%s", was not found.\n' % x)
print("Installing Spotify.\n")
terminateProgram('Spotify.exe')
startProgram('.\\data\spotify-1-1-62-583.exe')
while True:
if checkIfProcessRunning('spotify-1-1-62-583.exe') == False:
print("Finished Installing Spotify.\n")
terminateProgram('Spotify.exe')
break
print("Installing Spicetify.\n")
terminateProgram('powershell')
subprocess.Popen(["powershell","$v='2.5.0'; Invoke-WebRequest -UseBasicParsing 'https://raw.githubusercontent.com/khanhas/spicetify-cli/master/install.ps1' | Invoke-Expression\nspicetify\nspicetify backup apply enable-devtool"], startupinfo=st_inf)
while True:
if checkIfProcessRunning('powershell') == False:
print("Finished Installing Spicetify.\n")
terminateProgram('Spotify.exe')
break
print("Downloading Themes.\n")
terminateProgram('powershell')
subprocess.Popen(["powershell",'$sp_dir = "${HOME}\spicetify-cli"\n$zip_file = "${sp_dir}\Themes.zip"\n$download_uri = "https://github.com/morpheusthewhite/spicetify-themes/archive/refs/heads/v2.zip"\nInvoke-WebRequest -Uri $download_uri -UseBasicParsing -OutFile $zip_file\nExpand-Archive -Path $zip_file -DestinationPath $sp_dir -Force\nRemove-Item -Path $zip_file\nRemove-Item -LiteralPath "${HOME}\spicetify-cli\Themes" -Force -Recurse\nRename-Item "${HOME}\spicetify-cli\spicetify-themes-2" "${HOME}\spicetify-cli\Themes"\nRemove-Item "${HOME}\spicetify-cli\Themes\*.*" -Force -Recurse | Where { ! $_.PSIsContainer }\nRename-Item "${HOME}\spicetify-cli\Themes\default" "${HOME}\spicetify-cli\Themes\SpicetifyDefault"'], startupinfo=st_inf)
while True:
if checkIfProcessRunning('powershell') == False:
print("Finished Downloading Themes.\n")
break
You've set the state of the text widget to disabled, so you can't insert anything into it. If you want it to be disabled, disable it after inserting the text rather than before.
def textbox():
textbox=Text(root.canvas, width = 62, height = 25)
textbox.pack()
textbox.insert(constants.INSERT,'You text goes here')
textbox.configure(state=DISABLED)
I've made a Python program which reads the file and then sends/receives the data towards/from the microcontroller and everything worked well until I added a menu to display short instructions.
Since the UART communication has to run in a separate thread I used threading and StringVar() to access the data from the main thread.
To demonstrate the problem I've made a short example which has nothing to do with microcontrollers.
The steps to reproduce the problem:
Click the Next screen radio button to open the second screen (at the initial screen the menu works well)
Click Help > Instructions
After (or sometimes even before) closing the message box the program will crash with:
TclStackFree: incorrect freePtr. Call out of sequence?
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Note:
In the original program where there are more UI elements the program always crashes before showing the message box and after removing even more UI elements the program doesn't crash every time - that's why I've left some "redundant" labels. When some more labels are added the program will crash every time.
I have narrowed the cause of the crash to:
displayVal.set()
in checkForData() function. By removing that instruction everything works well.
Moreover, after removing displayVal.trace("w", displayVal_trace) the program will not crash anymore but opening the menu will still temporarily freeze the working thread.
I thought after displayVal.set() Tkinter is trying to update the label but can't because of showing the menu - however, the problem remained even after I removed label_data = Label(up2, textvariable = displayVal).
Here is the stripped down code tested with Python 2.7:
from Tkinter import *
import tkMessageBox
import threading
import time
threadRun = True
checkDelay = 0.5
def checkForData():
global threadRun, checkDelay
print "Simulating thread for receiving messages from UART"
while threadRun == True:
print time.time()
displayVal.set(time.time()) # <-- if removed the menu works OK (no crash)
time.sleep(checkDelay)
print "No more receiving of messages"
def listenForData():
t = threading.Thread(target=checkForData)
t.daemon = False
t.start()
def stopListening():
global threadRun, checkDelay
threadRun = False
time.sleep(checkDelay + 0.1)
def exit_handler():
print "Exiting..."
stopListening()
root.destroy()
root = Tk()
right = int((root.winfo_screenwidth() - 600) / 2)
down = int(root.winfo_screenheight() / 3 - 400 / 2)
root.geometry("600x400+%d+%d" % (right, down))
root.resizable(width = False, height = False)
root.protocol("WM_DELETE_WINDOW", exit_handler)
displayVal = StringVar()
displayVal.set("nothing")
def setupView():
global masterframe
masterframe = Frame()
masterframe.pack(fill=BOTH, expand=True)
selectPort() # the 1st screen for selecting COM ports
def selectPort():
global masterframe, radioVar
# remove everything from the frame
for child in masterframe.winfo_children():
child.destroy()
radioVar = StringVar()
l1 = Label(masterframe, text = "Select...")
l1.pack(pady=(50, 20))
# this would be a list of detected COM ports
lst = ["Next screen"]
if len(lst) > 0:
for n in lst:
r1 = Radiobutton(masterframe, text=n, variable=radioVar, value=n)
r1.config(command = next_screen)
r1.pack()
def mainScreen():
global masterframe, term, status
# remove previous screen from the frame
for child in masterframe.winfo_children():
child.destroy()
up1 = Frame(masterframe)
up1.pack(side=TOP)
up2 = Frame(masterframe)
up2.pack()
terminal = Frame(masterframe)
terminal.pack()
down = Frame(masterframe)
down.pack(side=BOTTOM, fill=BOTH)
label_top = Label(up1, text="Something")
label_top.pack(pady=5)
label_data = Label(up2, textvariable = displayVal)
label_data.pack(pady=(10, 0))
term = Text(terminal, height=10, width=35, bg="white")
term.pack()
term.tag_config("red", foreground="red")
term.tag_config("blue", foreground="blue")
term.insert(END, "The file has been read\n", "red")
term.insert(END, "File contents:\n")
term.insert(END, data)
status = Label(down, text="Status...", bd=1, relief=SUNKEN, anchor=W, bg="green")
status.pack(fill=X)
displayVal.trace("w", displayVal_trace) # <-- if removed only temporary freeze but no crash
def displayVal_trace(name, index, mode):
global term
if(displayVal.get() != "NOTHING"):
term.insert(END, "\nReceived: ", "blue")
term.insert(END, displayVal.get())
term.see(END)
def next_screen():
listenForData()
mainScreen()
def stop():
stopListening()
def instructions():
tkMessageBox.showinfo("Help", "This is help")
main_menu = Menu(root)
root.config(menu = main_menu)
help_menu = Menu(main_menu)
main_menu.add_cascade(label="Help", menu=help_menu)
help_menu.add_command(label="Instructions", command=instructions)
data = [[1], [2], [3]] # this would be the data read from the file
b1 = data[0][0]
b2 = data[1][0]
b3 = data[2][0]
print "Read from file:", b1, b2, b3
setupView()
root.mainloop()
I have some scripts written containing a handful of functions to do some webscraping. When running the scripts, the results print to the IDLE shell using simple 'print' commands.
I have a basic tkinter GUI that will run the script when a button is clicked, but the results still get printed to the shell. How could I adjust my code so that when Master.master() is called, all the print statements embedded in that process print to some area on my GUI. The code I have is the following:
from tkinter import *
import Master #Importing my scraper function
win = Tk()
win.title('Hashtag Scraper')
SearchButton = Button(win,text = 'Search')
SearchButton.grid(row=2,column = 1)
htag_label = Label(win,text = 'What Hashtag?')
htag_label.grid(row = 1,column = 0)
email_label = Label(win,text = 'FB Email')
email_label.grid(row = 1,column = 1)
password_label = Label(win,text = 'FB Password')
password_label.grid(row = 1,column = 2)
def button():
htag = hashtag.get()
user = usr.get()
password = pwd.get()
Master.master(htag,refresh = 3,usr = user,pwd = password) #Function call - want this to print on GUI instead of shell
#win.bind('<Return>', SearchButton)
SearchButton.configure(command = button)
hashtag = StringVar()
#hashtag.set('Hashtag')
hashtag_entry = Entry(win,textvariable=hashtag)
hashtag_entry.grid(row = 0, column = 0)
usr = StringVar()
usr.set('test#aol.com')
usr_entry = Entry(win,textvariable=usr)
usr_entry.grid(row = 0, column = 1)
pwd = StringVar()
#pwd.set('FB Password')
pwd_entry = Entry(win,textvariable=pwd)
pwd_entry.grid(row = 0, column = 2)
Depending on where on your GUI and what kind of widget you want to display the result of your master method call, or perhaps in a new popup TextBox window as mentioned in the comments, change it to the kind of widget you wish to use:
class Master:
def __init__(self, htag, refresh, usr, pwd):
self.htag = htag
self.refresh = refresh
self.usr = usr
self.pwd = pwd
def master(self):
return '\n'.join([self.htag, str(self.refresh), self.usr, self.pwd])
...
def button():
htag = hashtag.get()
user = usr.get()
password = pwd.get()
m = Master(htag, refresh = 3, usr = user, pwd = password)
master_response = m.master() #Function call - want this to print on GUI instead of shell
top = Toplevel()
top.title("Response from master method")
# response_message = "Search Button pushed response"
msg = Message(top, text=master_response)
msg.pack()
button = Button(top, text="Dismiss", command=top.destroy)
button.pack()
output:
How would I programmatically activate a window in Windows using Python? I'm sending keystrokes to it and at the moment I'm just making sure it's the last application used then sending the keystroke Alt+Tab to switch over to it from the DOS console. Is there a better way (since I've learned by experience that this way is by no means foolproof)?
You can use the win32gui module to do that. First you need to get a valid handle on your window. You can use the win32gui.FindWindow if you know the window class name or the exact title. If not, you can enumerate the windows with the win32gui.EnumWindows and try to find the right one.
Once you have the handle, you can call the win32gui.SetForegroundWindow with the handle. It will activate the window and will be ready for getting your keystrokes.
See an example below. I hope it helps
import win32gui
import re
class WindowMgr:
"""Encapsulates some calls to the winapi for window management"""
def __init__ (self):
"""Constructor"""
self._handle = None
def find_window(self, class_name, window_name=None):
"""find a window by its class_name"""
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
"""Pass to win32gui.EnumWindows() to check all the opened windows"""
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
self._handle = hwnd
def find_window_wildcard(self, wildcard):
"""find a window whose title matches the wildcard regex"""
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
def set_foreground(self):
"""put the window in the foreground"""
win32gui.SetForegroundWindow(self._handle)
w = WindowMgr()
w.find_window_wildcard(".*Hello.*")
w.set_foreground()
Pywinauto and SWAPY will probably require the least effort to set the focus of a window.
Use SWAPY to auto-generate the python code necessary to retrieve the window object, e.g.:
import pywinauto
# SWAPY will record the title and class of the window you want activated
app = pywinauto.application.Application()
t, c = u'WINDOW SWAPY RECORDS', u'CLASS SWAPY RECORDS'
handle = pywinauto.findwindows.find_windows(title=t, class_name=c)[0]
# SWAPY will also get the window
window = app.window_(handle=handle)
# this here is the only line of code you actually write (SWAPY recorded the rest)
window.SetFocus()
If by chance other windows are in front of the window of interest, not a problem. This additional code or this will make sure it is shown before running the above code:
# minimize then maximize to bring this window in front of all others
window.Minimize()
window.Maximize()
# now you can set its focus
window.SetFocus()
import ctypes, platform
if platform.system() == 'Windows':
Active_W = ctypes.windll.user32.GetActiveWindow()
ctypes.windll.user32.SetWindowPos(Active_W,0,0,0,0,0,0x0002|0x0001)
Here we go. you just need to store the value of the active window.
Pip install keyboard.
Before you set foreground window, simulate a keyboard to esc that is keyboard.send('esc')
You may want to do it three times for either of the following:
Sidebar
Windows key overlay
Task manager which is always on top
Using SetWindowPos or SetForegroundWindow might NOT be enough if the window was minified aka IsIconic! We can use ShowWindow with SW_RESTORE (9):
import ctypes
def activate_window(hwnd):
user32 = ctypes.windll.user32
user32.SetForegroundWindow(hwnd)
if user32.IsIconic(hwnd):
user32.ShowWindow(hwnd, 9)
Depending on how you identify the desired window there are some ways to get the hwnd aka window handle.
You could loop through all the windows to find the right handle according to the pid via user32.GetWindowThreadProcessId or by window name with user32.GetWindowTextW
To get ProcessIds you could use Windows built-in wmic. There are loads of other nifty things you can do with it. (all attributes: wmic process get /?) (get handle is broken tho) For example:
def get_pids(proc_name):
out = subprocess.check_output('wmic process where Name="%s" get ProcessId' % proc_name)
pids = out.decode().strip().split()[1:]
if not pids:
raise WindowsError('Could not find pids for process')
return [int(pid) for pid in pids]
GUI Application to keep windows active
Python3
install library
pip install pywin32
save below code as alive.pyw file
from ctypes import windll, wintypes, byref, c_uint, sizeof, Structure
import tkinter as tk
import ctypes
import sys
import threading
import time
import win32api
import win32con
stop_threads = True
SET_IDLE_TIME = 40 #in seconds
tm1 = time.time()
value = 0
class LASTINPUTINFO(Structure):
_fields_ = [
('cbSize', c_uint),
('dwTime', c_uint),
]
def get_idle_duration():
global value, tm1
lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = sizeof(lastInputInfo)
windll.user32.GetLastInputInfo(byref(lastInputInfo))
# millis = 4294967 - lastInputInfo.dwTime - windll.kernel32.GetTickCount()
# print(windll.kernel32.GetTickCount(), lastInputInfo.dwTime, sizeof(lastInputInfo), millis)
tm2 = time.time() - tm1
last_idel_time = lastInputInfo.dwTime
# print()
if value != last_idel_time:
value = last_idel_time
tm2 = time.time() - time.time()
tm1 = time.time()
# print("time:", tm1)
return tm2
def press_key_2():
global stop_threads, tm1
while True:
if not stop_threads:
break
idle_time = get_idle_duration() #seconds
# print(idle_time)
g = float("{:.2f}".format(idle_time))
st = str(g) + " / " + str(SET_IDLE_TIME)
var.set(st)
time.sleep(0.1)
if idle_time < SET_IDLE_TIME:
continue
print("in ideal state pressing cltr")
win32api.keybd_event(ord('x'), 0, win32con.KEYEVENTF_EXTENDEDKEY, 0)
tm1 = time.time()
#---------------- Monitor threads ------------------------------
t1 = threading.Thread(target=press_key_2, name='t1')
t1.daemon = True
#----------------- TK functions ----------------------
def display_on():
global tk, t1, stop_threads
stop_threads = True
print("Always On")
ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)
root.iconify()
t1.start()
# t2.start()
def display_reset():
print("quit pressed")
global stop_threads
stop_threads = False
ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
sys.exit(0)
root = tk.Tk()
root.geometry("200x110")
root.title("Devil")
frame = tk.Frame(root)
frame.pack()
var = tk.StringVar()
var_idle = tk.StringVar()
label = tk.Label(frame, textvariable = var)#, bd = 5, justify = tk.RIGHT, padx = 10, pady = 10)
label_idle = tk.Label(frame,textvariable = var_idle)
var_idle.set("Idle Time")
var.set("-")
button = tk.Button(frame,
text="Quit",
fg="red",
command=display_reset)
slogan = tk.Button(frame,
text="Always ON",
command=display_on)
label_idle.pack(side=tk.BOTTOM,padx=15, pady=13)
label.pack(side=tk.BOTTOM,padx=15, pady=5)
slogan.pack(side=tk.LEFT,padx=15, pady=5)
button.pack(side=tk.LEFT,padx=15, pady=5)
root.mainloop()
ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
To add on #luc's answer, following is how the code would be more verbose about the handle it selected when multiple windows exist:
After pip install pywin32, run
import win32gui
import re
class WindowMgr:
"""Encapsulates some calls to the winapi for window management"""
def __init__ (self):
"""Constructor"""
self._handle = None
self._handles = []
def find_window(self, class_name, window_name=None):
"""find a window by its class_name"""
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
"""Pass to win32gui.EnumWindows() to check all the opened windows"""
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
self._handles.append(hwnd)
self._handle = hwnd
def find_window_wildcard(self, wildcard):
"""find a window whose title matches the wildcard regex"""
self._handle = None
self._handles = []
win32gui.EnumWindows(self._window_enum_callback, wildcard)
self.set_handle()
def set_foreground(self):
"""put the window in the foreground"""
if self._handle != None:
win32gui.SetForegroundWindow(self._handle)
else:
print("No handle is selected, couldn't set focus")
def set_handle(self):
"""get one handle to operate on from all the matched handles"""
if len(self._handles) < 1:
print("Matched no window")
return False
if len(self._handles) > 1:
print("Selecting the first handle of multiple windows:")
else: # len(self._handles) == 1:
print("Matched a single window:")
self.print_matches()
self._handle = self._handles[0]
return True
def print_matches(self):
"""print the title of each matched handle"""
for hwnd in self._handles:
print("- " + str(win32gui.GetWindowText(hwnd)))
w = WindowMgr()
w.find_window_wildcard(".*Hello.*")
w.set_foreground()
Note: I couldn't make the addition by editing #luc's answer as its suggested edit queue is full.