自制Tkinter弹出菜单Python

时间:2018-07-30 09:43:50

标签: python events tkinter popup

我正在基于tkinter的Python中编写GUI库,并且正在设计和构建所有小部件,但是我来到了PopUp菜单。 由于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_allfunction1无法运行,并且事件处理程序将关闭弹出窗口。我仅尝试使用bind,但是这次function1运行并且事件处理程序未激活。

反正我能做到吗? 谢谢

2 个答案:

答案 0 :(得分:0)

我将使用跟踪变量来完成此操作。

我们可以先将None分配给f,以检查当前是否设置了f

如果f不为None,则创建边框和按钮。然后,当激活该功能时,我们可以运行功能并破坏按钮所在的框架。这也破坏了按钮,然后将f设置回None以便下次使用。

看看下面重新制作的示例。 如果您有任何问题,请告诉我。

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()

答案 1 :(得分:0)

我找到了一种无需过多修改代码即可完成此操作的方法,跟踪变量的想法很好,但不能解决所有问题,而此代码确实可以解决。

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>就会被绑定以关闭弹出菜单。 然后做一个技巧,那就是将菜单的按钮向下放置几个像素,这使鼠标通过弹出框到达该按钮,并禁用<Button-1>绑定,让我单击该按钮。 该按钮的功能激活了框架的place_forget方法,因此一切正常。