injaon
injaon

Reputation: 243

How to trigger changes in button in a comand in Tkinter?

I'm new to TKinter. I need to change the text of a button and its state when its clicked, then do some actions, and finally change again its text and state.

The problem is the changes only apply once the function has ended, skipping the first change of state and text. It never changes the Buttons text to "loading" and the button is never disabled.

Here is the code for the problem i'm experiencing:

#!/usr/bin/env python
import tkinter as tk
import time


class Application(tk.Frame):

    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack(fill=tk.BOTH, expand=1)
        self.create_widgets()

    def create_widgets(self):
        self.master.title("CW POS")

        cierre = tk.Button(
            self.master,
            command=self.re_imprimir_ultimo_cierre)

        cierre["text"] = "foo"
        cierre.pack(fill=tk.BOTH, expand=1)
        self._cierre = cierre

        salir = tk.Button(self.master, text="quit", command=self.salir)
        salir.pack(fill=tk.BOTH, expand=1)


    def salir(self):
        exit()

    def re_imprimir_ultimo_cierre(self):
        self._cierre["text"] = "Loading..."
        self._cierre["state"] = tk.DISABLED

        # TODO: magic
        time.sleep(2)

        self._cierre["text"] = "foo"
        self._cierre["state"] = tk.NORMAL



root = tk.Tk()
root.geometry("240x180")
root.resizable(False, False)
app = Application(root)
root.mainloop()

How do I make the button show text="loading" and state=DISABLED, while the button is doing my calculations?

Upvotes: 1

Views: 273

Answers (1)

MatthewG
MatthewG

Reputation: 815

There is a pretty quick fix to this problem, you just need to update the button, once you change it's text to "Loading" (self._cierre["text"] = "Loading...")

    def re_imprimir_ultimo_cierre(self):
        self._cierre["text"] = "Loading..."
        self._cierre["state"] = tk.DISABLED

        self._cierre.update() # This is the line I added

        # TODO: magic
        time.sleep(2)

        self._cierre["text"] = "foo"
        self._cierre["state"] = tk.NORMAL

This just simply updates the buttons state after you change the text and state.

From what I understand this is because a button will run all the code within its command, before updating anything on the screen, so you essentially have to force the button to update itself within its command.

Hope this helps :)

Upvotes: 1

Related Questions