在列表框中获取选定项并调用另一个函数来存储

2024-09-28 22:11:41 发布

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

我有一个画布,当单击它时它会调用createCategoryMeny(x)

这个函数只创建一个Toplevel()窗口

def createCategoryMenu(tableNumber):

    ##Not interesting below:
    categoryMenu = Toplevel()
    categoryMenu.title("Mesa numero: " + str(tableNumber))
    categoryMenu.geometry("400x400+100+100")

    categoryMenu.focus()
    categoryMenu.grab_set()

    Label(categoryMenu, text="Elegir categoria \n Mesa numero: " + str(tableNumber)).pack()


    ## RELEVANT CODE BELOW:
    listbox = Listbox(categoryMenu, width=50, height=len(info.listaCategorias))
    listbox.pack(pady=20)

    for item in info.listaCategorias:
        listbox.insert(END, item)

    listbox.selection_set(first=0)

    ##My attempt to solve it
    callback = lambda event, tag= "ThisShouldBeTheSelected!!": do(event, tag)
    listbox.bind("<Double-Button-1>", callback)

然后do函数:

def do(event, tag):
    print tag

这将成功打印“This shouldbetheselected!!”``.

这就是我完全被困的地方。

我无法获取双击的元素(选定的元素)。

我想把它作为tag=传递。

我试过:

listbox.curselection()

它总是打印('0',)

如果我删除listbox.selection_set(first=0),我只得到这个:()

所以问题是:

  • 如何获取所选项目(双击的项目)
  • (不那么重要)像我一样把它传递给另一个函数是否合理?

注:

我发现this

8.5. Why doesn't .listbox curselection or selection get return the proper item when I make a button binding to my listbox?

The best way to get the selected item during a button click event on a listbox is to use the following code:

bind .listbox { set item [%W get [%W nearest %y]] }

This ensures that the item under the pointer is what will be returned as item. The reason .listbox curselection can fail is because the items in curselection are not set until the Listbox class binding triggers, which is after the instance bindings by defaults. This is the same reason for which selection get can fail, but it will also fail if you set the -exportselection option to 0.

我不确定它是否有用,我真的不明白它在说什么。


Tags: theto函数eventgetistagitem
3条回答

对于spyder和Python3.6,以下代码起作用。

import tkinter as tk
root = tk.Tk()
root.geometry("612x417")
root.title("change label on listbox selection")
root.resizable(0,0)
root.configure(background='lightgrey')


#Show selected currency for from in label
frmcur_text = tk.StringVar()
frmcur = tk.Label(root, textvariable=frmcur_text, font="Helvetica 10 bold", anchor='w', background='lightgrey').place(x=195,y=50)

def onselect(evt):
    # Note here that Tkinter passes an event object to onselect()

    w = evt.widget
    index = int(w.curselection()[0])
    value = w.get(index)
#    print ('You selected item %d: "%s"' % (index, value))
    frmcur_text.set(value)

#Create listboxes for xurrency selection
listbox1 = tk.Listbox(root, font="Helvetica 11 bold", height=3, width=10)
listbox2 = tk.Listbox(root, font="Helvetica 11 bold", height=3, width=10)
listbox1.place(x=300,y=50)
listbox2.place(x=300,y=125)


for i in range(20):
    i = i + 1
    listbox1.insert(1, i)
    listbox2.insert(1, i)


listbox1.bind('<<ListboxSelect>>', onselect)    

cs = listbox1.curselection()

frmcur_text.set(cs)

root.mainloop()

虽然只有一个列表框可供管理,但使用类似这样的工具(Python 3)非常好:

import tkinter as tk

root = tk.Tk()
box = tk.Listbox(root)
box.insert(tk.END, 'First')
box.insert(tk.END, 'Second')
box.insert(tk.END, 'Third')
box.pack()


def onselect(event):
    w = event.widget
    idx = int(w.curselection()[0])
    value = w.get(idx)
    print(value)


box.bind('<<ListboxSelect>>', onselect)

root.mainloop()

但是,当您添加另一个列表框,或遇到列表框丢失其选择的情况时,将引发索引器错误。 为了避免这种情况,为了管理不同列表框的不同回调,我建议如下:

import tkinter as tk

root = tk.Tk()
box = tk.Listbox(root)
box.insert(tk.END, 'First')
box.insert(tk.END, 'Second')
box.insert(tk.END, 'Third')
box.pack()

box2 = tk.Listbox(root)
box2.insert(tk.END, 'First')
box2.insert(tk.END, 'Second')
box2.insert(tk.END, 'Third')
box2.pack()


def on_first_box(idx, val):
    print('First box idx: %s, value: %s' % (idx, val))


def on_second_box(idx, val):
    print('Second box idx: %s, value: %s' % (idx, val))


def onselect(event, listbox):
    w = event.widget
    try:
        idx = int(w.curselection()[0])
    except IndexError:
        return
    if listbox is box:
        return on_first_box(idx, w.get(idx))
    if listbox is box2:
        return on_second_box(idx, w.get(idx))


box.bind('<<ListboxSelect>>', lambda e: onselect(e, box))
box2.bind('<<ListboxSelect>>', lambda e: onselect(e, box2))

root.mainloop()

首先,不要使用lambda。它对范围很窄的问题很有用,但这不是其中之一。创建一个适当的函数,它们更容易编写和维护。

一旦这样做,就可以调用curselection来获取当前选择。你说你试过了,但是你的示例代码没有显示你试过什么,所以我只能假设你做错了。

至于使用nearest的不寻常建议。。。它所说的是,您在小部件上放置的绑定发生在同一事件的默认绑定之前。设置选择的是默认绑定,因此当您绑定到单个按钮单击时,您的绑定将在默认绑定更新选择之前触发。有很多方法可以解决这个问题,其中最好的方法是不点击一次就绑定,而是绑定到<<ListboxSelect>>上,在选择改变后会触发。

不过,你没有这个问题。由于您是在双击时绑定的,因此选择将由默认的单击绑定设置,curselection将返回正确的值。也就是说,除非您有自己的防止触发默认绑定的单击绑定。

这里有一个简单的例子,打印出选择,这样您就可以看到它是正确的。从命令行运行它,以便看到stdout:

import Tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        lb = tk.Listbox(self)
        lb.insert("end", "one")
        lb.insert("end", "two")
        lb.insert("end", "three")
        lb.bind("<Double-Button-1>", self.OnDouble)
        lb.pack(side="top", fill="both", expand=True)

    def OnDouble(self, event):
        widget = event.widget
        selection=widget.curselection()
        value = widget.get(selection[0])
        print "selection:", selection, ": '%s'" % value

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

相关问题 更多 >