Home > Back-end >  tkinter Toplevel window won't open from system tray menu
tkinter Toplevel window won't open from system tray menu

Time:01-26

I'm trying to open a Toplevel window with tkinter, from a system tray menu.

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

But this unfortunately will not work, it won't pull up the toplevel window, nor the main one. If I then open the root window myself, the toplevel window will open, but be unresponsive.

CodePudding user response:

As told, I added the root.

Works, kindof. Still cannot get the eventloop figured out.

def quit_window(icon, item):
    icon.stop()
    root.destroy()
    exit()


def hidden(root):
    global my_img1
    top=Toplevel(root)
    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)
    top.mainloop()


def hide_window():
    root.withdraw()
    image=Image.open("screen.ico")
    try:
        if pickle.load(open("window.dat","rb")) ==1:
            menu=(item('Dev window',lambda: hidden(root)),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()

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)





root.mainloop()

It still does not respond, neither with top.mainloop() or root.mainloop()

I didn't want the hidden function to be in "show window", this function is for root alone. I want some sort of hidden menu, in a sense. One I can open from taskbar without opening root, only displaying the toplevel window.

Thanks for your help so far mate.

CodePudding user response:

The Toplevel() remains unresponsive because it has no event loop attached (mainloop()) because in this code the Toplevel acts as a standalone main window.

Need to attach this Toplevel to the root - top = Toplevel(root) where root is passed as argument to hidden(root). This way the root event loop works for all widget children such as a Toplevel. This would help towards your main part of the question.

(#added...) so there is no need for top.mainloop() because now that the root is the master/parent top is inside root.mainloop().

The event loop is for checking in to any events that happen on your widget which you would normally program with bind(). eg top.bind('<Button>',dosomething) where dosomething is a defined function. (...#added)

If you want a title for top then you need to create your own title bar or label if you are using overrideredirect(True) because this removes the platform window manager.

(#added...) The platform window manager is not so much removed as it is not being used when using overrideredirect(True). This is probably another reason why your window seems unresponsive with this stage of code. Need to code for events attached to the widget yourself - as you have done with the Button widget to close. (...#added)

For main part of question: there is nothing that refers to top widget in show_window in this code.

(#added...) could look at making top a class and instantiate that in the root. The default status of hidden`` for top``` could be an attribute of this class. Then you can change the class attribute to hide or show functionally inside the body of the code somewhereelse.

eg skeleton sketch:

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

!!! obviously very brief general idea that needs work here of a way to maintain your design which seems quite good to me. (...#added)

  •  Tags:  
  • Related