Python Tkinter Listbox 事件绑定

0 投票
2 回答
15921 浏览
提问于 2025-04-17 13:22

我在用python/tkinter的时候遇到了一些麻烦,想要绑定一个事件。我的目标很简单,就是点击一下,然后打印出点击的位置。但是每次我这么做的时候,结果都是“-1”。

这是我的代码:

from Tkinter import *
import Tkinter

class make_list(Tkinter.Listbox):

    def __init__(self,master, **kw):
        frame = Frame(master)
        frame.pack()
        self.build_main_window(frame)

        kw['selectmode'] = Tkinter.SINGLE
        Tkinter.Listbox.__init__(self, master, kw)
        master.bind('<Button-1>', self.click_button)
        master.curIndex = None

    #display the clicked location
    def click_button(self, event):
        self.curIndex = self.nearest(event.x)
        print self.curIndex

    #display the window, calls the listbox
    def build_main_window(self, frame):
        self.build_listbox(frame)

    #listbox
    def build_listbox(self, frame):
        listbox = Listbox(frame)
        for item in ["one", "two", "three", "four"]:
            listbox.insert(END, item)    
        listbox.insert(END, "a list entry")
        listbox.pack()
        return

if __name__ == '__main__':
    tk = Tkinter.Tk()
    make_list(tk)
    tk.mainloop()

更新后的代码 - 我去掉了框架,但我还是搞不明白为什么在函数click_button里的第一个打印语句会得到-1。

from Tkinter import *
import Tkinter

class make_list(Tkinter.Listbox):

    #display the clicked location
    def click_button(self, event):
        ##this block works
        w = event.widget
        index = int(w.curselection()[0])
        value = w.get(index)
        print value
        ##this doesn't
        self.curIndex = self.nearest(event.y)
        print self.curIndex
        self.curIndex = event.widget.nearest(event.y)
        print self.curIndex

    #display the window, calls the listbox
    def build_main_window(self):
        self.build_listbox()

    #listbox
    def build_listbox(self):
        listbox = Listbox()
        listbox.bind('<<ListboxSelect>>', self.click_button)
        for item in ["one", "two", "three", "four"]:
            listbox.insert(END, item)    
        listbox.insert(END, "a list entry")
        listbox.pack()
        return

if __name__ == '__main__':
    tk = Tkinter.Tk()
    start = make_list(tk)
    start.build_main_window()
    start.mainloop()

2 个回答

6

在某个回答的评论里,你问到了最佳做法。最佳做法是绑定到 <<ListboxSelect>> 事件,这个事件会在你选择列表框中的某个项目后立即触发。

这个回答提供了一个类似问题的例子。

3

在这个列表框中,最近的项目是通过 y 坐标找到的,而不是 x 坐标。

 self.nearest(event.x)     # wrong
 self.nearest(event.y)     # right

更新:我一开始没有注意到真正的问题:

    listbox = Listbox(frame)

你使用的并不是你自己创建的那个列表框,而是另一个无关的列表框。你的列表框(也就是 make_list)是空的,所以它总是返回 -1,表示没有找到最近的项目。

也许把一个框架(frame)进行子类化是个好主意(总之,这比把列表框子类化再在里面加一个列表框要好)。这样你就需要在那个真实的非空列表框上绑定事件。

想快速看看修复后会怎样,可以用 event.widget 调用一个真实列表框的 nearest 方法:

self.curIndex = event.widget.nearest(event.y)

撰写回答