2

I am trying understand how to return a list from a function that is used when the user uses the mouse key to move an item in the box on the left to the box on the right. I am trying to capture the items in the box in the right as a list but need that list outside of the function.

So I am trying to return the list (current_list) from the select_events function. It's capturing the list in the function but I need to use it outside. I am struggling to understand how to use the return to do this

from tkinter import *
from tkinter import ttk

my_window = Tk()

my_frame_in = Frame(my_window)
my_frame_in.grid(row=0, column=0)
my_frame_out = Frame(my_window)
my_frame_out.grid(row=0, column=1)

listbox_events = Listbox(my_frame_in, height='5')
listbox_events.grid(row=0, column=0, padx=10, pady=10)
listbox_events_filtered = Listbox(my_frame_out, height='5')
listbox_events_filtered.grid(row=0, column=2, padx=(0, 10), pady=10)
my_instructions = Label(my_window, text='Use arrow keys to move selected items')
my_instructions.grid(row=1, column=0, columnspan=3, pady=(0, 10))

my_list_events = ['A', 'B', 'C', 'D']

for item in my_list_events:
    listbox_events.insert(END, item)

global current_list


def select_events(event=None):
#    current_list = []
    listbox_events_filtered.insert(END, listbox_events.get(ANCHOR))
    listbox_events.delete(ANCHOR)
    current_list = list(listbox_events_filtered.get(0, END))
    print(current_list)
    return current_list


print(current_list)


def deselect_events(event=None):
#    current_list = []
    listbox_events.insert(END, listbox_events_filtered.get(ANCHOR))
    listbox_events_filtered.delete(ANCHOR)
    current_list = list(listbox_events_filtered.get(0, END))


listbox_events.bind('<Right>', select_events)
listbox_events_filtered.bind('<Left>', deselect_events)

mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
Sid
  • 153
  • 3
  • 15
  • Return the list to what caller? – martineau May 01 '20 at 16:34
  • I dont know what you mean? I'm obviously doing something wrong.The items in current_list will form part of a filename which will be used later in the code using the line below. But at the moment I cant pass anything out of the function. I will use the line below later in the code to read in the items in current_list for item in current_list: x, y = np.loadtxt(item + '_' + 'Test.csv', skiprows=1, usecols=[my_col_x_axis, my_col_y_axis], unpack=True, delimiter=',') – Sid May 01 '20 at 17:08
  • Event handlers are typically called by `tkinter`, not directly, and it ignores their return value — which is why I asked. Although using global variables is generally a bad idea, you _could_ declare `global current_list` at the beginning of the `select_events()` function definition and then be able to create and update its value. Where you currently have the `global current_list` statement does nothing. – martineau May 01 '20 at 17:24
  • I suggest you take a look at the answers to the question [Best way to structure a tkinter application?](https://stackoverflow.com/questions/17466561/best-way-to-structure-a-tkinter-application) to learn about ways to avoid using global variables in tkinter applications. – martineau May 01 '20 at 17:30
  • thanks - so am I using the return current_list statement correctly at the end of the select_event function.? the print(current_list) statement underneath wasn't returning anything so don't think I had the right – Sid May 01 '20 at 17:38
  • No, it doesn't matter what `select_event()` returns. When **`tkinter`** calls it, the function can update the value of the global variable — and the value of that global can be processed afterwards (probably as the result of some other user action). GUI programs are "event-driven". See [Tkinter — executing functions over time](https://stackoverflow.com/questions/9342757/tkinter-executing-functions-over-time) – martineau May 01 '20 at 17:46

1 Answers1

1

Here's something that illustrates what can be done since there's no meaningful way to return a value from an tkinter event handler function. It shows how to reference a global variable like current_list for use inside a function (i.e. by declaring it a global).

You only need to do that when the function tries to change the value — the statement tells Python not to create a local variable with that name when something is assigned to it (which is the default behavior).

I've added a Process current list Button to the GUI that will call a function which also added named process_list() whenever it's clicked. This function contains the (commented-out) code you mentioned in one of your comments to indicate where processing like that could be done.

from tkinter import *
from tkinter import ttk

my_window = Tk()

my_frame_in = Frame(my_window)
my_frame_in.grid(row=0, column=0)
my_frame_out = Frame(my_window)
my_frame_out.grid(row=0, column=1)

listbox_events = Listbox(my_frame_in, height='5')
listbox_events.grid(row=0, column=0, padx=10, pady=10)
listbox_events_filtered = Listbox(my_frame_out, height='5')
listbox_events_filtered.grid(row=0, column=2, padx=(0, 10), pady=10)
my_instructions = Label(my_window, text='Use arrow keys to move selected items')
my_instructions.grid(row=1, column=0, columnspan=3, pady=(0, 10))

my_list_events = ['A', 'B', 'C', 'D']
current_list = []  # Initilize global variable.

for item in my_list_events:
    listbox_events.insert(END, item)

def select_events(event=None):
    global current_list

    listbox_events_filtered.insert(END, listbox_events.get(ANCHOR))
    listbox_events.delete(ANCHOR)
    current_list = list(listbox_events_filtered.get(0, END))

def deselect_events(event=None):
    global current_list

    listbox_events.insert(END, listbox_events_filtered.get(ANCHOR))
    listbox_events_filtered.delete(ANCHOR)
    current_list = list(listbox_events_filtered.get(0, END))

def process_list():
    print('current_list:', current_list)
#    for item in current_list:
#        x, y = np.loadtxt(item + '_' + 'Test.csv', skiprows=1, usecols=[my_col_x_axis,
#                          my_col_y_axis], unpack=True, delimiter=',')

my_button = Button(my_window, text='Process current list', command=process_list)
my_button.grid(row=2, column=0, columnspan=3, pady=(0, 10))

listbox_events.bind('<Right>', select_events)
listbox_events_filtered.bind('<Left>', deselect_events)

mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301