0

i want to return the selected item from a listbox from one module into another. Inside A.py i call a function from B.py which creates a small tkinter listbox. Within this listbox i want to select an item, and return it as a value to A.py.

I tried several things, i.e.

# inside A.py
import B

filter = B.get_pt_filter()

and

# inside B.py
from tkinter import * # (i know this is not clean, but let's keep it this way for now)
from functools import partial


def button_click(lb):    
    return lb.get(lb.curselection())

def get_pt_filter():
    pt_list = define_pt_list()
    # create window
    tk_window = Tk()
    tk_window.title('Choose')
    tk_window.geometry('350x400')
    # listbox border
    frame_listbox = Frame(master=tk_window, bg='#FFCFC9')
    frame_listbox.place(x=5, y=5, width=335, height=360)
    # button border
    frame_button = Frame(master=tk_window, bg='#D5E88F')
    frame_button.place(x=5, y=370, width=335, height=30)
    # Listbox
    lb = Listbox(master=frame_listbox, selectmode='browse')
    for pt in pt_list:
        lb.insert('end', pt)
        lb.place(x=5, y=5, width=325, height=350)
    # Label Text
    labelText = Label(master=frame_button, bg='white')
    labelText.place(x=5, y=5, width=325, height=20)
    # button_choose = Button(master=frame_button, text='Choose', command= lambda: button_click(lb))
    action_with_arg = partial(button_click, lb)
    button_choose = Button(master=frame_button, text='Choose', command=action_with_arg)
    button_choose .place(x=5, y=5, width=325, height=20)
    # Aktivierung des Fensters
    tk_window.wait_window()

def define_pt_list():
    return [
        'apple'
    ]

So far i get the value i want in button_click but i fail to return it to module A.py and assign it to filter. How would i do that? What am i missing here?

I've tried several things including a return button_choose at the end of get_pt_filter or lambda functions behind command while creating Button. I can not break the Loop however, and i'm stuck forever it seems like. Also i tried tk_window.mainloop() and tk_window.wait_window(). None of those work.

In Short: How do i assign "apple" to filter?

Ougaga
  • 127
  • 1
  • 9

1 Answers1

1

So the problem here is that although lb.get(lb.curselection()) does actually evaluate to "apple", button_click has nowhere to return that value. You can verify this by having the button_click function printing instead of returning. In order to use as much of the code you've already written i suggests that you create a global variable in button_click, e.g.:

def button_click(lb):
    global selection
    selection = lb.get(lb.curselection())

Then you can access the variable selection in get_pt_filter and thus return it from there with return selection.

To make sure that the 'choose'-button actually closes the window, you should make the 'root' global as well:

global tk_window
tk_window = Tk()

and finish button_click of with tk_window.quit(), so the function ends up looking like this:

def button_click(lb):   
    global selection
    selection = lb.get(lb.curselection())
    tk_window.quit()

Also replace tk_window.wait_window() with tk_window.mainloop().

This is a bit of a hacky solution, but it fits the code you already wrote.

A better solution would be to store the application in a class that has it's own variables that can be accessed by button_click. Have a look at this thread. I suggest the following application to accomplish what you need without using global:

from tkinter import *

class get_pt_filter:
    def __init__(self, parent, pt_list):
        # create window
        self.tk_window = parent
        self.tk_window.title('Choose')
        self.tk_window.geometry('350x400')
        # listbox border
        frame_listbox = Frame(master=self.tk_window, bg='#FFCFC9')
        frame_listbox.place(x=5, y=5, width=335, height=360)
        # button border
        frame_button = Frame(master=self.tk_window, bg='#D5E88F')
        frame_button.place(x=5, y=370, width=335, height=30)
        # Listbox
        self.lb = Listbox(master=frame_listbox, selectmode='browse')
        for pt in pt_list:
            self.lb.insert('end', pt)
            self.lb.place(x=5, y=5, width=325, height=350)
        # Label Text
        labelText = Label(master=frame_button, bg='white')
        labelText.place(x=5, y=5, width=325, height=20)
        button_choose = Button(master=frame_button, text='Choose', command=self.button_click)
        button_choose.place(x=5, y=5, width=325, height=20)

    def button_click(self):   
        self.selection = self.lb.get(self.lb.curselection())
        self.tk_window.quit()

if __name__ == "__main__":
    parent = Tk()
    get = get_pt_filter(parent, ['apple', 'pear'])
    # Aktivierung des Fensters
    parent.mainloop()

    #access the selection
    print(get.selection)

When mainloop quits you can access the selection varaible of the instance.

  • Thanks, this one is working so far. Although it is indeed a bit hacky - there must be a solution without globals aswell, no?! Anyways, upvoted and accepted for presenting a solution. – Ougaga Mar 26 '20 at 07:30
  • Typically you would structure your tkinter application in a class. This way you can have `button_click` change a variable in the class instance. [This thread](https://stackoverflow.com/questions/17466561/best-way-to-structure-a-tkinter-application) might be able to clarify how an application can be structured. – Sebastian Baltser Mar 26 '20 at 08:17