Несколько списков с одной и той же функцией обратного вызова приводят к IndexError

Я использую tkinter для графического интерфейса и создаю два списка:

# widgets     
create_list(win, 20, 20, ["Test", "Apfel", "Birne"])     
create_list(win, 220, 20, ["Alpha", "Beta", "Gamma", "Delta"])

где create_list — это функция:

def create_list(win, xx, yy, items=\[\]):
    lb = Listbox(win)
    i = 1
    for item in items:
        lb.insert(i, item)
        i += 1    
    lb.bind('<<ListboxSelect>>', on_select)
    lb.place(x=xx, y=yy) 

Пока ничего особенного. У меня есть одна функция on_select в качестве обратного вызова для изменений выбора для обоих списков.

def on_select(event):         
    w = event.widget         
    index = int(w.curselection()[0])         
    value = w.get(index)         
    print(f'You selected item {index}: {value}')`

он работает как положено, печатает выбранный элемент. Однако, если я щелкну элемент из второго списка (и наоборот), я получаю сообщение об ошибке:

Исключение в обратном вызове Tkinter Traceback (последний последний вызов):
Файл "/usr/lib/python3.8/tkinter/init.py", строка 1892, вызов вернуть файл self.func(*args) "/home/userx/projects/python/modules/ws_list.py", строка 8, в on_select index = int(w.curselection()[0]) IndexError: индекс кортежа вне допустимого диапазона

Если я затем выберу другой элемент в том же списке, проблема исчезнет. Как я это решаю? Нужна ли мне отдельная функция обратного вызова для каждого списка?

Вы всегда хотите использовать опцию exportselection=False со списком Tkinter, особенно когда на экране одновременно отображается более одного. По умолчанию выбор списка привязывается к системному буферу обмена, поэтому невозможно иметь выбор более чем в одном списке одновременно (и вы постоянно уничтожаете все, что пользователь мог поместить в буфер обмена).

jasonharper 30.01.2023 16:23
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Согласно этому ответу, событие <<ListboxSelect>> будет запущено, если выбор будет удален из списка, что происходит при переключении между списками. Это приведет к пустому curselection, что и вызывает вашу ошибку. Чтобы избежать этого, проверьте, не пусто ли выделение, прежде чем использовать его.

def on_select(event):         
    w = event.widget
    selection = w.curselection()
    if selection:
        index = int(selection[0])         
        value = w.get(index)         
        print(f'You selected item {index}: {value}')

Когда вы переходите с listbox1 на listbox2, on_select срабатывает для обоих. Таким образом, либо вы учитываете возможность того, что w.curselection() пусто, и, следовательно:

def on_select(event):         
    w = event.widget   
    if w.curselection():
       index = int(w.curselection()[0])         
       value = w.get(index)         
       print(f'You selected item {index}: {value} in listbox: {w}')

или используйте exportselection=False при создании LB, чтобы разрешить выбор из них по отдельности.

Вы также можете дать спискам имя (name=xxx), и вы сможете различать, из какого списка вызывается on_select.

Другие вопросы по теме