Tkinter ListboxSelect 回调始终处理列表中的最后一项

发布于 2025-01-15 10:57:06 字数 1401 浏览 4 评论 0原文

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

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 上尝试过

If the ListboxSelect callback is executed without having an entry selected, i.e the click in the respective listbox has been placed below the last item in the empty space, the "curselection" method always returns the index of the last item in the listbox. Even more, if one tries to use the default "browse" selection method for the listbox and moves the mouse cursor over the listbox while holding mouse button pressed, any move will execute the callback. I tried to find a hint on how to fix it... no luck though.

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

I tried it with python 2.7, 3.6 ( on Linux ) and with python 3.8 on Win

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

木槿暧夏七纪年 2025-01-22 10:57:06

实现您所要求的目标确实很棘手。
Listbox 的默认行为是在获得焦点时选择最后一项。

为了欺骗它,您可以添加一个空单词作为您的单词列表的最后一项。
这将使其在Listbox中不可见。
然后在您的 process_item 回调中,检查所选值是否为空(也可以选择是否为最后一个值)。如果是这样,请从 Listbox 中移除焦点并从您的回调中返回。这看起来就像什么都没发生一样。

这是修改后的代码:

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

It was indeed tricky to achieve what You've asked for.
Default behavior of Listbox is to select last item when it gains focus.

To fool it, You can add an empty word as a last item of Your words list.
This will make it invisible in a Listbox.
Then in Your process_item callback, check if selected value is empty (optionally if it's last value as well). If so, remove focus from Listbox and return from Your callback. This will look as if nothing happened.

Here is modified code:

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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文