Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
not updating
#1
:I Wall Wall
import tkinter as tk
window = tk.Tk()

score = 0

def click():
  score += 1
  score_display.config(text=score)

score_display = tk.Label(text=score)
score_display.pack()
button = tk.Button(text='Click me!', command=click)
score_display.pack()

window.mainloop()
Reply
#2
When a function assigns a value to a variable, it creates a local variable. score in line 7 is not the same score in line 4. Score in line 7 only exists in the function and gets created each time the function is called. There is no way to accumulate clicks because score keeps getting created and destroyed each time clink is called. In fact, line 7 raises an exception when click() is called. Tkinter hides that from you. You could use “ global score” in click() to fix, but I think a better solution is to make score a IntVar.
Reply
#3
Also line 13 score_display.pack() should be button.pack()
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#4
import tkinter as tk
window = tk.Tk()
 
score = 0
 
def click():
  global score # <- allows updating varibales on module level
  # if this is missing, it's a UnboundLocalError
  # The use of globals is bad
  score += 1
  score_display.config(text=score)
 
score_display = tk.Label(text=score)
score_display.pack()
button = tk.Button(text='Click me!', command=click)
button.pack() # <-- this was missing
score_display.pack()
 
window.mainloop()
A slightly better version:
import tkinter as tk

 
class Score:
    """
    Simple class to avoid the use of globals
    """
    def __init__(self, score_display):
        self.score = 0
        self.score_display = score_display

    def click(self):
       self.score += 1
       score_display.config(text=self.score)


window = tk.Tk()
score_display = tk.Label(text="0")
score_display.pack()
score = Score(score_display) # <- keep the instance of score_display and score
button = tk.Button(text='Click me!', command=score.click) # <- using the method score to update the score
button.pack() # <-- this was missing
score_display.pack()

tk.Button(window, text="Close", command=window.destroy).pack()

window.mainloop()
You can use also use IntVar from tkinter.
Updated code:
import tkinter as tk

 
class Score:
    """
    Simple class to avoid the use of globals
    """
    def __init__(self, score_variable: tk.IntVar):
        self.score = score_variable

    def click(self):
        self.score.set(self.score.get() + 1)

window = tk.Tk()
score_variable = tk.IntVar(window)
score_display = tk.Label(textvariable=score_variable) # <- the us of textvariable instead of text
# if score_variable changes, the score_display is updated automatically
score_display.pack()
score = Score(score_variable) # <- keep the instance of score_variable
button = tk.Button(text='Click me!', command=score.click) # <- using the method score to update the score
button.pack() # <-- this was missing
score_display.pack()

tk.Button(window, text="Close", command=window.destroy).pack()
tk.IntVar()
window.mainloop()
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#5
I would use IntVar in a slightly different way. This code subclasses IntVar to make an IntVar that has a click() method.
import tkinter as tk

class Score(tk.IntVar):
    """Add click() method to IntVar class."""

    def click(self):
        self.set(self.get() + 1)

window = tk.Tk()
score_variable = Score(window)
score_display = tk.Label(textvariable=score_variable)
score_display.pack()
button = tk.Button(text="Click me!", command=score_variable.click)
button.pack()
score_display.pack()
window.mainloop()
But you can also just make a global IntVar and use it like this.
import tkinter as tk


def clicked():
    score.set(score.get() + 1)


window = tk.Tk()
score = tk.IntVar(window, 0)
score_display = tk.Label(textvariable=score)
score_display.pack()
button = tk.Button(text="Click me!", command=clicked)
button.pack()
score_display.pack()
window.mainloop()
In this code the "score" in line 5 is the same "score" as in lines 9 and 10. Because there is not assignment in "clicked()", python does not create any local variables for the function. When clicked() executes it looks for a variable named "score" in the local variables, doesn't find one, and looks for a global variable named "score".

Takeaways:
assignment (=) creates variables in python. When the python code parser encounters an assignment, it creates a variable in the local scope.

global name circumvents the creation of local variables. When a function has "global name" it does not create a local variable with that name.

When a variable is encountered in a function, python first looks for a local variable with that name. If it doesn't find a matching local variable it looks for a matching global variable. If there is not a matching global variable, python looks for the variable in the builtins (built in functions like print, list...). There is an additional scope named "enclosed" that sits between local and global.

 Global variables should be avoided. Because global variables can be seen by everything in the module, changes that affect the use of global variables require a code review of all code in the module.
DeaD_EyE likes this post
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020