Tkinter overridedirect (minimizing and windows task bar issues)

Question:

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()
Asked By: Allen Dolgonos

||

Answers:

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!

Answered By: Allen Dolgonos

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

Answered By: SS EE
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.