Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter - Changing label text via another function

I know that it's often best practice to write Tkinter GUI code using object-oriented programming (OOP), but I'm trying to keep things simple because I'm new to Python.

I have written the following code to create a simple GUI:

#!/usr/bin/python3
from tkinter import *
from tkinter import ttk

def ChangeLabelText():
    MyLabel.config(text = 'You pressed the button!')

def main():
    Root = Tk()
    MyLabel = ttk.Label(Root, text = 'The button has not been pressed.')
    MyLabel.pack()
    MyButton = ttk.Button(Root, text = 'Press Me', command = ChangeLabelText)
    MyButton.pack()
    Root.mainloop()

if __name__ == "__main__": main()

The GUI looks like this.

I thought the text in the GUI (MyLabel) would change to "You pressed the button!" when the button is clicked, but I get the following error when I click the button:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\elsey\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1549, in __call__
    return self.func(*args)
  File "C:/Users/elsey/Documents/question code.py", line 6, in ChangeLabelText
    MyLabel.config(text = 'You pressed the button!')
NameError: name 'MyLabel' is not defined

What am I doing wrong? Any guidance would be appreciated.

like image 968
Jack Elsey Avatar asked Mar 12 '23 10:03

Jack Elsey


2 Answers

MyLabel is local to main() so the way you can not access it that way from ChangeLabelText().

If you do not want to change the design of your program, then you will need to change the definition of ChangeLabelText() like what follows:

def ChangeLabelText(m):
    m.config(text = 'You pressed the button!')

And withing main() you will need to pass MyLabel as an argument to ChangeLabelText().

But again, you will have a problem if you code this command = ChangeLabelText(MyLabel) when you declare and define MyButton because the program will execute directly the body of ChangeLabelText() at the start and you will not have the desired result.

To resolve this later problem, you will have to use (and may be read about) lambda

Full program

So your program becomes:

#!/usr/bin/python3
from tkinter import *
from tkinter import ttk

def ChangeLabelText(m):
    m.config(text = 'You pressed the button!')

def main():
    Root = Tk()
    MyLabel = ttk.Label(Root, text = 'The button has not been pressed.')
    MyLabel.pack()
    MyButton = ttk.Button(Root, text = 'Press Me', command = lambda: ChangeLabelText(MyLabel))
    MyButton.pack()
    Root.mainloop()

if __name__ == "__main__": 
  main()

Demo

Before clicking:

enter image description here

After clicking:

enter image description here

like image 123
Billal Begueradj Avatar answered Mar 15 '23 00:03

Billal Begueradj


Are your sure you don't want to do it as a class (i think it makes the code a bit more clean as your project grows)? Here is a way to accomplish what you'e looking for:

#!/usr/bin/python3
from tkinter import *
from tkinter import ttk


class myWindow:
    def __init__(self, master):
        self.MyLabel = ttk.Label(root, text = 'The button has not been pressed.')
        self.MyLabel.pack()
        self.MyButton = ttk.Button(root, text = 'Press Me', command = self.ChangeLabelText)
        self.MyButton.pack()

    def ChangeLabelText(self, event=None):
        self.MyLabel.config(text = 'You pressed the button!')


if __name__ == "__main__": 
    root = Tk()
    mainWindow = myWindow(root)
    root.mainloop()

In a Mac, is looks like this before pressing the button:

enter image description here

And when you press it:

enter image description here

But basically, in order to be able to change the text in a Label or a button, you need to ensure it has an active reference. In this case, we are doing it by creating the window as a class and referencing the widgets in the form self. widget_name = widget().

like image 40
Victor Domingos Avatar answered Mar 15 '23 00:03

Victor Domingos