0

I'm trying to learn Python and I've been having a hard time trying to understand the following problem:

My goal is to collect the value selected by the user in a combobox. Just below, I put a snippet of the program that I'm putting together. However, a doubt arose: In the PageOne Class - selected function, why does the code "list_1.append (var.get ())" works and the code "list_1 = (var.get ())" doesn't work ???

Also, in this part of the code, any manipulation of the list_1 variable is also unavailable, pointing out the error: UnboundLocalError: local variable 'list_1' referenced before assignment.

Could you help me to better understand this problem?

from tkinter import *
from tkinter import ttk

list_1 = []

class Validation_Tool(Tk):

    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)
        container = Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}

        for F in (PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("PageOne")

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

    def quit(self):
        self.destroy()

class PageOne(Frame):

        # Combobox event handler. ADDED
    def selected(self, event, var):
        # list_1=(var.get())        # DOES NOT WORK !!!!!!!!!!!!!!!!!
        list_1.append(var.get())    # IT WORKS!!!!!!!!!!!!

    def button(self, list_1):
        print(list_1)

    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller

        combobox_var = StringVar()  # ADDED.
        combobox = ttk.Combobox(self, values=list('abcde'),
                                textvar=combobox_var)  # For each Combobox. ADDED.
        combobox.grid(row=1, column=0)
        combobox.bind('<<ComboboxSelected>>',  # Bind event handler.           ADDED.
                        lambda event, var=combobox_var: self.selected(event, var))  # ADDED.

        quit_button = Button(self, text="Quit Program",
                            command=lambda: controller.quit())
        next_button = Button(self, text='Show options', command= lambda: self.button(list_1))

        quit_button.place(relx=0.98, rely=0.98, anchor=SE)
        next_button.place(relx=0.76, rely=0.98, anchor=SE)

class PageTwo(Frame):

    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller


if __name__ == "__main__":
    root = Validation_Tool()
    root.geometry('400x300+430+250')
    root.title("Validation Tool")
    root.mainloop()
Kelevra
  • 23
  • 3
  • What are you trying to do exactly? If you are trying to collect all of the user chosen options and print them on the screen, it works. If you are trying to get the user to pick only 1 option then why are you using a list for `list_1`? – TheLizzard Mar 04 '21 at 12:08
  • This code is adapted from an user that wanted to collect a list of options. What I'm trying to do is to collect only one value. In the final form, what I want is only collect the option the user selected and this value will be manipulated to form a key to search in a dictionary – Kelevra Mar 04 '21 at 13:37

1 Answers1

0

I think I fixed it:

from tkinter import ttk
import tkinter as tk


list_1 = None

class Validation_Tool(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}

        for FrameClass in (PageOne, PageTwo):
            page_name = FrameClass.__name__
            frame = FrameClass(parent=container, controller=self)
            self.frames.update({page_name: frame})

            frame.grid(row=0, column=0, sticky="news")

        self.show_frame("PageOne")

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

    def quit(self):
        self.destroy()


class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        self.combobox_var = tk.StringVar()
        self.combobox = ttk.Combobox(self, values=list("abcde"), textvar=self.combobox_var)
        self.combobox.grid(row=1, column=0)
        self.combobox.bind("<<ComboboxSelected>>", self.selected)

        quit_button = tk.Button(self, text="Quit Program", command=self.controller.quit)
        next_button = tk.Button(self, text="Show options", command=self.button)

        quit_button.place(relx=0.98, rely=0.98, anchor="se")
        next_button.place(relx=0.76, rely=0.98, anchor="se")

    def selected(self, event):
        # `list_1` need to be global as we are assigning a value to it
        global list_1
        list_1 = self.combobox_var.get()

    def button(self):
        print(list_1)


class PageTwo(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller


if __name__ == "__main__":
    root = Validation_Tool()
    root.geometry("400x300+430+250")
    root.title("Validation Tool")
    root.mainloop()

All I had to do was change the binding to:

self.combobox.bind("<<ComboboxSelected>>", self.selected)

and the method to:

def selected(self, event):
    # `list_1` need to be global as we are assigning a value to it
    global list_1
    list_1 = self.combobox_var.get()

If you want to assign a value to a global object you need to tell python to treat the object as a global variable by using global list_1. I also made your code more pythonic.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
  • Worked like a charm! Many thanks, and thanks again for rewriting the code in a more pythonic way! It helped me a lot! – Kelevra Mar 04 '21 at 17:47