feat: Implement lazy-loading for SearchFilterWidget to improve performance and resource management
This commit is contained in:
+42
-17
@@ -24,7 +24,6 @@ from pathology_management_window import PathologyManagementWindow
|
||||
from pathology_manager import PathologyManager
|
||||
from preferences import get_config_dir, get_pref, save_preferences, set_pref
|
||||
from search_filter import DataFilter
|
||||
from search_filter_ui import SearchFilterWidget
|
||||
from settings_window import SettingsWindow
|
||||
from theme_manager import ThemeManager
|
||||
from ui_manager import UIManager
|
||||
@@ -346,6 +345,8 @@ class MedTrackerApp:
|
||||
# --- Main Frame ---
|
||||
main_frame: ttk.Frame = ttk.Frame(self.root, padding="10", style="Card.TFrame")
|
||||
main_frame.grid(row=0, column=0, sticky="nsew")
|
||||
# Store for lazy child creation (search panel)
|
||||
self.main_frame = main_frame
|
||||
|
||||
# Configure root window grid
|
||||
self.root.grid_rowconfigure(0, weight=1)
|
||||
@@ -400,19 +401,14 @@ class MedTrackerApp:
|
||||
self.tree: ttk.Treeview = table_ui["tree"]
|
||||
self.tree.bind("<Double-1>", self.handle_double_click)
|
||||
|
||||
# --- Create Search/Filter Widget ---
|
||||
self.search_filter_widget = SearchFilterWidget(
|
||||
main_frame,
|
||||
self.data_filter,
|
||||
self._on_filter_update,
|
||||
self.medicine_manager,
|
||||
self.pathology_manager,
|
||||
logger,
|
||||
)
|
||||
# Restore prior visibility state from preferences
|
||||
# --- Search/Filter Widget (lazy-loaded) ---
|
||||
self.search_filter_widget = None # Created on demand
|
||||
# Restore prior visibility preference, but only create when needed
|
||||
self.search_filter_visible = bool(get_pref("search_panel_visible", False))
|
||||
if self.search_filter_visible:
|
||||
self.search_filter_widget.show()
|
||||
self._ensure_search_widget()
|
||||
# mypy: widget ensured above
|
||||
self.search_filter_widget.show() # type: ignore[union-attr]
|
||||
|
||||
# --- Create Status Bar ---
|
||||
self.status_bar = self.ui_manager.create_status_bar(main_frame)
|
||||
@@ -426,9 +422,8 @@ class MedTrackerApp:
|
||||
# Force one-time restoration in refresh and reflect in the UI if visible
|
||||
try:
|
||||
self.refresh_data_display(apply_filters=True)
|
||||
if self.search_filter_visible and hasattr(
|
||||
self.search_filter_widget, "sync_ui_from_filter"
|
||||
):
|
||||
if self.search_filter_visible and self.search_filter_widget is not None:
|
||||
# Keep UI in sync only if panel is actually instantiated
|
||||
self.search_filter_widget.sync_ui_from_filter()
|
||||
except Exception:
|
||||
self.refresh_data_display()
|
||||
@@ -1169,18 +1164,44 @@ Use Ctrl+S to save entries and Ctrl+Q to quit."""
|
||||
def _toggle_search_filter(self) -> None:
|
||||
"""Toggle the search and filter panel."""
|
||||
if self.search_filter_visible:
|
||||
self.search_filter_widget.hide()
|
||||
if self.search_filter_widget is not None:
|
||||
self.search_filter_widget.hide()
|
||||
self.search_filter_visible = False
|
||||
self.ui_manager.update_status("Search panel hidden", "info")
|
||||
set_pref("search_panel_visible", False)
|
||||
save_preferences()
|
||||
else:
|
||||
self.search_filter_widget.show()
|
||||
self._ensure_search_widget()
|
||||
# mypy: widget ensured above
|
||||
self.search_filter_widget.show() # type: ignore[union-attr]
|
||||
self.search_filter_visible = True
|
||||
self.ui_manager.update_status("Search panel shown", "info")
|
||||
set_pref("search_panel_visible", True)
|
||||
save_preferences()
|
||||
|
||||
def _ensure_search_widget(self) -> None:
|
||||
"""Create the search widget on demand to support lazy-loading."""
|
||||
if getattr(self, "search_filter_widget", None) is not None:
|
||||
return
|
||||
try:
|
||||
# Local import to defer module load cost until first use
|
||||
from search_filter_ui import SearchFilterWidget # type: ignore
|
||||
|
||||
self.search_filter_widget = SearchFilterWidget(
|
||||
self.main_frame,
|
||||
self.data_filter,
|
||||
self._on_filter_update,
|
||||
self.medicine_manager,
|
||||
self.pathology_manager,
|
||||
logger,
|
||||
)
|
||||
# If filters were restored earlier, reflect state in UI now
|
||||
with contextlib.suppress(Exception):
|
||||
self.search_filter_widget.sync_ui_from_filter()
|
||||
except Exception as exc:
|
||||
logger.error(f"Failed to initialize search panel: {exc}")
|
||||
self.ui_manager.update_status("Search panel unavailable", "error")
|
||||
|
||||
def _on_filter_update(self) -> None:
|
||||
"""Handle filter updates from the search widget."""
|
||||
# Debounce rapid filter changes to avoid repeated heavy refresh.
|
||||
@@ -1608,6 +1629,10 @@ Use Ctrl+S to save entries and Ctrl+Q to quit."""
|
||||
if current_scroll_top > 0:
|
||||
self.tree.yview_moveto(current_scroll_top)
|
||||
|
||||
# Ensure alternating stripes are normalized after any update
|
||||
with contextlib.suppress(Exception):
|
||||
self.ui_manager.normalize_tree_stripes(self.tree)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating tree efficiently: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user