import tkinter as tk from datetime import datetime from enum import Enum from customtkinter import CTkTextbox, CTk from loguru import logger from gui.utils import fonts class LogLevels(Enum): DEBUG = 0 ERROR = 1 WARNING = 2 INFO = 3 SUCCESS = 4 class CTkColoredConsoleFrame(CTkTextbox): def __init__(self, master: CTk, corner_radius=0, font=None, _callback=None, **kwargs): if font is None: font = fonts.log_font() super().__init__(master, corner_radius=corner_radius, font=font, **kwargs) self.configure(state='disabled') self.__callback = _callback self._create_tags() self._create_menu() def _copy(self, _=None): self.clipboard_clear() selected_text = self.get(tk.SEL_FIRST, tk.SEL_LAST).replace("\n\n", "\n") self.clipboard_append(selected_text) def _open_menu(self, ev): self.menu.post(ev.x_root, ev.y_root) def _create_menu(self): self.menu = tk.Menu(self, tearoff=0) self.menu.add_command(label="Copy", command=self._copy) self.master.bind("", self._copy) self.master.bind("", self._open_menu) def _create_tags(self): self.tag_config(LogLevels.DEBUG, foreground='#0000FF') self.tag_config(LogLevels.ERROR, foreground='#FF0000') self.tag_config(LogLevels.WARNING, foreground='#FFA500') self.tag_config(LogLevels.INFO, foreground='white') self.tag_config(LogLevels.SUCCESS, foreground='#008000') def clear(self): self.configure(state='normal') self.delete(1.0, 'end') self.configure(state='disabled') def log(self, level, message, _date=None): logger.debug(f"[{self.master}] [{level.name}] {message}") if not _date: _date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") if self.__callback: self.__callback(level, message, _date) self.update_idletasks() self.configure(state='normal') self.insert('end', f"{_date} | {level.name} | {message}" + '\n', (level, )) self.see('end') self.configure(state='disabled') self.update_idletasks() def debug(self, message): self.after(50, self.log, LogLevels.DEBUG, message) def error(self, message): self.after(50, self.log, LogLevels.ERROR, message) def warning(self, message): self.after(50, self.log, LogLevels.WARNING, message) def info(self, message): self.after(50, self.log, LogLevels.INFO, message) def success(self, message): self.after(50, self.log, LogLevels.SUCCESS, message) if __name__ == '__main__': _root = CTk() _root.title("CTkColoredConsoleFrame") _root.geometry("400x300") _root.configure(bg='white') con = CTkColoredConsoleFrame(_root) con.pack(fill='both', expand=True) con.debug("Debug message") con.error("Error message") con.warning("Warning message") con.info("Info message") con.success("Success message") _root.mainloop()