Home > OS >  Why the Label is not changing with StringVar in this code? (tkinter)
Why the Label is not changing with StringVar in this code? (tkinter)

Time:08-25

code enviroment:python 3.x

Here is my code:

import tkinter as tk


def abc():
    global Labelvar
    Labelvar = tk.StringVar()
    Labelvar.set('abc')
    
def xyz():
    global Labelvar
    Labelvar = tk.StringVar()
    Labelvar.set('xyz')

class Application(tk.Tk):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.geometry('300x350')
        self.show()

    def show(self, labelvar=None):
        bnt1 = tk.Button(self, text='a', command=abc)
        bnt1.place(x=0, y=0)
        bnt2 = tk.Button(self, text='b', command=xyz)
        bnt2.place(x=0, y=50)
        label1 = tk.Label(self, textvariable=labelvar)
        label1.place(x=0, y=100)


if __name__ == '__main__':
    app = Application()
    app.mainloop()

When i push the buttons, there is no responce with the Label,how i can i fix the problem?

Thank you.

CodePudding user response:

Because you are mixing OO programming with procedural programming and using global variables that you know are like the devil in addition to having named the variable assigned to the label once as Labelvar and the other as labelvar, among other things outside the class.... However I attach you a script OO, as is in part yours, to show you how to proceed, the variable to be assigned to the textvariable you must declare it in the init of the class to make it visible to all the methods of the class itself. I raised palce() as unless of very particular things it is never used.

#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox


class App(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Simple App")

        self.geometry('200x100')

        self.protocol("WM_DELETE_WINDOW", self.on_close)

        self.lablevar = tk.StringVar()

        self.lablevar.set("Hello World!")

        self.init_ui()

    def init_ui(self):

        f = ttk.Frame(self)

        self.my_label = ttk.Label(f, textvariable=self.lablevar)
        self.my_label.pack()

        ttk.Button(f, text="A", command=self.set_label_value).pack()
        ttk.Button(f, text="B", command=self.set_another_label_value).pack()
        ttk.Button(f, text="Close", command=self.on_close).pack()

        
        f.pack(fill=tk.BOTH, expand=0)

    def set_label_value(self,):
        self.lablevar.set("Ciao Mondo!")

    def set_another_label_value(self,):
        self.lablevar.set("Hola Mundo!")        

                
    def on_close(self, evt=None):

        msg = "Do you want to quit?"
        if messagebox.askokcancel(self.title(), msg, parent=self):
            self.destroy()

def main():
    app = App()
    app.mainloop()

if __name__ == '__main__':
    main()            
    

CodePudding user response:

This is the code you execute immediately by running your Script.

class Application(tk.Tk): 
    def __init__(self):
        super(self.__class__, self).__init__() 
        self.geometry('300x350')
        self.show()

    def show(self, labelvar=None): 
        bnt1 = tk.Button(self, text='a', command=abc) 
        bnt1.place(x=0, y=0) 
        bnt2 = tk.Button(self, text='b', command=xyz) 
        bnt2.place(x=0, y=50) 
        label1 = tk.Label(self, textvariable=labelvar) 
        label1.place(x=0, y=100) 
if __name__ == '__main__': 
    app = Application()
    app.mainloop()

If you read that code line by line, from top to bottom and from left to right. You will find a definition of a class and when you run this script as main you will initiate the class, therefore the __init__ method runs.

Then you have a call to super that contains unnecessary arguments for python 3.x.and can be shortened to be super().__init__(). After positioning your window you call the method show of your class without arguments. By calling the method without arguments the default parameter is used, which is None.So your definition of label1 becomes effectively tk.Label(self, textvariable=None)

The solution to this problem is somewhat arbitrary and should depend on what you do in the future. If you just want to access this variable inside your class, this is what the self parameter is for, it gives you a reference to your instance. If you want to have it globally available, you could use the expression global or just define a variable in the global namespace.

So everything you want to share among the instance or just to keep a reference in it. You can bound/set this these attributes like self.labelvar = xy.

My suggestion to solve your problem would be:

class Application(tk.Tk): 
    def __init__(self):
        super().__init__() 
        self.geometry('300x350')
        self.labelvar = tk.StringVar()
        self.show()

    def show(self): 
        bnt1 = tk.Button(self, text='a', command=abc) 
        bnt1.place(x=0, y=0) 
        bnt2 = tk.Button(self, text='b', command=xyz) 
        bnt2.place(x=0, y=50) 
        label1 = tk.Label(self, textvariable=self.labelvar) 
        label1.place(x=0, y=100) 
if __name__ == '__main__': 
    app = Application()
    app.mainloop()

For those free function you have defined in the global namespace. You could either decide to bound them to your instance by putting them in the namespace of your class and add the parameter self to them like:

def abc(self): 
    self.labelvar.set('abc') 
def xyz(self): 
    self.labelvar.set('xyz')

Or you decide to leave them in the global namespace and use the expression global on the labelvar or define the labelvar in the global namespace.

  • Related