-6

I'm using a function that allows the user to select an item from a list and store the index into a variable. I would like to use that variable outside the function but it's not working.

Here's what I have so far. (FYI: mylist section code is not shown)

class FirstWindow(Frame):
    selection_index = '0'
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)

         num_lines_lights = 4
         scrollbar = Scrollbar(self)
         #scrollbar.pack(side=RIGHT, fill=Y)
         scrollbar.place(x=55,y=200)
         #scrollbar.place(x=25, y=50)
         mylist = Listbox(self, yscrollcommand = scrollbar.set)
         for line in range(num_lines_lights):
             mylist.insert(END, "Light " + str(line))
         mylist.pack(side = LEFT, fill = BOTH)
         mylist.place(x=70,y=200)
         scrollbar.config(command = mylist.yview)

        def select_item(event):
            global selection_index
            widget = event.widget
            selection_index = (widget.curselection()[0])
            value = widget.get(index)
            print("Inside function %s " % selection_index) #works fine

        mylist.bind('<<ListboxSelect>>', select_item)

        print("This is return %s " % selection_index) #NOT WORKING

And here's the error I receive:

print("This is return %s " % selection_index)
NameError: name 'selection_index' is not defined
Irma
  • 19
  • 6

2 Answers2

0

because of global keyword, it is restricting the scope of the variable. Instead of global you can use self and define variable in def __init__()

def __init__(self, parent, controller):
    self.selection_index = '0'

now, instead of using selection_index use self.selection_index

Shubham Srivastava
  • 1,190
  • 14
  • 28
0

You shouldn't be trying to use global for this. One of the main reasons for using a class is so it can hold related objects in a way that makes them easy to access.

You can make selection_index an instance attribute of FirstWindow. Like this:

class FirstWindow(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.selection_index = '0'

        def select_item(event):
            widget = event.widget
            selection_index = (widget.curselection()[0])
            value = widget.get(index)
            print("Inside function %s " % self.selection_index)

        mylist.bind('<<ListboxSelect>>', select_item)

        print("This is return %s " % self.selection_index)

Of course, that will just print This is return 0 because select_item hasn't had a chance to run yet.


Here's a runnable example based on the new code you posted, which still wasn't a MCVE: I had to add extra things to make it runnable. BTW, you should not mix different layout methods (pack, place, grid) in the one container widget because they don't co-operate with one another.

I've added an extra button to demonstrate that self.selection_index is available throughout FirstWindow.

from tkinter import *

class FirstWindow(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.selection_index = '-1'

        num_lines_lights = 4
        scrollbar = Scrollbar(self)
        scrollbar.pack(side=RIGHT, fill=Y)
        mylist = Listbox(self, yscrollcommand=scrollbar.set)
        for line in range(num_lines_lights):
            mylist.insert(END, "Light " + str(line))
        mylist.pack(side=LEFT, fill=BOTH)
        scrollbar.config(command = mylist.yview)

        def select_item(event):
            widget = event.widget
            self.selection_index = (widget.curselection()[0])
            value = widget.get(self.selection_index)
            print("Inside function %s: %s" % (self.selection_index, value))

        mylist.bind('<<ListboxSelect>>', select_item)
        print("This is return %s " % self.selection_index)

        # A button to print the current selection_index
        Button(parent, text='Show index', command=self.show_index).pack()

    def show_index(self):
        print(self.selection_index)

root = Tk()
win = FirstWindow(root, root)
win.pack()
root.mainloop()

BTw, it's better to not use from tkinter import *. Instead, use

import tkinter as tk

and then you do stuff like root = tk.Tk(), scrollbar = tk.Scrollbar(self), etc. This makes the code easier to read, since it makes it clear where the imported names are coming from, and it stops Tkinter from dumping over 130 names into your global namespace, which can lead to name collisions.

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • I think the intent is probably to print when the value changes, not when the class is created. In other words, it always prints 0 at the last line – OneCricketeer Dec 13 '17 at 08:08
  • @lrma Then remove the print at the end, if that's not wanted – OneCricketeer Dec 13 '17 at 08:14
  • I'm using that print statement to try verify output. I want it to print the value of the selection. I updated the code – Irma Dec 13 '17 at 08:20
  • I want to save the selection into a variable to use it later on, but i'm not sure how to do it. The print statement is only there to verify output but it's obviously not correct – Irma Dec 13 '17 at 08:24
  • @Irma You can use `self.selection_index` later anywhere inside the class. – PM 2Ring Dec 13 '17 at 08:29
  • Thanks so much for your help. Makes sense. @PM2Ring – Irma Dec 13 '17 at 08:58
  • If I wanted to use this variable with another class, how would I got about that? – Irma Dec 13 '17 at 08:58
  • @Irma The exact details depend on how you organize your code. `.selection_index` is an attribute of the `FirstWindow` instance. In my code that instance is bound to the name `win`, and so outside of `FirstWindow` we can use `win.selection_index` to access it. – PM 2Ring Dec 13 '17 at 09:16