tkinter Toplevel window 无法从系统托盘菜单打开
tkinter Toplevel window won't open from system tray menu
我正在尝试使用 tkinter 从系统托盘菜单打开 Toplevel
window。
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()
但不幸的是,这不会起作用,它不会拉起顶层 window,也不会拉起主层。
如果我自己打开根 window,顶层 window 将打开,但没有响应。
编辑
好的,所以我尝试将 topwindow 添加为 class,但我一直收到错误 'Top' object has no attribute '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()
置顶window仍然没有反应
不是当 root 打开时,而是当 top 自己打开时,它再次保持无响应。但是,当我单击按钮并拖动鼠标时,它会响应。我尝试在顶部添加一个主循环,但是 self.top.mainloop
和 root.mainloop
都不起作用。
我尝试使用绑定,但它们也表现出相同的行为。
我创建的东西行不通吗?
我正在创建的应用程序是多线程的,我的问题是;这会使其他 classes 变得复杂吗?我对编码很陌生,坦率地说不知道。
我将整个项目放在一个 pastebin here 中,供任何感兴趣的人使用。我觉得这很乱,但对于初学者来说我还是很自豪的。
Toplevel()
仍然没有响应,因为它没有附加事件循环 (mainloop()
),因为在这段代码中 Toplevel 充当独立的主要 window。
需要将此 Toplevel 附加到根 - top = Toplevel(root)
其中根作为参数传递给 hidden(root)
。这样,根事件循环适用于所有小部件 children,例如 Toplevel
。这将有助于解决问题的主要部分。
(#added...) 所以不需要 top.mainloop()
因为现在根是 master/parent top
在 root.mainloop()
.
事件循环用于检查您的小部件上发生的任何事件,您通常会使用 bind()
进行编程。例如
top.bind('<Button>',dosomething)
其中 dosomething
是定义的函数。
(...#added)
如果您想要 top
的标题,那么如果您使用 overrideredirect(True)
,则需要创建自己的标题栏或标签,因为这会删除平台 window 管理器。
(#已添加...)
平台 window 管理器并没有被删除,因为它在使用 overrideredirect(True)
时没有被使用。这可能是您的 window 似乎对这一阶段的代码没有反应的另一个原因。需要自己为附加到小部件的事件编写代码 - 正如您对要关闭的 Button
小部件所做的那样。
(...#added)
对于问题的主要部分:
此代码中 show_window
中没有任何内容涉及 top
小部件。
(#已添加...)
可以看看使 top
成为 class 并在根目录中实例化它。 top
的 hidden
的默认状态可能是此 class 的属性。然后,您可以更改 class 属性以在其他地方的代码 body 中隐藏或显示功能。
例如骨架草图:
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 小部件合并到 class 中,但这与原始问题有点不同。
(...#added)
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__()
将调用继承的 object 的初始化函数,在这种情况下会返回到 self.master
是 root
,然后返回到 tk.__init__
,它在 Tk()
.
中被调用
我建议查看 Python 下载中 Lib\tkinter\
文件夹中的代码 __init__.py
文件,以更好地理解 tkinter 的工作原理。
我认为这绝对是可以实现的,但可能需要不同的 GUI - 同意这对初学者来说是一个很好的开始,因此并不是一团糟!
使用 class
并不是实现你想要做的事情所必需的,但是 classes 对于封装一个 object 非常有用,这样任何额外的属性和方法都可以与 object 可以为您的项目定制。这使得进一步或未来的开发更容易。
...添加于 1 月 28 日
我正在尝试使用 tkinter 从系统托盘菜单打开 Toplevel
window。
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()
但不幸的是,这不会起作用,它不会拉起顶层 window,也不会拉起主层。 如果我自己打开根 window,顶层 window 将打开,但没有响应。
编辑 好的,所以我尝试将 topwindow 添加为 class,但我一直收到错误 'Top' object has no attribute '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()
置顶window仍然没有反应
不是当 root 打开时,而是当 top 自己打开时,它再次保持无响应。但是,当我单击按钮并拖动鼠标时,它会响应。我尝试在顶部添加一个主循环,但是 self.top.mainloop
和 root.mainloop
都不起作用。
我尝试使用绑定,但它们也表现出相同的行为。
我创建的东西行不通吗?
我正在创建的应用程序是多线程的,我的问题是;这会使其他 classes 变得复杂吗?我对编码很陌生,坦率地说不知道。 我将整个项目放在一个 pastebin here 中,供任何感兴趣的人使用。我觉得这很乱,但对于初学者来说我还是很自豪的。
Toplevel()
仍然没有响应,因为它没有附加事件循环 (mainloop()
),因为在这段代码中 Toplevel 充当独立的主要 window。
需要将此 Toplevel 附加到根 - top = Toplevel(root)
其中根作为参数传递给 hidden(root)
。这样,根事件循环适用于所有小部件 children,例如 Toplevel
。这将有助于解决问题的主要部分。
(#added...) 所以不需要 top.mainloop()
因为现在根是 master/parent top
在 root.mainloop()
.
事件循环用于检查您的小部件上发生的任何事件,您通常会使用 bind()
进行编程。例如
top.bind('<Button>',dosomething)
其中 dosomething
是定义的函数。
(...#added)
如果您想要 top
的标题,那么如果您使用 overrideredirect(True)
,则需要创建自己的标题栏或标签,因为这会删除平台 window 管理器。
(#已添加...)
平台 window 管理器并没有被删除,因为它在使用 overrideredirect(True)
时没有被使用。这可能是您的 window 似乎对这一阶段的代码没有反应的另一个原因。需要自己为附加到小部件的事件编写代码 - 正如您对要关闭的 Button
小部件所做的那样。
(...#added)
对于问题的主要部分:
此代码中 show_window
中没有任何内容涉及 top
小部件。
(#已添加...)
可以看看使 top
成为 class 并在根目录中实例化它。 top
的 hidden
的默认状态可能是此 class 的属性。然后,您可以更改 class 属性以在其他地方的代码 body 中隐藏或显示功能。
例如骨架草图:
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 小部件合并到 class 中,但这与原始问题有点不同。 (...#added)
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__()
将调用继承的 object 的初始化函数,在这种情况下会返回到 self.master
是 root
,然后返回到 tk.__init__
,它在 Tk()
.
我建议查看 Python 下载中 Lib\tkinter\
文件夹中的代码 __init__.py
文件,以更好地理解 tkinter 的工作原理。
我认为这绝对是可以实现的,但可能需要不同的 GUI - 同意这对初学者来说是一个很好的开始,因此并不是一团糟!
使用 class
并不是实现你想要做的事情所必需的,但是 classes 对于封装一个 object 非常有用,这样任何额外的属性和方法都可以与 object 可以为您的项目定制。这使得进一步或未来的开发更容易。
...添加于 1 月 28 日