Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Tkinter GUI Error

64 views
Skip to first unread message

flutte...@gmail.com

unread,
Jan 13, 2014, 1:49:07 PM1/13/14
to

Inside the function is where I am having the problem, I am trying to get it to delete the label so that it may then replace it with a shorter text.
Here is the full code:




from tkinter import *
import random
main = Tk()
main.title("Crack the Code")

def check1():
entry = entry1var.get()
if entry == num1:
labelent1.destroy()
labelent1 = Label(main, text="Correct!",fg="green").grid(row = 0, column = 3)
elif entry > num1:
labelent1.destroy()
labelent1 = Label(main, text="Too Big",fg="red").grid(row = 0, column = 3)
elif entry < num1:
labelent1.destroy()
labelent1 = Label(main, text="Too Small",fg="red").grid(row = 0, column = 3)




global num1
global num2
global num3
num1 =str(random.randint(10,99))
num2 =str(random.randint(10,99))
num3 =str(random.randint(10,99))
mastercode = num1+num2+num3


entry1var = StringVar()
entry2var = StringVar()
entry3var = StringVar()


number1 = Label(main, text="Number 1").grid(row = 0, column = 0)
number2 = Label(main, text="Number 2").grid(row = 1, column = 0)
number3 = Label(main, text="Number 3").grid(row = 2, column = 0)
entry1 = Entry(main, textvariable=entry1var).grid(row=0,column=1)
entry2 = Entry(main, textvariable=entry2var).grid(row=1,column=1)
entry3 = Entry(main, textvariable=entry3var).grid(row=2,column=1)
button1 = Button(main, text="Try Number",command=check1).grid(row=0,column=2)
button2 = Button(main, text="Try Number").grid(row=1,column=2)
button3 = Button(main, text="Try Number").grid(row=2,column=2)

labelent1 = Label(main, text="Waiting for Input").grid(row = 0, column = 3)
labelent2 = Label(main, text="Waiting for Input").grid(row = 1, column = 3)
labelent3 = Label(main, text="Waiting for Input").grid(row = 2, column = 3)



mastercodelabel= Label(main, text="Enter master code below:").grid(row=3,column=1)
mastercodeentry= Entry(main).grid(row=4,column=1)
mastercodebutton= Button(main,text="Enter").grid(row=4,column=2)




#main.config(menu=menubar)
main.mainloop()




And this is the error displayed when clicking on button1:

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "C:/Users/User/Desktop/Programming/Tkinter/Tkinter.py", line 15, in check1
labelent1.destroy()
UnboundLocalError: local variable 'labelent1' referenced before assignment


Thanks, Lewis.

Lewis Wood

unread,
Jan 13, 2014, 1:51:23 PM1/13/14
to
Forgot to mention I am using Python 3.3.3

Christian Gollwitzer

unread,
Jan 13, 2014, 2:03:42 PM1/13/14
to
Am 13.01.14 19:49, schrieb flutte...@gmail.com:
>
> Inside the function is where I am having the problem, I am trying to get it to delete the label so that it may then replace it with a shorter text.
> Here is the full code:
>
>
>
>
> from tkinter import *
> import random
> main = Tk()
> main.title("Crack the Code")
>
> def check1():
> entry = entry1var.get()
> if entry == num1:
> labelent1.destroy()
> labelent1 = Label(main, text="Correct!",fg="green").grid(row = 0, column = 3)

This is the wrong way to do it. Yes, in principle you could remove the
label and put a new one there; but it's much better to just change the
text of it by means of either

labelent1.configure(text="New text ")

or by linking a variable with the label variable at the setup time
somestringvar = StringVar("initial text")
Label(main, textvariable=somestringvar)

and then change that variable
somestringvar.set("New text")

Both of these don't solve the error, though; it has nothing to do with
Tk, you just did not make labelent1 global. However, I strongly advise
to use an object for the entire window, where you make this labelent1 an
instance variable (put into self).

Christian


Lewis Wood

unread,
Jan 13, 2014, 2:21:12 PM1/13/14
to
When I try to use the labelent1.configure, it greets me with an error:
AttributeError: 'NoneType' object has no attribute 'configure'

I changed the labelent's to global. Don't suppose you know why?
Also how would I go about using an object for the entire window. I am still a Novice at Tkinter and Python but can make my way around it.

Peter Otten

unread,
Jan 13, 2014, 2:36:53 PM1/13/14
to pytho...@python.org
flutte...@gmail.com wrote:

> Inside the function is where I am having the problem, I am trying to get
> it to delete the label so that it may then replace it with a shorter text.
> Here is the full code:

> def check1():
> entry = entry1var.get()
> if entry == num1:
> labelent1.destroy()
> labelent1 = Label(main, text="Correct!",fg="green").grid(row = 0,
> column = 3)
> elif entry > num1:
> labelent1.destroy()
> labelent1 = Label(main, text="Too Big",fg="red").grid(row = 0,
> column = 3)
> elif entry < num1:
> labelent1.destroy()
> labelent1 = Label(main, text="Too Small",fg="red").grid(row = 0,
> column = 3)

> And this is the error displayed when clicking on button1:
>
> Exception in Tkinter callback
> Traceback (most recent call last):
> File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
> return self.func(*args)
> File "C:/Users/User/Desktop/Programming/Tkinter/Tkinter.py", line 15, in
> check1
> labelent1.destroy()
> UnboundLocalError: local variable 'labelent1' referenced before assignment
>
>
> Thanks, Lewis.

Kudos, your problem description is very clear!

Your post would be perfect, had you reduced the number of Labels from three
to one ;)

The error you are seeing has nothing to do with the GUI. When you assign to
a name inside a function Python determines that the name is local to that
function. A minimal example that produces the same error is

>>> a = "global"
>>> def test():
... print(a)
... a = "local"
...
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in test
UnboundLocalError: local variable 'a' referenced before assignment

The name `a` passed to print() references the local `a` which is not yet
defined. A possible fix is to tell Python to reference the global `a`

>>> a = "global"
>>> def test():
... global a
... print(a)
... a = "local"
...
>>> test()
global
>>> a
'local'

However, in the case of your GUI code you should not destroy and create
Label instances -- it is more efficient (and easier I think) to modify the
Label's text:

(1) working demo with 'global' -- don't do it that way:

from tkinter import *

main = Tk()

def check1():
global labelent1
labelent1.destroy()
labelent1 = Label(main, text="Correct!", fg="green")
labelent1.grid(row = 0, column = 3) # must be a separate statement as
# grid() returns None

Button(main, text="Try Number", command=check1).grid(row=0, column=2)
labelent1 = Label(main, text="Waiting for Input")
labelent1.grid(row=0, column=3) # must be a separate statement as
# grid() returns None

main.mainloop()


(2) The way to go, modify the label text instead of replacing it:

from tkinter import *

main = Tk()

def check1():
labelent1.configure(text="Correct!", fg="green")

Button(main, text="Try Number", command=check1).grid(row=0, column=2)
labelent1 = Label(main, text="Waiting for Input")
labelent1.grid(row=0, column=3)

main.mainloop()

> global num1

By the way, global declarations on the module level have no effect.


Message has been deleted

Rick Johnson

unread,
Jan 13, 2014, 9:47:39 PM1/13/14
to
On Monday, January 13, 2014 12:49:07 PM UTC-6, Lewis Wood wrote:
> labelent1 = Label(main, text="Correct!",fg="green").grid(row = 0, column = 3)
>
> [snip]
>
> UnboundLocalError: local variable 'labelent1' referenced before assignment

Observe the following interactive session and prepare to be enlightened.

## INCORRECT ##
py> from Tkinter import *
py> root = Tk()
py> label = Label(root, text="Blah").pack()
py> type(label)
<type 'NoneType'>

## CORRECT ##
py> label = Label(root, text="Blah")
py> label.pack()
py> label
<Tkinter.Label instance at 0x027C69B8>
py> type(label)
<type 'instance'>

## ANY QUESTIONS? ##
py> help()

Chris Angelico

unread,
Jan 13, 2014, 10:12:01 PM1/13/14
to pytho...@python.org
On Tue, Jan 14, 2014 at 5:49 AM, <flutte...@gmail.com> wrote:
> entry = entry1var.get()
> if entry == num1:
> elif entry > num1:
> elif entry < num1:
>
> num1 =str(random.randint(10,99))
> num2 =str(random.randint(10,99))
> num3 =str(random.randint(10,99))
> mastercode = num1+num2+num3

Be careful of code like this. You've specified that your three parts
range from 10 through 99, so this will work as long as the user knows
this and enters exactly two digits. Doing inequality comparisons on
strings that represent numbers will work as long as they're the same
length, but if the lengths vary, the string comparisons will start at
the beginning - not what most people will expect. These are all true:

"2" > "10"
"3.14159" > "2,000,000"
"42" < "Life, the universe, and everything"
"00012" < "12"

If your intention is to have a six-digit number, you could simply ask
for one, and then format the pieces accordingly:

num = random.randint(1,999999)
num_str = "%06d" % num

You can then slice up num_str as needed (it'll have leading zeroes if
it needs them), or you can do numerical comparisons against num
itself.

ChrisA

Lewis Wood

unread,
Jan 14, 2014, 2:11:20 PM1/14/14
to
I cannot say how grateful I am to find such a community willing to help <3 Thanks to everyone posting, learned a lot of new stuff :) Never knew you could just bring a local var into a def block using global inside of the function. Again, thanks for taking your time to help out newbies to programming such as myself.

Lewis Wood

unread,
Jan 14, 2014, 4:27:29 PM1/14/14
to
Also anyone know how to create an entry box for Tkinter where you can only enter in 2 digits?

Christian Gollwitzer

unread,
Jan 14, 2014, 4:33:23 PM1/14/14
to
Am 14.01.14 22:27, schrieb Lewis Wood:
> Also anyone know how to create an entry box for Tkinter where you can only enter in 2 digits?
>
You must use a validator to achieve this. This is a more advanced topic
though. A validator is a function that is called whenever the user keys
something in - even by copy/pasting - and has to decide, whether this
change is accepted or not. It is relatively easy to annoy your users if
the validator is not written carefully. For instance, you must always
accept th eempty string, otherwise the users won't be able to delete
everything - very annoying behaviour.

See for example this SO question

http://stackoverflow.com/questions/4140437/python-tkinter-interactively-validating-entry-widget-content

Christian
0 new messages