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

Dav*_*ker 0 python types keyboard-shortcuts contextmenu tkinter

我总是觉得当我在stackoverflow上问一个问题就像答案那样......应该是...... RTFM,即使我得到的每一个答案都是友好,耐心和接受的.经过一个下午试图找到答案,我被困住了.我想打开一个Tkinter,文本框和绑定键(键盘快捷键)和一个菜单项,所以我会有一个很好的弹出菜单(也就是上下文菜单),如Window的记事本,你右击,看看

Cut 
Copy 
Paste 
----- 
Select All
Run Code Online (Sandbox Code Playgroud)

Ctrl+ X,Ctrl+ C,Ctrl+ VCtrl+ 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()
Run Code Online (Sandbox Code Playgroud)

它在键绑定上方的编写方式有效,但菜单项给了我:

TypeError: select_all() takes exactly 1 argument (0 given)
Run Code Online (Sandbox Code Playgroud)

我可以写两个函数,但这似乎效率很低,并不能解释为什么程序以这种方式运行.

Tig*_*kT3 5

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

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

  1. def select_all(event=None)而不是定义你的功能def select_all(event).这将使你的函数期望0或1个参数,默认为一eventNone,如果没有参数传递给它.(谢谢,@布莱恩.)

  2. def select_all(*event)而不是定义你的功能def select_all(event).这将允许您的函数期望任意数量的位置参数,包括0或1.这个的通用名称是*args,或"star 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])).