Home > Net >  How to show every change to an class object in Tkinter?
How to show every change to an class object in Tkinter?

Time:09-27

I have this skeleton of a game in two files.

First file mygui.py:

from tkinter import Tk, Label, Button
from mygame import p1, play_game

def rungame():
    play_game()
    gui_widgets()

root = Tk()

def gui_widgets():
    health_label = Label(root, text=f"health: {p1.health}")
    health_label.grid(column=0, row=0)

    mana_label = Label(root, text=f"mana: {p1.mana}")
    mana_label.grid(column=0, row=1)

    mybtn = Button(root, text="RUN GAME", command=rungame)
    mybtn.grid(column=0, row=2)

gui_widgets()
root.mainloop()

Seccond file mygame:

import time

class Player:

    def __init__(self, health, mana):
        self.health = health
        self.mana = mana

def play_game():
    p1.health -= 1
    time.sleep(0.5)
    p1.mana -= 3
    time.sleep(0.5)
    p1.mana  = 1

p1 = Player(10, 15)

The game shows the begining statistic on gui and after clicking button it shows the end result. I want gui to show every p1 atribute change made in play_game() as they are happening. How would I do this?

Edit: I am keen on keeping two seperate files so that program would be more scalable.

I am not sure if this is possible, but I would figure that if I could run gui_widgets() continuosly (for example every 0,1 secconds) It would probalby work as intended. Still I understand that this may be impossible since tkinter seems to wait everytime when play_game()is running, witch takes at least one seccond to finish. So in that case they should probalby run alongside each other (if that even is a thing).

CodePudding user response:

There maybe lot of ways for it.

Here's one way

  • Define __setattr__ method to send signal to buffer to update GUI.
  • sleep in main thread may block your GUI to update, so another thread used here.
  • A fixed and short timer to fresh/update GUI from the content of buffer.
# mygui.py
import threading
from tkinter import Tk, Label, Button

from mygame import p1, play_game, buffer


def rungame():
    threading.Thread(target=play_game, args=(), daemon=True).start()

def update():

    if buffer:
        attribute, value = buffer.pop(0)
        if attribute == 'health':
            health_label.configure(text=f"health: {value}")
            health_label.update()
        elif attribute == 'mana':
            mana_label.configure(text=f'mana: {value}')
            mana_label.update()
    root.after(100, update)

def gui_widgets():

    health_label = Label(root, text=f"health:", width=20)
    health_label.grid(column=0, row=0)
    mana_label = Label(root, text=f"mana:", width=20)
    mana_label.grid(column=0, row=1)
    mybtn = Button(root, text="RUN GAME", command=rungame)
    mybtn.grid(column=0, row=2)
    return health_label, mana_label

root = Tk()

health_label, mana_label = gui_widgets()

root.after(100, update)
root.mainloop()
#my game.py
import time

class Player(object):

    def __init__(self, health, mana):
        self.health = health
        self.mana = mana

    def __setattr__(self, attribute, value):
        super().__setattr__(attribute, value)
        buffer.append((attribute, value))

def play_game():

    for i in range(10):
        p1.health = i
        time.sleep(0.2)
        p1.mana = 9 - i
        time.sleep(0.2)

buffer = []
p1 = Player(10, 15)
  • Related