Исходный код EJIO.ctk_extender.window.controller
## /ctk_extender/window/controller.py
import sys
from threading import Lock
from typing import Any
from loguru import logger
from EJIO.utils import StaticClass
from .registry import WindowRegistry
from .base import Window
from .err import WindowNotFoundError, WindowNotActiveError
from .session import WindowSessionManager
__all__ = [
'WindowController',
]
[документация]
class WindowController(StaticClass):
"""
Статический контроллер рантайм-операций над окнами.
Управляет живыми экземплярами окон, их размерами, фокусом и состояниями.
"""
_lock: Lock = Lock()
_active_windows: dict[str, Window] = {}
[документация]
@classmethod
def open_window(cls, name: str, *args: Any, **kwargs: Any) -> Window:
"""
Создает, регистрирует и выводит на экран окно, используя WindowRegistry.
Если окно уже открыто, просто переводит на него фокус.
:param name: Имя окна, под которым оно зарегистрировано в WindowRegistry.
:param args: Аргументы для инициализации окна.
:param kwargs: Ключевые аргументы для инициализации окна.
:return: Созданный живой экземпляр Window.
"""
with cls._lock:
# Если окно с таким именем уже запущено, возвращаем его
if name in cls._active_windows:
logger.warning(f"Window '{name}' already opened. Shifting focus on it.")
cls._active_windows[name].focus()
return cls._active_windows[name]
# Если словарь активных окон пуст, значит это самое первое окно в приложении.
# Мы принудительно прописываем is_main=True, чтобы класс Window создал ctk.CTk()
if not cls._active_windows:
kwargs['is_main'] = True
try:
# Извлекаем класс из реестра окон
window_cls = WindowRegistry.get(name)
# Инстанцируем окно
window_instance = window_cls(*args, **kwargs)
cls._active_windows[name] = window_instance
except WindowNotFoundError:
logger.critical(f"Window with name {name} is missing.")
sys.exit(1)
logger.info(f"Window '{name}' successfully created and displayed on the screen.")
return window_instance
[документация]
@classmethod
def close_window(cls, name: str) -> None:
"""
Принудительно закрывает окно по имени и удаляет его из рантайм-реестра,
сохраняя его финальные координаты сессии.
"""
with cls._lock:
if not name in cls._active_windows:
logger.warning(f"Window '{name}' not opened.")
return
window = cls._active_windows.pop(name)
try:
instance = window.ctk_instance
instance.update_idletasks()
WindowSessionManager.store_geometry(
window_name=name,
width=instance.winfo_width(),
height=instance.winfo_height(),
x=instance.winfo_x(),
y=instance.winfo_y()
)
except Exception as e:
logger.error(f"Failed to intercept closing window geometry '{name}': {e}")
window.destroy()
WindowSessionManager.save_sessions()
[документация]
@classmethod
def get_active(cls, name: str) -> Window:
"""Возвращает живой экземпляр запущенного окна."""
with cls._lock:
if name not in cls._active_windows:
raise WindowNotActiveError(f"Window '{name}' is not running in runtime.")
return cls._active_windows[name]
[документация]
@classmethod
def clear(cls) -> None:
"""Закрывает абсолютно все активные окна приложения и очищает реестр."""
with cls._lock:
for name, window in list(cls._active_windows.items()):
try:
try:
instance = window.ctk_instance
instance.update_idletasks()
WindowSessionManager.store_geometry(
window_name=name,
width=instance.winfo_width(),
height=instance.winfo_height(),
x=instance.winfo_x(),
y=instance.winfo_y()
)
except Exception as e:
logger.error(f"Failed to intercept closing window geometry '{name}': {e}")
window.destroy()
except Exception as e:
logger.error(f"Error during closing of window '{name}': {e}")
WindowSessionManager.save_sessions()
cls._active_windows.clear()
logger.info("All active windows of application successfully unloaded.")