简体   繁体   中英

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?

在此处输入图像描述

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()

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM