在tkinter列表框上使用curselection(),但第一次选择返回空元组

2024-10-01 13:41:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用带有tkinter字体的列表框更改文本字段的字体。除了第一次选中列表框外,它工作正常

在第一次单击列表框时,我将得到这个错误消息IndexError: tuple index out of range,并且列表框选择的元组将是()。但是,下一个选择完全可以。然后我会得到这样一个元组(number,)这是什么原因?如果我绑定<Double-Button-1>而不是<Button-1>,那么第一个选择(双击列表框)可以正常工作

import tkinter
from tkinter import font

class EnkelTeksteditor:
    def __init__(self):
        self.hovedvindu = tkinter.Tk()
        self.tekstomraadet = tkinter.Text(self.hovedvindu, height=10, width=30)
        self.tekstomraadet.grid(column=0, row=0)
        self.scrollbar = tkinter.Scrollbar(self.hovedvindu, orient=tkinter.VERTICAL,
                                           command=self.tekstomraadet.yview)
        self.scrollbar.grid(column=1, row=0, sticky=(tkinter.N, tkinter.S))
        self.tekstomraadet.config(yscrollcommand=self.scrollbar.set)
        self.hovedvindu.title("Enkel teksteditor")

        self.fontlistbox = tkinter.Listbox(self.hovedvindu, selectmode=tkinter.SINGLE)
        self.fontene = font.families()
        for fonten in self.fontene:
            self.fontlistbox.insert(tkinter.END, fonten)
        self.fontlistbox.grid(column=3, row=0, sticky=(tkinter.N, tkinter.S))

        self.fontscroller = tkinter.Scrollbar(self.hovedvindu, orient=tkinter.VERTICAL,
                                              command=self.fontlistbox.yview)
        self.fontlistbox.config(yscrollcommand=self.fontscroller.set)
        self.fontscroller.grid(column=4, row=0, sticky=(tkinter.N, tkinter.S))


        self.fontlistbox.bind("<Button-1>", self.endre_font_listbox)
        self.fontlistbox.bind("<Key-Return>", self.endre_font_listbox)

        tkinter.mainloop()

    def endre_font_listbox(self, hendelse):
        valgte_indekser = self.fontlistbox.curselection()
        print(valgte_indekser)
        if valgte_indekser:
            font_tekst = self.fontene[valgte_indekser[0]]
            ny_font = font.Font(size=10, weight=bold_tekst, slant=italic_tekst, family=font_tekst)
            self.tekstomraadet.config(font=ny_font)


if __name__ == "__main__":
    gui = EnkelTeksteditor()

Tags: selftkintercolumnbuttongridrowfont列表框
2条回答

当选择更改时,listbox会生成一个特殊的虚拟事件。您应该使用它,而不是绑定到密钥。因为您要绑定到一个键并按,所以绑定会在默认绑定之前触发。是默认绑定导致选择发生更改

以下是绑定到虚拟事件的方式:

self.fontlistbox.bind("<<ListboxSelect>>", self.endre_font_listbox)

除了解决调用事件回调的顺序问题外,这还有一个额外的优点,即如果用户使用键盘更改选择,它也可以工作

当您绑定到<Button-1>时,绑定函数会在listbox有机会处理事件之前激发。这就是为什么可以从绑定函数返回"break"来停止事件

请看下面的代码:

import tkinter as tk

def return_break(event):
    return "break"

root = tk.Tk()
text = tk.Text(root)
text.pack()
text.bind("<Key>", return_break)
root.mainloop()

只要你按下一个按钮,tkinter就会调用你的函数return_break。该函数返回"break",通知tkinter停止事件。这就是事件从未到达text小部件的原因

类似地,当您绑定到<Button-1>时,您的函数会在列表框了解鼠标按下之前被调用。当您将其更改为<ButtonRelease-1>时,它会起作用,因为在释放鼠标按钮时会调用该函数,并且列表框有时间处理<Button-1>事件

解决此问题的另一种方法是将代码更改为:

def endre_font_listbox(self, hendelse):
    self.fontlistbox.after(1, self._endre_font_listbox)

def _endre_font_listbox(self):
    valgte_indekser = self.fontlistbox.curselection()
    print(valgte_indekser)
    ...

这会告诉tkinter在调用函数(_endre_font_listbox)之前等待1毫秒(这对于listbox处理事件来说是足够的时间)

始终记住,在小部件的处理程序之前调用函数

相关问题 更多 >