Я использую 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: индекс кортежа вне допустимого диапазона
Если я затем выберу другой элемент в том же списке, проблема исчезнет. Как я это решаю? Нужна ли мне отдельная функция обратного вызова для каждого списка?






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