Search code examples
pythontkintercomboboxlistbox

ttk.Combobox triggers <<ListboxSelect>> event in different tk.Listbox


What i am trying to do: I am trying to build a GUI using tkinter in Python (i am using version 3.7.7 on Windows) with a main window that has a Listbox and a second window that contains a Combobox. In the Listbox there are different files that can be opened. When clicking on each entry some additional information are displayed in the main window (That part is not in my shorter example code below). So what i did was binding the Listbox to a function that loads and displays the information (function_1 in the code below) with the <<ListboxSelect>> event. The second window can be opened with a button and should edit the selected file. In the Combobox in the second window are different options that change other elements of the second window depending on whats selected. Thats why i bind the <<ComboboxSelected>> event to a different function (function_2 in the code below).

My problem with this is: When i select a value in the Combobox of the second window, the first function that is binded to the Listbox of the first window is executed just after the correct function for the Combobox. This only happens the first time a value for the Combobox is selected, for each time the second window is created. Also when looking at the selected value of the Listbox it returns the selected value of the Combobox.

Edit: I just noticed this problem only happens when i previously selected an item in the Listbox. So like i said below it might have something to do that the Listbox is still active or something like that.

My code and an example:

import tkinter as tk
from tkinter import ttk


class MainGUI:
    def __init__(self):
        self.root = tk.Tk()

        items = ['Test 1', 'Test 2', 'Test 3']

        self.item_box = tk.Listbox(self.root)
        self.item_box.insert('end', *items)
        self.item_box.bind('<<ListboxSelect>>', self.function_1)
        self.item_box.pack()
        tk.Button(self.root, text='Open second window',
                  command=self.open_window).pack()

        self.root.mainloop()

    def function_1(self, event):
        print('MainGUI function:', event)
        print('Text in Listbox:', self.item_box.selection_get())

    def open_window(self):
        SecondGUI()


class SecondGUI:
    def __init__(self):
        self.window = tk.Toplevel()
        self.window.grab_set()

        items = ['A', 'B', 'C']

        self.dropdown = ttk.Combobox(self.window, values=items)
        self.dropdown.current(0)
        self.dropdown.pack()
        self.dropdown.bind('<<ComboboxSelected>>', self.function_2)

    def function_2(self, event):
        print('SecondGUI function:', event)


MainGUI()

Image of the GUI before and after the option B is clicked

The output after selecting Test 1, opening the second window with the button and selecting B looks like this:

MainGUI function: <VirtualEvent event x=0 y=0>
Text in Listbox: Test 1
SecondGUI function: <VirtualEvent event x=0 y=0>
MainGUI function: <VirtualEvent event x=0 y=0>
Text in Listbox: B

My guess: If i had to guess what the problem is, i would say the Combobox maybe had some sort of Listbox in it that sends the event, but as i wasn't able to find more about when and how these events are sent, i couldn't really find anything about it (Edit: Less likely). When looking at the picture, you can see that the entry in the first window is still selected until the entry in the second window is clicked, so my second guess would be that the Listbox is still active and takes the new selected value when it is clicked or something like that (Edit: more likely).

My question: Why does the first function execute when i use a different widget in a different window, how can i fix this, or are there any better way to do this in the first place?

TL;DR: A Listbox recieves an event when a Combobox is selected in a different window. Why?

Thanks in advance!


Solution

  • It may be due to that exportselection=False is not set for both the Listbox and Combobox. So when an item in the Combobox is selected, it will clear the selection of Listbox which triggers the <<ListboxSelect>> event.

    Also you have used wrong function, self.item_box.selection_get(), to get the current selected item of Listbox. self.item_box.get(self.item_box.curselection()) should be used instead.

    Below changes should fix the issue:

    class MainGUI:
        def __init__(self):
            ...
            self.item_box = tk.Listbox(self.root, exportselection=False)
            ...
    
        def function_1(self, event):
            print('MainGUI function:', event)
            print('Text in Listbox:', self.item_box.get(self.item_box.curselection()))
    
        ...
    
    class SecondGUI:
        def __init__(self):
            ...
            self.dropdown = ttk.Combobox(self.window, values=items, exportselection=False)
            ...
    
        ...