Tkinter 和绑定到 ListboxSelect 事件的两个列表框的意外行为 [英] Unexpected behavior with Tkinter and two Listboxes bound to ListboxSelect event

查看:27
本文介绍了Tkinter 和绑定到 ListboxSelect 事件的两个列表框的意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在编写的脚本中遇到了一个不寻常的问题.该程序是用 Python3/Tkinter 编写的.它初始化两个列表框,包裹在两个单独的框架中,并根据用户的命令显示一个或另一个.当用户选择第一个 Listbox 中的一个项目,然后决定更改屏幕并选择第二个框架中的一个项目时,就会出现异常.

I’ve encountered an unusual problem in a script that I’m working on. The program is written in Python3/Tkinter. It initializes two Listboxes, wrapped in two separate Frames, and according to the user’s commands displays either one or the other. An exception arises when the user selects on one of the items in the first Listbox, then decides to change screen and selects an item in the second frame.

我创建了一个示例代码(如下)来重现问题.使用此代码,在运行时,单击第一个列表框(白色背景)中的一个项目会显示第二个列表框(橙色背景).此外,第一个对象已解包",因此用户不应再与其进行交互.最后,单击第二个 Listbox 中的项目,会在第一个对象的on_select_1"方法中引发 IndexError.为什么那个方法会在那个事件之后执行?我很清楚自己作为程序员的局限性,但我很确定这不是应该发生的事情.

I’ve created a sample code (below), to replicate the problem. With this code, during runtime, clicking on one item in the first Listbox (white background) makes the second Listbox appear (orange background). Also, the first object is "unpacked" and thus the user should no longer be able to interact with it. Finally, clicking on an item in the second Listbox, raises an IndexError in the "on_select_1" method from the first object. Why would that method execute after that event?? I’m well aware of my limits as a programmer, but I’m pretty sure this is not what is supposed to happen.

import tkinter as tk


class Listbox1(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.lb1 = tk.Listbox(self)
        for i in ["item 1.1", "item 1.2", "item 1.3", "item 1.4"]:
            self.lb1.insert(tk.END, i)
        self.lb1.bind("<<ListboxSelect>>", self.on_select_1)
        self.lb1.pack()

    def on_select_1(self, *args):
        try:
            print("item {} selected in listbox 1".format(self.lb1.curselection()[0]))
        except IndexError:
            print("IndexError raised in method 'on_select_1'")

        self.master.switch()


class Listbox2(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.lb2 = tk.Listbox(self, bg='orange')
        for i in ["item 2.1", "item 2.2", "item 2.3", "item 2.4"]:
            self.lb2.insert(tk.END, i)
        self.lb2.bind("<<ListboxSelect>>", self.on_select_2)
        self.lb2.pack()

    def on_select_2(self, *args):
        print("item {} selected in listbox 2".format(self.lb2.curselection()[0]))


class App(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.pack()
        self.lb1_frame = Listbox1(self)
        self.lb2_frame = Listbox2(self)
        self.lb1_frame.pack()

    def switch(self):
        self.lb1_frame.pack_forget()
        self.lb2_frame.pack()


def main():
    root = tk.Tk()
    app = App(root)
    app.mainloop()


if __name__ == '__main__':
    main()

推荐答案

默认情况下,tkinter 一次只允许一个小部件保存选择.因此,当您在第二个列表框中选择某些内容时,第一个列表框中选择的项目将被取消选择.这会导致您的函数被调用.发生这种情况时,self.lb1.curselection()[0]) 会抛出错误,因为选择为空.

By default, tkinter only allows one widget to hold the selection at a time. Thus, when you select something in your second listbox, the item selected in the first listbox is deselected. That causes your function to be called. When this happens, self.lb1.curselection()[0]) throws an error because the selection is empty.

当您在第二个列表框中选择某些内容时,允许选择在第一个列表框中保持不变的简单解决方案是将两个列表框的 exportselection 选项设置为 False.

A simple solution that allows the selection to remain unchanged in the first listbox when you select something in the second listbox is to set the exportselection option to False for both listboxes.

self.lb1 = tk.Listbox(self, exportselection=False)
...
self.lb2 = tk.Listbox(self, bg='orange', exportselection=False)

这篇关于Tkinter 和绑定到 ListboxSelect 事件的两个列表框的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆