0

What I'm trying to achieve is a Tkinter window, using overridedirect, that show up in your taskbar. You can minimize it like a normal window, and bring it back up like a normal window. The problem that I'm having right now is that I've achieved adding it to the taskbar, but for some reason when you minimize it and then bring it back, it's no longer on the taskbar.

# Imports
from tkinter import *
from ctypes import windll
# Some WindowsOS styles, required for task bar integration
GWL_EXSTYLE = -20
WS_EX_APPWINDOW = 0x00040000
WS_EX_TOOLWINDOW = 0x00000080
def set_appwindow(mainWindow):
    # Honestly forgot what most of this stuff does. I think it's so that you can see 
# the program in the task bar while using overridedirect. Most of it is taken 
# from a post I found on stackoverflow.
    hwnd = windll.user32.GetParent(mainWindow.winfo_id())
    stylew = windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
    stylew = stylew & ~WS_EX_TOOLWINDOW
    stylew = stylew | WS_EX_APPWINDOW
    res = windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, stylew)
    # re-assert the new window style
    mainWindow.wm_withdraw()
    mainWindow.after(10, lambda: mainWindow.wm_deiconify())
def main():
    global mainWindow
    # Default window configuration
    mainWindow = Tk()
    mainWindow.geometry('800x400')
    mainWindow.resizable(width=False, height=False)
    mainWindow.overrideredirect(True)
    mainWindow.after(10, lambda: set_appwindow(mainWindow))
    def exitGUI():
        mainWindow.destroy()
    def minimizeGUI():
        mainWindow.state('withdrawn')
        mainWindow.overrideredirect(False)
        mainWindow.state('iconic')
    def frameMapped(event=None):
        mainWindow.overrideredirect(True)
        mainWindow.state("normal")
        mainWindow.iconbitmap("ANALOG.ico")
    exitButton = Button(mainWindow, text='', bg='#212121', fg='#35DAFF',
     command=exitGUI)
    minimizeButton = Button(mainWindow, text='', bg="#212121", fg='#35DAFF',
     command=minimizeGUI)
    exitButton.place(x=780, y=0)
    minimizeButton.place(x=759, y=0)
    mainWindow.bind("<Map>", frameMapped) # This brings back the window
    mainWindow.mainloop()  # Window Loop
if __name__ == '__main__':
    main()
Saad
  • 3,340
  • 2
  • 10
  • 32
  • Using `overridedirect` has such a disadvantage and i dont think there is actually a way around it. – Delrius Euphoria Aug 02 '20 at 14:35
  • Take a look at [this](https://stackoverflow.com/questions/4066027/making-tkinter-windows-show-up-in-the-taskbar) – Delrius Euphoria Aug 02 '20 at 14:37
  • @CoolCloud I guess there is by making a root invisible and then use a toplevel instead. But I dont get this with that fancy stuff. I like my applications to fit in the system. – Thingamabobs Aug 02 '20 at 14:40
  • @CoolCloud your link shows this idea, but there are missing some points. Since he would like to minimize his window. He need to set this toplevel as transient or a group as well. – Thingamabobs Aug 02 '20 at 14:45
  • transient? i thought once the window is transient it wont show up as a window nd is harder to minimize? – Delrius Euphoria Aug 02 '20 at 14:47
  • thats why I updated to group. You are right when you say it "has such a disadvantage". – Thingamabobs Aug 02 '20 at 14:48

2 Answers2

3

Okay guys, I finally figured it out.

# Imports
from tkinter import *
from ctypes import windll

# Some WindowsOS styles, required for task bar integration
GWL_EXSTYLE = -20
WS_EX_APPWINDOW = 0x00040000
WS_EX_TOOLWINDOW = 0x00000080

lastClickX = 0
lastClickY = 0


def SaveLastClickPos(event):
    global lastClickX, lastClickY
    lastClickX = event.x
    lastClickY = event.y


def Dragging(event):
    x, y = event.x - lastClickX + mainWindow.winfo_x(), event.y - lastClickY + mainWindow.winfo_y()
    mainWindow.geometry("+%s+%s" % (x , y))

def set_appwindow(mainWindow):
    # Honestly forgot what most of this stuff does. I think it's so that you can see
    # the program in the task bar while using overridedirect. Most of it is taken
    # from a post I found on stackoverflow.
    hwnd = windll.user32.GetParent(mainWindow.winfo_id())
    stylew = windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
    stylew = stylew & ~WS_EX_TOOLWINDOW
    stylew = stylew | WS_EX_APPWINDOW
    res = windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, stylew)
    # re-assert the new window style
    mainWindow.wm_withdraw()
    mainWindow.after(10, lambda: mainWindow.wm_deiconify())


def main():
    global mainWindow, z
    # Default window configuration
    mainWindow = Tk()
    mainWindow.geometry('800x400')
    mainWindow.resizable(width=False, height=False)
    mainWindow.overrideredirect(True)
    mainWindow.after(10, lambda: set_appwindow(mainWindow))
    mainWindow.bind('<Button-1>', SaveLastClickPos)
    mainWindow.bind('<B1-Motion>', Dragging)
    z = 0

    def exitGUI():
        mainWindow.destroy()

    def minimizeGUI():
        global z
        mainWindow.state('withdrawn')
        mainWindow.overrideredirect(False)
        mainWindow.state('iconic')
        z = 1

    def frameMapped(event=None):
        global z
        mainWindow.overrideredirect(True)
        mainWindow.iconbitmap("ANAL_OG.ico")
        if z == 1:
            set_appwindow(mainWindow)
            z = 0


    exitButton = Button(mainWindow, text='', bg='#212121', fg='#35DAFF',
                        command=exitGUI)
    minimizeButton = Button(mainWindow, text='', bg="#212121", fg='#35DAFF',
                            command=minimizeGUI)
    exitButton.place(x=780, y=0)
    minimizeButton.place(x=759, y=0)
    mainWindow.bind("<Map>", frameMapped)  # This brings back the window
    mainWindow.mainloop()  # Window Loop


if __name__ == '__main__':
    main()

Thanks for all your suggestions!

1

If you want to create your own minimize button while having 'root.overrideredirect(True)', You can try this code.

import tkinter as tk
root = tk.Tk()
#actual part========
root.overrideredirect(True)
def minimize_root_drawn():
    root.state('withdrawn')
    root.overrideredirect(False)
    root.state('iconic')
def minimize_root_threw(a):
    root.overrideredirect(True)
root.bind("<Map>", minimize_root_threw)
#=============
root_min_button = tk.Button(title_bar, text='-', height=1, width=2, font=('Comic Sans', 10), activebackground='gray', command=minimize_root_drawn)
root_min_button.pack(side=tk.RIGHT)

For this example, i call 'minimize_root_drawn()' from the '-' button, commonly known as 'Minimize', to make root.overrideredirect(False), then i detect if the root has opened up with 'root.bind("", minimize_root_threw), to change 'root.overrideredirect(True)' so there is never the default task bar on top

SS EE
  • 11
  • 1