How can I change the title bar on a Tkinter window to have the "modern" look on macOS?

Viewed 199

By default when we create a simple window on macOS using tkinter it looks like the window on the left. I'm trying to create a window that looks like the one on the right.enter image description here

I've tried Googling this but I can't seem to find a solution. I assume it is because I am not using the correct key terms as "modern title bar" is most likely wrong.

If doing this is not possible using tkinter, are there any recommendations for other GUI libraries that supports this "modern" look?

1 Answers

Here is some code to create a window similar to the window you want. win is where your gui will be. It is a Canvas

from tkinter import *
## if installed: from tkmacosx import *
from tkinter.ttk import Sizegrip
import time

Title="finish mac titlebar"

root=Tk()
root.overrideredirect(1)
## if needed for your mac: root.overrideredirect(0)
root.geometry("300x150")
root.update_idletasks()
root.title(" "+Title+" ")
root.resizable(True, True)
root.maxsize(root.winfo_screenwidth(), root.winfo_screenheight())
root.attributes("-transparent", True)

dummy=Tk()
dummy.geometry("1x1")
dummy.resizable(0,0)
dummy.attributes("-alpha", False)
dummy.title(Title)

def unminimize_me(e):
    root.deiconify()

dummy.bind("<FocusIn>", unminimize_me)

gray="#221F1E"
black="#111010"

root.config(bg=black)

title=Frame(root, bg=gray)
title.pack(fill=X, side=TOP)

win=Canvas(root, width=1, height=1, bg=black, highlightthickness=0)
win.pack(side=TOP, expand=True, fill=BOTH)

bottom=Frame(root, bg=black)
bottom.pack(side=BOTTOM, fill=X)

bottomright=Canvas(bottom,  width=8, height=8, highlightthickness=0, bg="systemTransparent")
bottomright.pack(side=RIGHT)
bottomright.create_oval(-9,-9, 7,7, fill=black, outline=black)

bottomleft=Canvas(bottom,  width=8, height=8, highlightthickness=0, bg="systemTransparent")
bottomleft.pack(side=LEFT)
bottomleft.create_oval(1,-9, 17,7, fill=black, outline=black)

left=Canvas(title, width=8, height=8, highlightthickness=0, bg="systemTransparent")
left.place(x=0, y=0)
left.create_oval(0,0, 16,16, fill=gray, outline=gray)
right=Canvas(title, width=8, height=8, highlightthickness=0, bg="systemTransparent")
right.pack(side=RIGHT, anchor=NE)
right.create_oval(7,1, -9,17, fill=gray, outline=gray)

def get_pos(e):
    xwin=root.winfo_x()
    ywin=root.winfo_y()
    startx=e.x_root
    starty=e.y_root

    ywin=ywin-starty
    xwin=xwin-startx

    def move_window(e):
        if e.x_root+xwin > -1 and e.y_root+ywin >-1:
            root.geometry("+{0}+{1}".format(e.x_root+xwin, e.y_root+ywin))
    startx=e.x_root
    starty=e.y_root

    title.bind("<Button1-Motion>", move_window)
title.bind("<Button-1>", get_pos)

def onx(e):
    close.create_text(8,8, text="x", fill="dark red")

def offx(e):
    close.delete(ALL)
    close.create_oval(1,1, 15,15, outline="dark red", fill="red")

def x(e):
    dummy.unbind("<FocusIn>")
    root.destroy()
    dummy.destroy()

close=Canvas(title, bg=gray, height=16, width=16, highlightthickness=0)
close.create_oval(1,1, 15,15, outline="dark red", fill="red")
close.pack(side=LEFT, pady=3, padx=2)
close.bind("<Enter>", onx)
close.bind("<Leave>", offx)
close.bind("<Button-1>", x)

def onmin(e):
    minimize.create_text(8,8, text="-", fill="goldenrod")

def offmin(e):
    minimize.delete(ALL)
    minimize.create_oval(1,1, 15,15, outline="goldenrod", fill="yellow")

def minimize_me(e):
    root.update_idletasks()
    root.state("withdrawn")

minimize=Canvas(title, bg=gray, height=16, width=16, highlightthickness=0)
minimize.create_oval(1,1, 15,15, outline="goldenrod", fill="yellow")
minimize.pack(side=LEFT, pady=3, padx=2)
minimize.bind("<Enter>", onmin)
minimize.bind("<Leave>", offmin)
minimize.bind("<Button-1>", minimize_me)

window = 0
run=True
def maximize_me_for_command():
    run=True
    def loop():
        global window, run
        if run == True:
            if window < 2000:
                window += 132
                root.geometry(f"{window}x{window}")
            else:
                window = 0
                run=False
            root.after(50, loop)
    loop()
    root.geometry("+0+0")

def titleleft():
    root.geometry(f"400x1500+0+0")

def titleright():
    root.geometry(f"400x1500+{root.winfo_screenwidth()-400}+0")

maxmenu=Menu(root)
maxmenu.add_cascade(label="▬  Enter Full Screen", command=maximize_me_for_command)
maxmenu.add_cascade(label="⇤ Title Window to Left of Screen", command=titleleft)
maxmenu.add_cascade(label="⇥ Title Window to Right of Screen", command=titleright)

go=False

def show():
    global go
    if go==True:
        maxmenu.tk_popup(root.winfo_x()+55, root.winfo_y()+32)
        go=False

def onmax(e):
    global go
    maximize.create_rectangle(4,4, 12,12, width=0, fill="darkolivegreen")
    maximize.create_text(8,8, text="⁄", fill="green")
    go=True
    root.after(1000, show)

def offmax(e):
    global go
    go=False
    maximize.delete(ALL)
    maximize.create_oval(1,1, 15,15, outline="darkolivegreen", fill="green")

def maximize_me(e):
    run=True
    def loop():
        global window, run
        if run == True:
            if window < 2000:
                window += 132
                root.geometry(f"{window}x{window}")
            else:
                window = 0
                run=False
            root.after(50, loop)
    loop()
    root.geometry("+0+0")

maximize=Canvas(title, bg=gray, height=16, width=16, highlightthickness=0)
maximize.create_oval(1,1, 15,15, outline="darkolivegreen", fill="green")
maximize.pack(side=LEFT, pady=3, padx=2)
maximize.bind("<Enter>", onmax)
maximize.bind("<Leave>", offmax)
maximize.bind("<Button-1>", maximize_me)

text=Frame(title, bg=gray)
text.pack(pady=3)
textintext=Frame(text, bg=gray)
textintext.pack()
l=Label(textintext, text=Title, bg=gray, fg=black, font="Helvetica 8")
l.grid(row=1, column=2)
icn=Label(textintext, text="I", font="Helvetica 8")
icn.grid(row=1, column=1)

sg = Sizegrip(root, cursor="lr_angle")
sg.pack(anchor=SE, side=BOTTOM, pady=1, padx=9)
Related