代码之家  ›  专栏  ›  技术社区  ›  David González Blazman

自制Tkinter弹出菜单Python

  •  0
  • David González Blazman  · 技术社区  · 6 年前

    我在用Python编写一个基于tkinter的GUI库,并设计和构建了所有的小部件,但是我来到了弹出菜单。 由于tkinter选择了系统菜单,而这无法定制,所以我编写了以下代码来制作一个框架,在这个框架中,我可以将定制的按钮放入并作为弹出窗口工作。

    from tkinter import *
    
    root = Tk()
    
    w = Label(root, text="Right-click to display menu", width=40, height=20)
    w.place(x=0)
    
    
    def function1():
        print('function1 activated')
    # create a menu
    f = Frame(root,width=80,height=60,background='green')
    b2 = Button(f,text='function',command=function1)
    b2.pack()
    
    def open_popup(event):
        try:
            f.place(x=event.x, y=event.y)
            root.after(1)
            f.focus_set()
            w.bind_all("<Button-1>",close_popup)
        except:
            print("Can't open popup menu")
    
    def close_popup(event):
        try:
            f.place_forget()
            root.after(1)
            w.unbind_all("<Button-1>")
        except:
            print("Can't close popup menu")
    
    w.bind("<Button-3>", open_popup)
    
    b = Button(root, text="Quit", command=root.destroy)
    b.pack()
    
    root.mainloop()
    

    一切正常,如果我用鼠标右键点击弹出菜单出现,如果我点击其他部分弹出菜单消失。 问题是,由于 bind_all 当我按下弹出菜单的按钮时, function1 不运行,事件处理程序将关闭弹出窗口。我只试过 bind 但这次, 功能1 运行而事件处理程序不激活。

    我能做到吗?

    2 回复  |  直到 6 年前
        1
  •  0
  •   Mike - SMT    6 年前

    我会用一个跟踪变量。

    None f 作为检查 f型 当前已设置。

    f型 不是没有,然后我们创建框架和按钮。然后当功能被激活时,我们可以运行函数并销毁按钮所在的帧。这也破坏了按钮,然后我们设置 f型 供下次使用。

    请看下面重新编写的示例。 如果你有任何问题,请告诉我。

    from tkinter import *
    
    root = Tk()
    
    w = Label(root, text="Right-click to display menu", width=40, height=20)
    w.place(x=0)
    f = None # Tracking F to see if it is None or not.
    
    def function1():
        global f
        print('function1 activated')
        # add this to the end of the function to destroy the frame and reset f
        if f != None:
            f.destroy()
            f = None
    
    def open_popup(event):
        global f
        # if f is None then create frame and button else don't
        if f == None:
            f = Frame(root,width=80,height=60,background='green')
            f.place(x=event.x, y=event.y)
            b2 = Button(f,text='function',command=function1)
            b2.pack()
        else:
            print("Can't open popup menu")
    
    
    w.bind("<Button-3>", open_popup)
    b = Button(root, text="Quit", command=root.destroy)
    b.pack()
    
    root.mainloop()
    
        2
  •  0
  •   David González Blazman    6 年前

    我找到了一种不用修改太多代码的方法,跟踪变量的想法很好,但并不能解决所有的问题,而这段代码确实解决了。

    from tkinter import *
    
    root = Tk()
    
    w = Label(root, text="Right-click to display menu", width=40, height=20)
    w.pack()
    
    
    def function1():
        print('function1 activated')
        try:
            f.place_forget()
        except:
            pass
    # create a menu
    f = Frame(root,width=80,height=60,background='green')
    b2 = Button(f,text='function',command=function1)
    b2.place(x=0,y=5)
    
    def open_popup(event): 
        try:
            f.place(x=event.x, y=event.y)
            root.after(1)
            f.focus_set()
        except:
            pass
    
    def close_popup(event):
        try:
            f.place_forget()
            root.after(1)
            w.unbind_all("<Button-1>")
        except:
            pass
    
    def enable_depopup(event):
        w.bind_all("<Button-1>",close_popup)
    
    def disable_depopup(event):
        w.unbind_all("<Button-1>")
    
    w.bind("<Button-3>", open_popup)
    w.bind("<Motion>", enable_depopup)
    f.bind("<Motion>", disable_depopup)
    
    b = Button(root, text="Quit", command=root.destroy)
    b.pack()
    root.mainloop()
    

    这样,每当我在父窗口上移动鼠标时 <Button-1> 鼠标被绑定以关闭弹出菜单。 <按钮-1> 绑定让我点击按钮。 按钮的功能激活 place_forget 方法的框架,所以一切正常工作。