获取列表框中选定项并调用另一个函数以存储选定项
我有一个画布,当我点击它时,会调用 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
这个函数成功地打印了 `"ThisShouldBeTheSelected!!"`。
但是我现在完全卡住了。
我无法获取到双击的元素(也就是选中的那个)。
我想把它作为 tag=
传递。
我尝试过:
listbox.curselection()
但是总是打印 ('0',)
如果我去掉 listbox.selection_set(first=0)
,我只会得到 ()
所以我的问题是:
- 我该如何获取选中的项目(也就是双击的那个)
- (不太重要)像我这样把它传递给另一个函数合理吗?
注意:
我发现了 这个链接:
8.5. 为什么 .listbox 的 curselection 或 selection 在我给 listbox 绑定按钮时不返回正确的项目?
在 listbox 的按钮点击事件中获取选中项目的最好方法是使用以下代码:
bind .listbox { set item [%W get [%W nearest %y]] }
这确保了指针下的项目会被返回作为选中的项目。之所以 .listbox 的 curselection 可能会失败,是因为 curselection 中的项目在 Listbox 类绑定触发之前并不会被设置,而这个触发是在实例绑定之后的。这个原因也适用于 selection get 可能会失败的情况,但如果你把 -exportselection 选项设置为 0,它也会失败。
我不确定这是否有帮助,我其实也不太理解它在说什么。
3 个回答
对于Spyder和Python 3.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()
但是当你添加了另一个列表框,或者遇到列表框失去选择的情况时,就会出现IndexError(索引错误)。为了避免这个问题,并且能够为不同的列表框管理不同的回调函数,我建议使用下面这样的代码:
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
会返回正确的值。除非你有自己的单击绑定,这样会阻止默认绑定的执行。
这里有一个简单的例子,可以打印出选择的内容,让你看到它是正确的。请从命令行运行它,这样你可以看到输出:
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()