from threading import Thread from typing import Optional, Union, Tuple from customtkinter import CTkToplevel, CTkProgressBar, CTkLabel, ThemeManager, CTkFont from loguru import logger class CTkLoadingBox(CTkToplevel): def __init__(self, title: str = "CTkDialog", text: str = "CTkDialog", font: Optional[Union[tuple, CTkFont]] = None, 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) 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 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()