Jack Elsey
Jack Elsey

Reputation: 134

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.

Upvotes: 4

Views: 10973

Answers (3)

Victor Domingos
Victor Domingos

Reputation: 1093

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().

Upvotes: 2

user4171906
user4171906

Reputation:

but I'm trying to keep things simple because I'm new to Python Hopefully this helps in understanding that classes are the simple way, otherwise you have to jump through hoops and manually keep track of many variables. Also, the Python Style Guide suggests that CamelCase is used for class names and lower_case_with_underlines for variables and functions. https://www.python.org/dev/peps/pep-0008/

from tkinter import *
from tkinter import ttk

class ChangeLabel():
    def __init__(self):
        root = Tk()
        self.my_label = ttk.Label(root, text = 'The button has not been pressed.')
        self.my_label.pack()
        ## not necessary to keep a reference to this button
        ## because it is not referenced anywhere else
        ttk.Button(root, text = 'Press Me',
               command = self.change_label_text).pack()
        root.mainloop()

    def change_label_text(self):
        self.my_label.config(text = 'You pressed the button!')

if __name__ == "__main__":
    CL=ChangeLabel()

Upvotes: 1

Billal BEGUERADJ
Billal BEGUERADJ

Reputation: 22804

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

Upvotes: 4

Related Questions