I'm tinkering with Tkinter and trying to check if my program is open on pressing a button, but the Tkinter is not updating my label. Why?
from win32gui import GetWindowRect, FindWindow
from tkinter import Tk, ttk, BooleanVar
class Bot:
root = Tk()
is_gta_open = BooleanVar(None, False)
def mta_open_string(self):
return "włączone" if self.is_gta_open.get() else "wyłączone"
def draw_gui(self):
frame = ttk.Frame(self.root, padding=10)
frame.grid()
ttk.Label(frame, text=f"Status gry: {self.mta_open_string()}").grid(column=0, row=0)
ttk.Button(frame, text="Odśwież", command=lambda: [self.try_finding_rect(), self.root.update()]).grid(column=1, row=0)
self.root.mainloop()
def try_finding_rect(self):
window_handle = FindWindow("Grand theft auto San Andreas", None)
if window_handle == 0:
self.is_gta_open.set(False)
return
self.is_gta_open.set(True)
def run(self):
self.try_finding_rect()
self.draw_gui()
if __name__ == "__main__":
Bot().run()
I'm updating the state using self.root.update
method and using BooleanVar
, so I don't know why this is not working.
CodePudding user response:
Updating a variable won't change an f-string that uses the variable. You must explicitly configure the widget to show the new value.
To do that you'll need to keep a reference to the label widget, and then update the widget with the configure
method.
def draw_gui(self):
...
self.status_label = ttk.Label(frame, text=f"Status gry: {self.mta_open_string()}")
self.status_label.grid(column=0, row=0)
...
def try_finding_rect(self):
...
self.is_gta_open.set(True)
self.status_label.configure(text=f"Status gry: {self.mta_open_string()}")
Personally I recommend using a proper method for the button rather than a complicated lambda. That will make the code easier to read and easier to debug.
For example:
def draw_gui(self):
...
ttk.Button(frame, text="Odśwież", command=self.update_status)
...
def update_status(self):
self.try_finding_rect(),
self.status_label.configure(text=f"Status gry: {self.mta_open_string()}")
CodePudding user response:
I've put together a very minimal example app that should work as intended. I don't have a copy of GTA to test with so I used a different app, but it should function the same way with any app in principle:
import tkinter as tk
import ctypes
from tkinter import ttk
class Bot(tk.Tk): # init Tk
def __init__(self):
super.__init___()
APP_NAME = 'Grand theft auto San Andreas'
self.status_label = tk.Label(self, text='Press the button')
self.status_label.pack()
self.run_btn = ttk.Button(
self,
text='Click Me!',
command=lambda: self.check_for_app(APP_NAME)
)
self.run_btn.pack()
def check_for_app(app_name: str):
user32 = ctypes.WinDLL('user32')
if user32.FindWindowW(None, app_name):
self.status_label.config(text='Running')
else:
self.status_label.config(text='Not Running')
if __name__ == '__main__':
app = Bot()
app.mainloop()