fmex
fmex

Reputation: 138

Python/Tkinter: Unwanted interaction between two widgets

Following is the smallest fully functional tkinter code I could write to demonstrate a problem I am having in a larger application. This code presents two frames - the left containing a listbox, the right containing a scrollable text widget. When the user selects a listbox item, the content of that item appears in the text widget. If you place your cursor in the text widget, all is well. You can add more text with no problem and/or use the delete key to delete text. But if you select any text in the text widget, the "ListboxSelect" function is called, and throws the error "IndexError: tuple index out of range". This makes no sense. Why would selecting text in the text widget call a function that is explicitly tied to the listbox widget?

enter image description here

import tkinter as tk
from tkinter import scrolledtext

root = tk.Tk()
root.geometry("400x200")

def listbox_selected(event):
    w = event.widget
    listbox_index = int(w.curselection()[0])
    right_text.delete(1.0,tk.END)
    right_text.insert(tk.END,left_listbox.get(listbox_index))

left_frame = tk.Frame(root,height=200,width=180,bg="lightblue")
left_frame.place(x=15,y=2)

# left frame contains listbox
left_listbox = tk.Listbox(left_frame)
left_listbox.bind("<<ListboxSelect>>",listbox_selected)
left_listbox.place(x=5,y=5)
for index in range(5):
    left_listbox.insert(index,"This is item " + str(index))

right_frame = tk.Frame(root,height=200,width=180,bg="lightyellow")
right_frame.place(x=200,y=5)

# right frame contains scrollable text widget
right_text = tk.scrolledtext.ScrolledText(right_frame,width=18,
                                                height=10)
right_text.place(x=5,y=5)

root.mainloop()

Upvotes: 0

Views: 130

Answers (1)

acw1668
acw1668

Reputation: 47173

It is because when selecting text inside Text widget will deselect the selected item in Listbox which triggers the <<ListboxSelect>> event.

The deselection in the Listbox can be disabled by setting exportselection=0:

left_listbox = tk.Listbox(left_frame, exportselection=0)

Another way is to check whether there is selected item inside listbox_selected():

def listbox_selected(event):
    w = event.widget
    selection = w.curselection()
    # check whether there is item selected
    if selection:
        listbox_index = int(selection[0])
        right_text.delete(1.0,tk.END)
        right_text.insert(tk.END,left_listbox.get(listbox_index))

Upvotes: 1

Related Questions