Задать вопрос
vo0ov
@vo0ov
Кодер на python

Как сделать кастомный заголовок окна в Tkinter?

Как сделать свой заголовок окна в Tkinter? Я пробовал так:
from tkinter import Tk, Label, font, Frame, Button

root = Tk()
root['bg'] = '#232428'
root.geometry('350x500')
root.resizable(False, False)
root.overrideredirect(True)
custom_font = font.Font(family='Impact', size=16)

header_frame = Frame(root, bg='#3F3F3F', relief='raised', bd=0)
header_frame.pack(fill='x')
close_button = Button(header_frame, text='x', bg='#3F3F3F', fg='white', activebackground='#C70039',
                      activeforeground='white', bd=0, highlightthickness=0, command=root.destroy, font=custom_font)
close_button.pack(side='right', padx=5)
header_label = Label(header_frame, text='Test',
                     font=custom_font, fg='#FFFFFF', bg='#3F3F3F')
header_label.pack(pady=5)

content_frame = Frame(root, bg='#232428')
content_frame.pack(fill='both', expand=True)


def on_drag_start(event):
    root._offset_x = event.x_root - root.winfo_x()
    root._offset_y = event.y_root - root.winfo_y()


def on_drag(event):
    x = event.x_root - root._offset_x
    y = event.y_root - root._offset_y
    root.geometry(f"+{x}+{y}")


header_frame.bind('<Button-1>', on_drag_start)
header_frame.bind('<B1-Motion>', on_drag)
header_label.bind('<Button-1>', on_drag_start)
header_label.bind('<B1-Motion>', on_drag)

root.mainloop()


Но если выйти из фокуса окна (Например нажать куда то вне окна) то оно пропадёт и будет в фоне, а на панели задач его нет. И вообще это не окно. Я хочу что бы это было окно и можно было делать так:
66d9df10bd535399413493.png
  • Вопрос задан
  • 103 просмотра
Подписаться 2 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 1
@mr_secret
Основываясь на коде, представленном здесь и здесь, мне удалось составить работающий пример.
Для данного примера реализованы:
  1. Отключение дефолтного заголовка окна
  2. Отображение иконки программы в панели задач
  3. Возможность открытия окна через панель задач
  4. Возможность двигать окно
  5. Возможность изменять размер окна

Недостатки данного примера:
  1. длящееся примерно долю секунды отображение вспомогательного окна (хотя если формально - главного) при разворачивании окна через панель задач
  2. Отсутствие изображения содержимого окна при наведении мыши на иконку на панели задач
  3. Окно, если не свернуто, всегда отображается строго поверх других окон, что отличает его от обычных окон


678f95bee1ec1622947023.png

код:
from tkinter import *
from tkinter import font


class NewRoot(Tk):
    def __init__(self):
        Tk.__init__(self)


class MyMain(Toplevel):
    def __init__(self, master):
        Toplevel.__init__(self, master)
        self.overrideredirect(True)
        self.attributes('-topmost', 1)
        self.bind('<ButtonRelease-3>', self.on_close)  #right-click to get out
        # region geometry method
        self.set_geometry_on_center()
        # endregion


        # region Чтобы можно было двигать окно
        self.main_frm = Frame(master=self, bg='#232428')
        self.main_frm.pack(fill=BOTH, expand=True)
        self.main_frm.bind("<B1-Motion>", self.move)
        # endregion
        custom_font = font.Font(family='Impact', size=16)
        # region Кнопка закрытия окна
        Button(self.main_frm, text='x', bg='#3F3F3F', fg='white', activebackground='#C70039',
               activeforeground='white', bd=0, highlightthickness=0, command=root.destroy, font=custom_font)\
            .pack(side='right', anchor=NE, padx=5)
        # endregion
        # region Заголовок
        header_label = Label(master=self.main_frm, text='Заголовок', font=custom_font, fg='#FFFFFF', bg='#3F3F3F')
        header_label.pack(pady=5)
        # endregion
        # region Чтобы можно было изменять размер
        self.resize_lbl = Label(master=self.main_frm, bg='#3F3F3F', fg='white', activebackground='#C70039',
                                activeforeground='white', bd=0, highlightthickness=0,  text='resize', font=custom_font)
        self.resize_lbl.pack(anchor=E)
        self.resize_lbl.bind("<B1-Motion>", self.resize)
        # endregion
        # region Чтобы можно было свернуть
        self.minimize_lbl = Button(master=self.main_frm, bg='#3F3F3F', fg='white', activebackground='#C70039',
                                 activeforeground='white', bd=0, highlightthickness=0,  text='Свернуть', font=custom_font,
                                 command=self.minimize)
        self.minimize_lbl.pack(anchor=E)
        self.minimize_lbl.bind("<B1-Motion>", self.resize)
        # endregion

    def on_close(self, event) -> None:
        self.master.destroy()

    def set_geometry_on_center(self) -> None:  # Placing the window in the center of the screen
        rx = self.winfo_screenwidth()
        ry = self.winfo_screenheight()
        x = int((rx / 2) - (500 / 2))
        y = int((ry / 2) - (500 / 2))
        self.geometry(f"500x500+{x}+{y}")

    def resize(self, event) -> None:
        x = self.winfo_pointerx() - self.winfo_rootx()
        y = self.winfo_pointery() - self.winfo_rooty()
        if x > 0:
            fx = self.winfo_rootx()
            fy = self.winfo_rooty() + y
            ht = self.winfo_height() - y
            if ht > 0:
                self.geometry(f"{x}x{ht}+{fx}+{fy}")

    def move(self, event) -> None:
        fx = root.winfo_pointerx() - 250
        fy = root.winfo_pointery() - 10
        self.geometry(f"{self.winfo_width()}x{self.winfo_height()}+{fx}+{fy}")

    def minimize(self):  # свернуть
        self.state('withdrawn')


def func(event):
    app.state('normal')
    root.iconify()


if __name__ == '__main__':

    root = NewRoot()
    root.lower()
    root.iconify()

    app = MyMain(root)
    root.bind("<Map>", func)

    app.mainloop()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы