Home > database >  Tkinter not updating when changing variables
Tkinter not updating when changing variables

Time:01-03

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()
  • Related