【问题标题】:Stardand context menu in Python TKinter text widget when mouse right button is pressed按下鼠标右键时 Python TKinter 文本小部件中的标准上下文菜单
【发布时间】:2011-05-15 01:44:54
【问题描述】:

我正在使用 Python 2.6.x 和 TKinter 开发 Windows XP。在应用程序中使用文本小部件,但缺少标准弹出菜单(剪切、复制、粘贴、删除、全选)。如何让它出现?

【问题讨论】:

  • 右键单击上下文菜单,以及出现在此类菜单上的内容(如果出现)尚未广泛标准化。在支持它的平台上,对于某些应用程序(如编辑文本)有许多约定。 tkinter API 是独立于平台的,所以如果你想要这个功能,我相信你必须编写(或找到)实现它的代码或接近你想要的东西。

标签: python menu popup tkinter contextmenu


【解决方案1】:

感谢this post,我找到了方法。我做了一些修改。在底部有一个最小的main 可以尝试。

from Tkinter import *

def rClicker(e):
    ''' right click context menu for all Tk Entry and Text widgets
    '''

    try:
        def rClick_Copy(e, apnd=0):
            e.widget.event_generate('<Control-c>')

        def rClick_Cut(e):
            e.widget.event_generate('<Control-x>')

        def rClick_Paste(e):
            e.widget.event_generate('<Control-v>')

        e.widget.focus()

        nclst=[
               (' Cut', lambda e=e: rClick_Cut(e)),
               (' Copy', lambda e=e: rClick_Copy(e)),
               (' Paste', lambda e=e: rClick_Paste(e)),
               ]

        rmenu = Menu(None, tearoff=0, takefocus=0)

        for (txt, cmd) in nclst:
            rmenu.add_command(label=txt, command=cmd)

        rmenu.tk_popup(e.x_root+40, e.y_root+10,entry="0")

    except TclError:
        print ' - rClick menu, something wrong'
        pass

    return "break"


def rClickbinder(r):

    try:
        for b in [ 'Text', 'Entry', 'Listbox', 'Label']: #
            r.bind_class(b, sequence='<Button-3>',
                         func=rClicker, add='')
    except TclError:
        print ' - rClickbinder, something wrong'
        pass


if __name__ == '__main__':
    master = Tk()
    ent = Entry(master, width=50)
    ent.pack(anchor="w")

    #bind context menu to a specific element
    ent.bind('<Button-3>',rClicker, add='')
    #or bind it to any Text/Entry/Listbox/Label element
    #rClickbinder(master)

    master.mainloop()

【讨论】:

  • rClickbinder 在上面的示例中显得多余。或者我想你应该在打电话给mainloop()之前打电话给rClickbinder(master)
  • @scorpiodawg 你说得对,我已经编辑了答案:rClickbinder 在那里是因为它是一种有用的方法,可以在列出的类型的每个元素上启用上下文菜单。
【解决方案2】:

我想我会根据 stackoverflow 上的几个代码 sn-ps 分享我的解决方案。它包括一个最低限度的测试应用程序:

编辑:类绑定可能不起作用。如果是这种情况,请使用普通绑定并在 select_all 函数中返回“break”。

import Tkinter as tk

if 1:  # nice widgets
    import ttk
else:
    ttk = tk

class EntryPlus(ttk.Entry):
    def __init__(self, *args, **kwargs):
        ttk.Entry.__init__(self, *args, **kwargs)
        _rc_menu_install(self)
        # overwrite default class binding so we don't need to return "break"
        self.bind_class("Entry", "<Control-a>", self.event_select_all)  
        self.bind("<Button-3><ButtonRelease-3>", self.show_menu)

    def event_select_all(self, *args):
        self.focus_force()
        self.selection_range(0, tk.END)

    def show_menu(self, e):
        self.tk.call("tk_popup", self.menu, e.x_root, e.y_root)

class TextPlus(tk.Text):
    def __init__(self, *args, **kwargs):
        tk.Text.__init__(self, *args, **kwargs)
        _rc_menu_install(self)
        # overwrite default class binding so we don't need to return "break"
        self.bind_class("Text", "<Control-a>", self.event_select_all)  
        self.bind("<Button-3><ButtonRelease-3>", self.show_menu)

    def event_select_all(self, *args):
        self.focus_force()        
        self.tag_add("sel","1.0","end")

    def show_menu(self, e):
        self.tk.call("tk_popup", self.menu, e.x_root, e.y_root)


def _rc_menu_install(w):
    w.menu = tk.Menu(w, tearoff=0)
    w.menu.add_command(label="Cut")
    w.menu.add_command(label="Copy")
    w.menu.add_command(label="Paste")
    w.menu.add_separator()
    w.menu.add_command(label="Select all")        

    w.menu.entryconfigure("Cut", command=lambda: w.focus_force() or w.event_generate("<<Cut>>"))
    w.menu.entryconfigure("Copy", command=lambda: w.focus_force() or w.event_generate("<<Copy>>"))
    w.menu.entryconfigure("Paste", command=lambda: w.focus_force() or w.event_generate("<<Paste>>"))
    w.menu.entryconfigure("Select all", command=w.event_select_all)        


if __name__ == "__main__":

    class SampleApp(tk.Tk):
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, **kwargs)

            self.entry = EntryPlus(self)
            self.text = TextPlus(self)

            self.entry.pack()
            self.text.pack()

            self.entry.insert(0, "copy paste")
            self.text.insert(tk.INSERT, "copy paste")

    app = SampleApp()
    app.mainloop()

【讨论】:

  • self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 可以转化为更易读的self.menu.tk_popup(e.x_root, e.y_root )。 HTH
【解决方案3】:

感谢 Gonzo 的代码和蓝色的 '&lt;Control-c&gt;', 我的 textwidget 右键正常工作。 我没有 50 名声望,但我遇到了一个问题,即无论点击的位置如何,右键都会触发该功能。 通过以下方式得出结论:

    def show_menu(self, e):
       if e.widget==self.text:
          self.tk.call("tk_popup", self.menu, e.x_root, e.y_root)

现在,当您单击文本小部件时,只会触发右侧按钮的弹出窗口。

【讨论】:

    猜你喜欢
    • 2011-01-17
    • 2011-08-27
    • 2019-03-21
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    相关资源
    最近更新 更多