键盘快捷键绑定、弹出式上下文菜单和TypeErrors



当我在stackoverflow上问问题时,我总是觉得答案。。。应该是…RTF,即使我得到的每一个答案都是友好、耐心和可接受的。经过一个下午的努力,我终于找到了答案。我想打开一个Tkinter,文本框,绑定键(键盘快捷键)和菜单项,这样我就会有一个很好的弹出菜单(又名上下文菜单),比如Window的记事本,如果你右键点击并看到

Cut 
Copy 
Paste 
----- 
Select All

使用Ctrl+X+Ctrl+V1作为密钥绑定(我还没有弄清楚如何撤消)。问题是,我无法同时使用键绑定和弹出菜单来使用相同的功能。如果我在select_all()的定义中添加或删除"event"参数,其中一个有效,但另一个无效。

from Tkinter import *
# Clears the clipboard and copies the selected text to the it
def copy():
    mainwin.clipboard_clear()
    mainwin.clipboard_append(mainwin.selection_get())
# Needed for the right click pop-up menu to work, goes with copy()
def popup(event):
    popupmenu.post(event.x_root, event.y_root)
# Selects all text, used with the "control a" keybinding
def select_all(event):
    textbox.tag_add(SEL, "1.0", END)
    textbox.mark_set(INSERT, "1.0")
    textbox.see(INSERT)
    return 'break'
# Start of the program
mainwin = Tk()
scrollbar = Scrollbar(mainwin)
scrollbar.pack(side=RIGHT, fill=Y)
textbox = Text(mainwin, yscrollcommand=scrollbar.set)
textbox.pack(side=LEFT, fill=BOTH)
scrollbar.config(command=textbox.yview)
# Key bindings for the Text widget
textbox.bind("<Control-Key-a>", select_all)
# Pop-up menu, with right click binding for the Text widget
popupmenu = Menu(mainwin, tearoff=0)
popupmenu.add_command(label="Copy", command=copy)
popupmenu.add_separator()
popupmenu.add_command(label="Select All", command=select_all)
textbox.bind("<Button-3>", popup)
mainloop()

在密钥绑定上面写的方式是有效的,但菜单项给了我:

TypeError: select_all() takes exactly 1 argument (0 given)

我可以只写两个函数,但这似乎真的很低效,也不能解释为什么程序会这样运行。

这里的问题是,当您将函数绑定到用户输入事件(如按键或鼠标单击),然后用该事件调用它时,它会将事件发送到该函数。这是非常有用的,因为你可能想把鼠标点击的位置传给一个函数,这个函数应该在画布上画一个点。但是,如果单击或按键只是用作加速器,那么您传递的事件是无效的。这本身并没有那么糟糕,但如果你也想在无需按键或鼠标点击的情况下访问该功能,比如通过菜单中的命令,该怎么办?这不会发送事件,而您的函数正期待一个事件。

有多种方法可以解决这个问题。

  1. def select_all(event=None)而不是def select_all(event)定义您的函数。这将允许您的函数期望0或1个参数,如果没有参数传递给它,则默认为Noneevent。(谢谢,@Bryan。)

  2. def select_all(*event)而不是def select_all(event)定义您的函数。这将允许函数期望任意数量的位置参数,包括0或1。它的通用名称是*args,或"星形args"。

  3. 将菜单命令与popupmenu.add_command(label="Select All", command=lambda: select_all(0))绑定。这定义了一个内联函数,该函数包括用一个参数调用select_all函数。这个论点是垃圾,但你无论如何都没有使用它,所以一切都很好。我认为在tkinter中,您也可以使用command=select_all, 0绑定带参数的命令,但lambda构造要流行得多,因为它在tkinter之外很有用,而且确实是一个很方便学习的语言特性(例如,使用sorted(mylist, key=lambda x: x[1])对每个项的第二个元素的可迭代项排序)。

最新更新