Interface-module/boxes/CTkLoadingBox.py
2025-03-20 19:07:00 +03:00

158 lines
6.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import ctypes
from threading import Thread
from typing import Optional, Union, Tuple
from customtkinter import CTkToplevel, CTkProgressBar, CTkLabel, ThemeManager, CTkFont
from loguru import logger as _logger
logger = _logger.bind(module="CTkLoadingBox", prefix="misc")
class CTkLoadingBox(CTkToplevel):
def __init__(self,
title: str = "CTkDialog",
text: str = "CTkDialog",
font: Optional[Union[tuple, CTkFont]] = None,
hide_topbar: bool = False,
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
button_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
button_text_color: Optional[Union[str, Tuple[str, str]]] = None,
entry_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
entry_border_color: Optional[Union[str, Tuple[str, str]]] = None,
entry_text_color: Optional[Union[str, Tuple[str, str]]] = None,
parent=None):
super().__init__(fg_color=fg_color)
self._fg_color = ThemeManager.theme["CTkToplevel"]["fg_color"] if fg_color is None else self._check_color_type(fg_color)
self._text_color = ThemeManager.theme["CTkLabel"]["text_color"] if text_color is None else self._check_color_type(button_hover_color)
self._button_fg_color = ThemeManager.theme["CTkButton"]["fg_color"] if button_fg_color is None else self._check_color_type(button_fg_color)
self._button_hover_color = ThemeManager.theme["CTkButton"]["hover_color"] if button_hover_color is None else self._check_color_type(button_hover_color)
self._button_text_color = ThemeManager.theme["CTkButton"]["text_color"] if button_text_color is None else self._check_color_type(button_text_color)
self._entry_fg_color = ThemeManager.theme["CTkEntry"]["fg_color"] if entry_fg_color is None else self._check_color_type(entry_fg_color)
self._entry_border_color = ThemeManager.theme["CTkEntry"]["border_color"] if entry_border_color is None else self._check_color_type(entry_border_color)
self._entry_text_color = ThemeManager.theme["CTkEntry"]["text_color"] if entry_text_color is None else self._check_color_type(entry_text_color)
if hide_topbar:
self.overrideredirect(True)
# Округление окна
hwnd = ctypes.windll.user32.GetParent(self.winfo_id())
self.bind("<ButtonPress-1>", self.__start_move)
self.bind("<B1-Motion>", self.__on_move)
self._running: bool = False
self._progress = 0
self._text = [text, ""]
self._font = font
# self.geometry("300x100")
self.transient(parent)
self.title(title)
self.lift() # lift window on top
self.attributes("-topmost", True) # stay on top
self.protocol("WM_DELETE_WINDOW", self._on_closing)
self._create_widgets()
self.resizable(False, False)
# self.grab_set() # make other windows not clickable
self.withdraw()
self._req_events()
def __start_move(self, event):
self.x = event.x
self.y = event.y
def __on_move(self, event):
self.geometry(f"+{event.x_root - self.x}+{event.y_root - self.y}")
def _req_events(self):
event.register("loading.open", self.open)
event.register("loading.close", self.close)
event.register("loading.set_text", self.set_text)
event.register("loading.set_subtext", self.set_subtext)
event.register("loading.set_progress", self.set_progress)
def open(self, *_, **__):
self.grab_set()
self.deiconify()
def close(self, *_, **__):
self.grab_release()
self.withdraw()
self.set_text("closed")
self.set_subtext("closed")
self.set_progress(1)
def _create_widgets(self):
# self.message_label = CTkLabel(self, text=self._text)
self.message_label = CTkLabel(
self, width=300, wraplength=300, fg_color="transparent", text=self._text[0]
)
self.message_label.pack(pady=5)
# Прогресс-бар
self.progress_bar = CTkProgressBar(self, mode="determinate", width=250)
self.progress_bar.pack(pady=10)
self.progress_bar.set(0) # Устанавливаем начальное значение прогресса
# Текст с процентами
self.percent_label = CTkLabel(
self, width=300, wraplength=300, fg_color="transparent", text="0%"
)
self.percent_label.pack(pady=5)
def _on_closing(self):
self.grab_release()
# self.destroy()
def __run(self, f, *args, **kwargs):
self._running = True
try:
f(*args, **kwargs)
except Exception as e:
logger.exception(e)
finally:
self._running = False
self.grab_release()
self.destroy()
self.quit()
def process(self, func, *args, **kwargs):
Thread(target=self.__run, args=(func, self, *args), kwargs=kwargs, daemon=True).start()
self.mainloop()
def _set_subtext(self, subtext):
self._text[1] = subtext
self.message_label.configure(text=f"{self._text[0]}: {self._text[1]}")
def set_subtext(self, subtext, *_, **__):
self.after(0, self._set_subtext, subtext)
def _set_text(self, text):
self._text[0] = text
self.message_label.configure(text=f"{self._text[0]}")
def set_text(self, text, *_, **__):
self.after(0, self._set_text, text)
def _set_progress(self, value):
if 0.0 <= value <= 1.0:
self._progress = value
self.progress_bar.set(value) # Обновляем прогресс-бар
self.percent_label.configure(text=f"{int(value * 100)}%") # Обновляем текст процентов
def set_progress(self, value, *_, **__):
self.after(0, self._set_progress, value)
if __name__ == '__main__':
c = CTkLoadingBox("Title", "Message")
c.set_progress(0.475)
c.mainloop()