7

I'm making a music player GUI and I can't make it appear on the taskbar or in Alt-Tab. I have set overrideredirect() to true to remove the borders and the title. I also made it so that when the user does a 'mouse click and drag' action the window moves. Here's the code:

import tkinter
import sys
import os


class Win(tkinter.Tk):
    global imgfile
    imgfile = r"play.png"

    def __init__(self, master=None):
        def close():
            self.destroy()
            sys.exit()

        def dirchosen():
            global songlist
            songlist = []
            try:
                os.chdir(dirinput.get())
            except:
                print("Invalid Directory")
                raise
            for file in os.listdir(dirinput.get()):
                songlist.append(file)

        tkinter.Tk.__init__(self, master)
        self.overrideredirect(True)
        self._offsetx = 0
        self._offsety = 0

        self.bind('<Button-1>', self.clickwin)
        self.bind('<B1-Motion>', self.dragwin)

        self.geometry("350x200")
        self.config(bg="#FF4766")

        titlelabel = tkinter.Label(self, text="FoxSGR Media Player", bg="#FF4766", font=("Segoe UI", 12))
        titlelabel.pack(ipady=4)

        chdirbutton = tkinter.Button(self, relief="groo", activebackground="#FF8080", command=dirchosen)
        chdirbutton.config(text="Choose Directory", bg="#FF4766", font=("Segoe UI", 8))
        chdirbutton.pack()
        chdirbutton.place(relx=0.66, rely=0.22)

        dirinput = tkinter.Entry(self, font=("Segoe UI", 8), width="34")
        dirinput.pack()
        dirinput.place(relx=0.05, rely=0.23)

        xbutton = tkinter.Button(self, text="x", height="1", command=close)
        xbutton.config(bg="red", activebackground="#FF8080", relief="groo", font=("Segoe UI", 8))
        xbutton.pack()
        xbutton.place(relx=0.90, rely=0.05)

    def dragwin(self, event):
        x = self.winfo_pointerx() - self._offsetx
        y = self.winfo_pointery() - self._offsety
        self.geometry('+{x}+{y}'.format(x=x, y=y))

    def clickwin(self, event):
        self._offsetx = event.x
        self._offsety = event.y

win = Win()

# Had to set the images appart from up there

imgplay = tkinter.PhotoImage(file=imgfile)
playbutton = tkinter.Button(win, image=imgplay, bg="#FF4766", relief="flat")
playbutton.pack()
playbutton.place(rely=0.45, relx=0.4)

imgnext = tkinter.PhotoImage(file="next.png")
nextbutton = tkinter.Button(win, image=imgnext, bg="#FF4766", relief="flat")
nextbutton.pack()
nextbutton.place(rely=0.45, relx=0.57)

imgprev = tkinter.PhotoImage(file="previous.png")
prevbutton = tkinter.Button(win, image=imgprev, bg="#FF4766", relief="flat")
prevbutton.pack()
prevbutton.place(rely=0.45, relx=0.30)

win.mainloop()

Is there any way that I can make it at least appear in Alt-Tab?

FoxSGR
  • 105
  • 3
  • 6
  • This doesn't answer your question, but from your comment after `win = Win()`, I'm guessing you had some trouble getting images to render properly when you created them inside the class. This is because of premature garbage collection of PhotoImage instances. See [Why do my Tkinter images not appear?](http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm) for guidance. – Kevin Jun 29 '15 at 19:13
  • @Kevin I had seen that article before when I was trying to figure the images problem, but it didn't help much at that time. Maybe I didn't apply what's in that page that correctly. – FoxSGR Jun 29 '15 at 19:26
  • are you running the project as a script or freezing it? – timeyyy Jul 01 '15 at 08:35
  • Related answer: https://stackoverflow.com/a/6662135/10742758 – Maximouse Feb 09 '20 at 11:24

1 Answers1

8

after a bit of research i have found that there is a way to do this, but it involves using ctypes and is a windows only solution:

import tkinter as tk
import tkinter.ttk as ttk
from ctypes import windll

GWL_EXSTYLE=-20
WS_EX_APPWINDOW=0x00040000
WS_EX_TOOLWINDOW=0x00000080

def set_appwindow(root):
    hwnd = windll.user32.GetParent(root.winfo_id())
    style = windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
    style = style & ~WS_EX_TOOLWINDOW
    style = style | WS_EX_APPWINDOW
    res = windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, style)
    # re-assert the new window style
    root.wm_withdraw()
    root.after(10, lambda: root.wm_deiconify())

def main():
    root = tk.Tk()
    root.wm_title("AppWindow Test")
    button = ttk.Button(root, text='Exit', command=lambda: root.destroy())
    button.place(x=10,y=10)
    root.overrideredirect(True)
    root.after(10, lambda: set_appwindow(root))
    root.mainloop()

if __name__ == '__main__':
    main()

this involves using ctypes to manipulate the windows style, however you need to use the right Get/Set functions depending on the applications environment. for 32 bit windows it seems you need to use either:
GetWindowLongW and SetWindowLongW
or
GetWindowLongA and SetWindowLongA

but 64 bit needs:
GetWindowLongPtrW and SetWindowLongPtrW
or
GetWindowLongPtrA and SetWindowLongPtrA
see this

or alternatively, if you want this behaviour by default:

import tkinter as tk

from ctypes import windll

class Tk(tk.Tk):
    def overrideredirect(self, boolean=None):
        tk.Tk.overrideredirect(self, boolean)
        GWL_EXSTYLE=-20
        WS_EX_APPWINDOW=0x00040000
        WS_EX_TOOLWINDOW=0x00000080
        if boolean:
            print("Setting")
            hwnd = windll.user32.GetParent(self.winfo_id())
            style = windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
            style = style & ~WS_EX_TOOLWINDOW
            style = style | WS_EX_APPWINDOW
            res = windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, style)
        self.wm_withdraw()
        self.wm_deiconify()
James Kent
  • 5,763
  • 26
  • 50
  • Thanks a lot! Adding functions for minimizing the window are causing overrideredirect to be set to False and no matter what I do, it stays the same after that. Can you please show me how to add that functionality to this code – Subham Burnwal Jun 28 '20 at 21:18
  • 1
    Guys please. For whoever wants to achieve this, read this answer carefully. You will thank James Kent later, trust me. First chunk of code he provided works perfectly, without any issues for me – Thalis May 22 '21 at 09:24