键盘快捷键绑定、弹出上下文菜单和 TypeErrors
Keyboard shortcut bindings, pop-up context menus and TypeErrors
当我在 Whosebug 上提问时,我总是觉得答案...应该是...RTFM,即使我得到的每一个答案都是友好、耐心和接受的。经过一个下午试图找到答案后,我被困住了。我想打开一个 Tkinter、文本框和绑定键(键盘快捷键)和一个菜单项,这样我就会有一个很好的弹出菜单(又名上下文菜单),比如 Window 的记事本,如果你右键单击并见
Cut
Copy
Paste
-----
Select All
用Ctrl+X, Ctrl+C、Ctrl+V 和 Ctrl+A 作为键绑定(我还没有弄清楚如何撤消)。问题是我无法让键绑定和弹出菜单同时使用相同的功能。如果我在 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)
我可以只写两个函数,但这看起来效率很低,而且无法解释为什么程序会这样运行。
这里的问题是,当您将函数绑定到用户输入事件(例如按键或鼠标单击),然后使用该事件调用它时,它会将事件发送到该函数。这非常有用,因为也许您想将鼠标点击的位置传递给一个函数,该函数应该在 canvas 上画一个点。但是,如果单击或按键仅用作加速器,那么您将传递一个无用的事件。这本身并没有那么糟糕,但是如果您还想在没有按键或鼠标单击的情况下访问该功能怎么办 - 例如,通过菜单中的命令?这不会发送事件,而您的函数需要一个事件。
有多种方法可以解决这个问题。
用 def select_all(event=None)
代替 def select_all(event)
定义函数。这将允许您的函数期望 0 或 1 个参数,如果没有参数传递给它,则默认为 None
的 event
。 (谢谢,@Bryan。)
用 def select_all(*event)
代替 def select_all(event)
定义函数。这将允许您的函数期望任意数量的位置参数,包括 0 或 1。它的通用名称是 *args
,或 "star args"。
将菜单命令与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])
按每个项目的第二个元素对可迭代对象进行排序)。
当我在 Whosebug 上提问时,我总是觉得答案...应该是...RTFM,即使我得到的每一个答案都是友好、耐心和接受的。经过一个下午试图找到答案后,我被困住了。我想打开一个 Tkinter、文本框和绑定键(键盘快捷键)和一个菜单项,这样我就会有一个很好的弹出菜单(又名上下文菜单),比如 Window 的记事本,如果你右键单击并见
Cut
Copy
Paste
-----
Select All
用Ctrl+X, Ctrl+C、Ctrl+V 和 Ctrl+A 作为键绑定(我还没有弄清楚如何撤消)。问题是我无法让键绑定和弹出菜单同时使用相同的功能。如果我在 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)
我可以只写两个函数,但这看起来效率很低,而且无法解释为什么程序会这样运行。
这里的问题是,当您将函数绑定到用户输入事件(例如按键或鼠标单击),然后使用该事件调用它时,它会将事件发送到该函数。这非常有用,因为也许您想将鼠标点击的位置传递给一个函数,该函数应该在 canvas 上画一个点。但是,如果单击或按键仅用作加速器,那么您将传递一个无用的事件。这本身并没有那么糟糕,但是如果您还想在没有按键或鼠标单击的情况下访问该功能怎么办 - 例如,通过菜单中的命令?这不会发送事件,而您的函数需要一个事件。
有多种方法可以解决这个问题。
用
def select_all(event=None)
代替def select_all(event)
定义函数。这将允许您的函数期望 0 或 1 个参数,如果没有参数传递给它,则默认为None
的event
。 (谢谢,@Bryan。)用
def select_all(*event)
代替def select_all(event)
定义函数。这将允许您的函数期望任意数量的位置参数,包括 0 或 1。它的通用名称是*args
,或 "star args"。将菜单命令与
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])
按每个项目的第二个元素对可迭代对象进行排序)。