0

I have a tabbed interface with listboxes on each tab. When changing tabs, the first selection on the new tab errors out (index error) but any selection after that is recognized correctly. I've managed to replicate the error in this simplified example:

import tkinter as tk
from tkinter import ttk

class App(tk.Tk):
    """basic class to replicate tab-switching error"""

    def __init__(self):
        """exactly what it looks like"""
        super().__init__()
        self.items = {'Alphic': ["A","B","C",'c','d'], 'Numera':['1','2','3','4','5','6']}

        self.selection = tk.StringVar()
        self.main = tk.Frame()
        self.tabs = ttk.Notebook(self.main)
        
        self.make_tabs()

        self.main.pack()


    def make_tabs(self):
        """create all tabs in collected data"""

        def make_tab(f, data):
            'create single tab'
            frame = ttk.Frame(self.tabs)
            select  = tk.Listbox(frame,
                                 width = 20,
                                 height = 8)
            
            def update_selection(*_):
                try:
                    index = [i for i in select.curselection()][0]
                except IndexError:
                    index = "This Error Right Here"
                print(index)
            
            
            for n,k in enumerate(data):
                print("inserting", n)
                select.insert(n+1,k)
    
            select.pack()
            frame.pack()
            select.bind('<<ListboxSelect>>', update_selection)
            return frame


        for i, k in self.items.items():
            self.tabs.add(make_tab(i,k), text=i)
            
        self.tabs.pack()

            
if __name__ == "__main__":
    a = App()
    a.mainloop()

This issue is causing a dangerous bug in a larger program, as the error allows the selected index to 'bleed thru' from the previously selected tab. I've isolated that bug to this issue.

I've tried examining the Event that's passed to see if there's any clarification to be had, but no dice --or clarification-- was to be found.

2 Answers 2

0

By default, the selection of a listbox will be clear if there is selection in other widget. Clear of the selection will also trigger the the event <<ListboxSelect>> which causes the exception.

To keep the selection of the previous listbox, you need to set exportselection=False when creating those listboxes:

select = tk.Listbox(frame,
                    exportselection=False,
                    width = 20,
                    height = 8)
Sign up to request clarification or add additional context in comments.

1 Comment

Beautiful! Much appreciated, that's exactly what i was hoping for.
0

By default, the user may select text with the mouse, and the selected text will be exported to the clipboard. To disable this behavior, use exportselection=0.

Let us consider a situation for a particular system to keep selecting multiple files from a directory and, once copied in the clipboard, paste them into another directory. The idea of making multiple selections in ListBoxes can be implemented by using the exportselection property. The property prevents the selected options from losing while choosing an item from another ListBox. Thus, we can select multiple options from the ListBoxes. To configure a Listbox to behave like keep selection steady, we can make exportselection = False.

You can execute following script to view what's wrong. The items in first two listboxes can be selected at the same time, but not for last two listboxes.

For your case, exportselection=True is default, then the selection will be cleared when you select item in another listbox, then an '<<ListboxSelect>>' event will be generated and the result for select.curselection() will be an empty tuple.

That's why you got an exception, IndexError: list index out of range, for [i for i in select.curselection()][0] is same as [][0].

Demo Code

import tkinter as tk

root = tk.Tk()
options = {"width":5, "height":5, "font":("Courier New", 16), "bg":"green", "fg":"white"}

for i in range(2):
    for j in range(2):
        listbox = tk.Listbox(root, exportselection=i, **options)
        for j in range(5):
            listbox.insert(j, j)
        listbox.pack(side=tk.LEFT)

root.mainloop()

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.