我正在尝试从系统托盘菜单中使用 tkinter 打开一个 Toplevel
窗口。
from cmath import phase
from tkinter import *
from tkinter import messagebox, messagebox
from tracemalloc import start
from pystray import MenuItem as item
import pystray
from PIL import ImageTk,Image
import pickle
def quit_window(icon, item):
icon.stop()
root.destroy()
exit()
def hidden():
global my_img1
top=Toplevel()
top.title("Secret menu, shhh :^)")
top.overrideredirect(True)
top.attributes('-alpha', 0.9)
w = 1100
h = 450
ws = top.winfo_screenwidth()
hs = top.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/3) - (h/2)
top.geometry('%dx%d+%d+%d' % (w, h, x, y))
top.iconbitmap('screen.ico')
my_img1 = ImageTk.PhotoImage(Image.open("ITEXTRA.png"))
label1=Label(top,image=my_img1).place(relx=0.01,rely=0.01)
button2=Button(top,text="Close window",bg='#ff4a65',command=top.destroy, relief=GROOVE).place(relx=0.9,rely=0.9)
# Marks window as used
hiddenwindow=1
pickle.dump(hiddenwindow, open("window.dat", "wb"))
Button(root, text="Developer Options", padx=57, bg="#86b3b3",fg="black", command = hidden).grid(row=3,column=0)
def hide_window():
root.withdraw()
image=Image.open("screen.ico")
menu=(item('Dev window', hidden),item('show window', show_window),item('Exit app', quit_window))
icon=pystray.Icon("ITExtra", image, "Program", menu)
icon.run()
def show_window(icon, item):
icon.stop()
root.after(0,root.deiconify())
root.after(0,root.focus_force)
root = Tk()
root.title("ITextra")
root.geometry("400x400")
root.protocol('WM_DELETE_WINDOW', hide_window)
hidden()
root.mainloop()
但不幸的是,这不起作用,它不会拉起顶层窗口,也不会拉起主窗口。 如果我自己打开根窗口,顶层窗口将打开,但没有响应。
编辑 好吧,所以我尝试将 topwindow 添加为类,但我不断收到错误“Top”对象没有属性“tk”。 我粘贴了下面更新的代码。任何帮助总是非常感谢!
from cmath import phase
from tkinter import *
from tkinter import messagebox, messagebox
from tracemalloc import start
from pystray import MenuItem as item
import pystray
from PIL import ImageTk,Image
import pickle
class Top():
def __init__(self,master=None):
self.hide = True
def hidden(self):
if self.hide:
global my_img1
self.top=Toplevel(root)
self.top.title("Secret menu, shhh :^)")
self.top.attributes('-alpha', 0.9)
w = 1100
h = 450
ws = self.top.winfo_screenwidth()
hs = self.top.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/3) - (h/2)
self.top.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.top.iconbitmap('screen.ico')
my_img1 = ImageTk.PhotoImage(Image.open("ITEXTRA.png"))
label1=Label(self.top,image=my_img1).place(relx=0.01,rely=0.01)
button2=Button(self.top,text="Close window",bg='#ff4a65',command=self.top.destroy, relief=GROOVE).place(relx=0.9,rely=0.9)
# Marks window as used
hiddenwindow=1
pickle.dump(hiddenwindow, open("window.dat", "wb"))
self.top.mainloop()
def somewhereelse():
top.hide = True
top.hidden()
def quit_window(icon, item):
icon.stop()
root.destroy()
exit()
def show_window(icon, item):
icon.stop()
root.after(0,root.deiconify())
root.after(0,root.focus_force)
def hide_window():
root.withdraw()
image=Image.open("screen.ico")
try:
if pickle.load(open("window.dat","rb")) ==1:
menu=(item('Dev window', top.hidden),
item('show window', show_window),
item('Exit app', quit_window))
else:
menu=(item('Exit app', quit_window))
except:
menu=(item('Exit app', quit_window))
icon=pystray.Icon("ITextra", image, "Program", menu)
icon.run()
root = Tk()
root.title("ITextra")
root.geometry("400x400")
top = Top(root) #in main part
root.protocol('WM_DELETE_WINDOW', hide_window)
Button(root, text="Developer Options", padx=57, bg="#86b3b3",fg="black", command =top.hidden).grid(row=3,column=0)
root.mainloop()
顶部窗口仍然没有响应 不是当 root 打开时,而是当 top 自行打开时,它仍然没有响应。但是,当我单击按钮并拖动鼠标时,它会做出响应。我尝试在顶部添加一个主循环,但是 self.top.mainloop 和 root.mainloop 都不起作用。 我尝试使用绑定(bind),但它们也显示出相同的行为。
我是否创建了一些不起作用的东西?
我正在创建的应用程序是多线程的,我的问题是;这会让其他类的事情变得复杂吗?我对编码很陌生,坦率地说我不知道。 我将整个项目放在粘贴箱中 here ,对于任何有兴趣的人。我认为这很困惑,但对于初学者来说我仍然感到非常自豪。
最佳答案
Toplevel()
保持无响应,因为它没有附加事件循环 ( mainloop()
),因为在此代码中,顶层充当独立的主窗口。
需要将此顶级附加到根 - top = Toplevel(root)
其中 root 作为参数传递给 hidden(root)
。这样,根事件循环适用于所有小部件子项,例如 Toplevel
。这将有助于解决问题的主要部分。
(#added...) 所以不需要 top.mainloop()
因为现在根是主/父top
在里面root.mainloop()
.
事件循环用于检查小部件上发生的任何事件,您通常使用bind()
进行编程。例如
top.bind('<Button>',dosomething)
哪里dosomething
是一个已定义的函数。
(...#已添加)
如果您想要 top
的标题如果您使用 overrideredirect(True)
那么您需要创建自己的标题栏或标签因为这会删除平台窗口管理器。
(#已添加...)
平台窗口管理器并没有被删除太多,因为它在使用overrideredirect(True)
时没有被使用。 。这可能是您的窗口似乎对此阶段的代码没有响应的另一个原因。需要自己为附加到小部件的事件进行编码 - 正如您对 Button
所做的那样要关闭的小部件。
(...#已添加)
对于问题的主要部分:
没有任何内容涉及 top
小部件 show_window
在此代码中。
(#已添加...)
可以看看制作 top
一个类并在根中实例化它。默认状态hidden
对于 top
可能是这个类的一个属性。然后,您可以更改类属性以在代码正文中的其他位置隐藏或显示功能。
例如骨架草图:
class Top():
def __init__(self,master=None):
...
self.hide = True
...
def hidden(self):
if self.hide:
...
def somewhereelse():
top.hide = true
top.hidden()
top = Top(root) #in main part
!!!显然,非常简短的总体想法需要在这里工作,以维护您的设计,这对我来说似乎相当不错。有多种方法可以将 Toplevel 小部件合并到类中,但这有点偏离了原始问题。 (...#已添加)
添加于 1 月 28 日...
推荐学习class
更彻底,而不是仅仅以我的例子为例。但这里还有一点
class Top():
def __init__(self,master=None):
super().__init__()
self.master = master
self.hide = True
def hidden(self):
...
self.top = Toplevel(self.master)
...
用我的话来说,但请检查 Python 文档,super().__init__()
将调用继承对象的初始化函数,在本例中返回到 self.master
这是 root
然后返回tk.__init__
在 Tk()
中调用.
我建议查看代码__init__.py
文件在 Lib\tkinter\
Python 下载中的文件夹,以便更好地了解 tkinter 的工作原理。
我认为这绝对是可以实现的,但可能需要不同的 GUI - 同意这对于初学者来说是一个很好的开始,因此并不是真正的困惑!!
使用class
对于实现您想要做的事情并不是必需的,但是类对于封装对象非常有用,以便可以为您的项目自定义与该对象相关的任何额外属性和方法。这使得进一步或 future 的开发变得更加容易。
...添加于 1 月 28 日
关于python - tkinter 顶级窗口不会从系统托盘菜单打开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70839527/