Tkinter ListboxSelect 回调总是处理列表中的最后一项

Tkinter ListboxSelect callback always processes last item in the list

如果在未选择条目的情况下执行 ListboxSelect 回调,即在相应列表框中的单击已放置在空 space 中最后一项的下方,“curselection”方法始终 returns 列表框中最后一项的索引。更重要的是,如果尝试使用列表框的默认“浏览”选择方法并在按住鼠标按钮的同时将鼠标光标移到列表框上,则任何移动都会执行回调。我试图找到有关如何修复它的提示...不过运气不好。

from tkinter import *

class simple( Frame ):
  def __init__( self, parent = None ):
    Frame.__init__( self )
    self.master.title( 'DEMO' )
    self.master.bind( '<Control-q>', quit )
    self.pack()

    self.create_widgets()

  def create_widgets( self ):
    words = ['An','"empty"','selection','processes','the', 'last', 'item','in','this','list' ]

    self.lb = Listbox ( self, width = 12, height = 25, selectmode = SINGLE, exportselection = False )
    self.lb.pack ( side = LEFT )
    self.lb.bind ( '<<ListboxSelect>>', self.process_item )

    Label ( self, anchor = W, text = '\n\nClick here\n\n<--\n\nin the emtpy space...' ).pack ( side = RIGHT )

    for w in words:
      self.lb.insert ( 0, w )


  def process_item ( self, event ):
    selection = self.lb.curselection ( )
    self.do_stuff_with_item ( self.lb.get ( selection ) )
    self.lb.delete ( selection )


  def do_stuff_with_item ( self, item ):
    print ( item )




def engage():
  root = Tk()
  sw = simple( root )
  sw.pack()
  root.mainloop()


if __name__ == '__main__':
  engage()

我用 python 2.7、3.6(在 Linux 上)和 python 3.8 在 Win

上试过

实现您的要求确实很棘手。
Listbox 的默认行为是 select 获得焦点时的最后一项。

为了愚弄它,您可以添加一个空词作为您的 words 列表的最后一项。 这将使它在 Listbox 中不可见。 然后在您的 process_item 回调中,检查 selected 值是否为空(可选,如果它也是最后一个值)。如果是这样,请从您的回调中移除 Listbox 和 return 的焦点。这看起来好像什么都没发生。

这里是修改后的代码:

from tkinter import *


class simple(Frame):
    def __init__(self, parent=None):
        Frame.__init__(self)
        self.master.title('DEMO')
        self.master.bind('<Control-q>', quit)
        self.pack()

        self.create_widgets()

    def create_widgets(self):
        # Words with dummy "" word in the end
        words = ['An', '"empty"', 'selection', 'processes', 'the', 'last', 'item', 'in', 'this', 'list', ""]

        self.lb = Listbox(self, width=12, height=25, selectmode=SINGLE, exportselection=False)
        self.lb.pack(side=LEFT)
        self.lb.bind('<<ListboxSelect>>', self.process_item)

        Label(self, anchor=W, text='\n\nClick here\n\n<--\n\nin the emtpy space...').pack(side=RIGHT)

        self.lb.insert(0, *words)

    def process_item(self, event):
        selection = self.lb.curselection()
        item = self.lb.get(selection)
        if item == "":
            # It's last dummy item, remove focus and return
            self.master.after(0, self.master.focus)
            return

        # Real item was clicked
        self.do_stuff_with_item(item)
        self.lb.delete(selection)

    def do_stuff_with_item(self, item):
        print(item)


def engage():
    root = Tk()
    sw = simple(root)
    sw.pack()
    root.mainloop()


if __name__ == '__main__':
    engage()