-3

Below is a part of the code used in the app I'm building for my current employment. when the following code is ran, I receive the error stated in the title of this post. The code for the tkinter wizard is pulled from http://mail.python.org/pipermail/tutor/2005-May/038686.html. I've run the code in its own window and it works, but when I place the code in my app it runs into the aforementioned error.

So, here's my question: What is going on, and how can I fix it?

from tkinter import *

#Start Code for the Introduction Wizard
def wizIntro():
    wizIntro = tkinter.Tk()



    #Title:
    wizIntro.title('Welcome to Training')

    #Content:
    page1 = Frame(wizIntro)
    Label(page1, text='', width=110).pack()
    Label(page1, text='--Welcome to Training--', width=85).pack()
    Label(page1, text='', width=85).pack()
    Label(page1, text='This tutorial will help you familiarize yourself with the program.  Following it is key to understanding', width=85).pack()
    Label(page1, text='the proper operation of the Laser Cutter.', width=85).pack()
    Label(page1, text='', width=90).pack()
    Label(page1, text='It is also important to follow every insrtuction exactly as stated, to avoid or minimize damage to the Laser', width=85).pack()
    Label(page1, text='Cutter and reduce the risk of injury to the operator and those around him.', width=85).pack()
    Label(page1, text='Therefore, all safety notices must be followed with extreme care.', width=110).pack()
    Label(page1, text='--Failure to follow all safety notices poses a severe risk of damage to the equipment and to the operator, which can be fatal--', width=110, fg='red').pack()
    Label(page1, text='', width=110).pack()
    Label(page1, text='Click Next to Continue...', width=110).pack()
    page1.pack()

    page2 = Frame(wizIntro)
    Label(page2, text='', width=110).pack()

    #Commands:
    pages = [page1, page2]
    current = page1
    def move(dirn):
        global current
        idx = pages.index(current) + dirn
        if not 0 <= idx < len(pages):
            return
        current = pages[idx]
        current.pack_forget()
        current.pack(side = TOP)

    def nex():
        move(+1)

    def prev():
        move(-1)

    Button(wizIntro, text='Previous', command=prev).pack(side = LEFT)
    Button(wizIntro, text='Next', command=nex).pack(side = RIGHT)

#End Code for the Introduction Wizard
jdlunt0313
  • 3
  • 2
  • 5
  • Please define more precisely what you want to get and what obstacles have you encountered and failed to overcome. – Vladimir Mar 18 '13 at 17:46
  • Can you copy and paste the full traceback of the exception into the question? That should narrow down where in the code the error is happening. – Blckknght Mar 18 '13 at 17:46
  • @Blckknght Exception in Tkinter callback Traceback (most recent call last): File "C:\Python33\lib\tkinter\__init__.py", line 1442, in __call__ return self.func(*args) File "I:\Documents\Python Projects\CS-LC0001.py", line 54, in nex move(+1) File "I:\Documents\Python Projects\CS-LC0001.py", line 46, in move idx = pages.index(current) + dirn NameError: global name 'current' is not defined – jdlunt0313 Mar 18 '13 at 17:50
  • @Vladimir I'm working to create a tutorial for training on a laser cutter, and this is the first of the tutorials, hopefully to be set up in Wizard Format. However, I'm running into this error (posted above this comment). I've run the same code (minus revisions to displayed text and desired width) in a separate project file and it ran without any problems. – jdlunt0313 Mar 18 '13 at 17:53
  • Please fix the indentation in the post. – wRAR Mar 18 '13 at 17:58
  • Let me know if that works for you @wRAR – jdlunt0313 Mar 18 '13 at 18:03

3 Answers3

1

I'm not sure if this is your problem, but it definitely is at least a related problem:

current = page1
def move(dirn):
    global current

These two current variables do not refer to the same thing. The first one is a local variable in the function wizintro. The second is a global variable.

The reason for this specific error, as opposed to a different one, is this line:

idx = pages.index(current) + dirn

You're referencing a variable named current. You've said that it's global, but you've never assigned any value to it in the global scope. So, it's undefined. So you get an exception.

If you just remove the global current line, then they refer to local variables in two different functions, which still probably isn't what you want. The same line will give effectively the same error—now it's a local variable that you're using without having assigned it any value in the local scope, but that's not any better.

It's pretty clear that you want move to refer to the current from the outer scope.

If you're using Python 3.x, nonlocal current is probably what you're after.

If not, there are a few options.

You can use the "mutable default parameter value" trick. Replace current with, say, a list of one element (current=[page1]), then pass current=current as an extra parameter to move. As long as nobody overrides the default, move will have a local variable named current that, despite not being the same variable as the one in the outer scope, is a reference to the same value, so current[0] is the same variable. (There are different tricks to bind a local variable into a closure that may feel more friendly to people coming from a Scheme/Haskell/etc. background, but the effect is the same.)

Or you can just make current a global in both scopes.

Or, go the opposite direction: turn wizintro into a class, move and friends into methods, and current into an instance variable. This really seems like what you're going for here.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • I removed the line "global current" and it gave me the following error: Exception in Tkinter callback Traceback (most recent call last): File "C:\Python33\lib\tkinter\__init__.py", line 1442, in __call__ return self.func(*args) File "I:\Documents\Python Projects\CS-LC0001.py", line 53, in nex move(+1) File "I:\Documents\Python Projects\CS-LC0001.py", line 45, in move idx = pages.index(current) + dirn UnboundLocalError: local variable 'current' referenced before assignment – jdlunt0313 Mar 18 '13 at 18:11
  • @user2169633: Yes, because if you remove `global current`, then they're both referring to different local variables from different scopes. You have to actually do one of the things suggested in the answer to solve the problem. – abarnert Mar 18 '13 at 18:12
  • Removing the line "current = page1" didn't fix the problem either. I still get the original error this way. – jdlunt0313 Mar 18 '13 at 18:15
  • I'm not sure what you are saying. Am I to remove the above portion of code altogether, or are you saying something else? – jdlunt0313 Mar 18 '13 at 18:16
  • @user2169633: Why do you think removing random lines of code is going to fix the problem? You can't do `idx = pages.index(current)` without having either defined `current` locally, or pulled it in from some other scope. Otherwise, what value could it possibly have? – abarnert Mar 18 '13 at 18:17
  • @user2169633: Well, yes, removing all of your code will make your errors go away, but presumably that's not what you want. I gave you four different ways you can reference the same `current` from `wizintro` inside the `move` function. You have to actually do one of those four things. – abarnert Mar 18 '13 at 18:18
  • @abarnet Thank you for your answer! Using "nonlocal" instead of "global" did the trick, and yes, I'm on python 3.3.0. Thanks again. – jdlunt0313 Mar 18 '13 at 18:23
0

You cannot use global to change a non-global variable from an outer scope, only to change a global (module-level) variable. Python 3.x has nonlocal for that. Consider changing your logic.

wRAR
  • 25,009
  • 4
  • 84
  • 97
0

The trouble you're having is because current is not a global variable, but rather a local variable in your wizIntro function. Your nested function move tries to access it, but it's global statement doesn't find the value in the global namespace. This means that when you try to access it later, you get a NameError.

If you're using Python 2, you don't have any good way to access variables of an outer function's namespace from within a nested function. I think the best you could do is declare current to be global in wizIntro (before you first assign to it). Python 3 introduces the nonlocal keyword that can work with the current structure (just replace your current global statement.

Blckknght
  • 100,903
  • 11
  • 120
  • 169