Adding splitter and saving layout state when closing the app
This commit is contained in:
@@ -13,7 +13,7 @@ from PySide6.QtWidgets import (
|
|||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QLabel,
|
QLabel,
|
||||||
)
|
)
|
||||||
from PySide6.QtCore import Qt, QTimer
|
from PySide6.QtCore import Qt, QTimer, QSettings
|
||||||
from PySide6.QtGui import QAction, QKeySequence
|
from PySide6.QtGui import QAction, QKeySequence
|
||||||
|
|
||||||
from src.database.db_manager import DatabaseManager
|
from src.database.db_manager import DatabaseManager
|
||||||
@@ -52,8 +52,8 @@ class MainWindow(QMainWindow):
|
|||||||
self._create_tab_widget()
|
self._create_tab_widget()
|
||||||
self._create_status_bar()
|
self._create_status_bar()
|
||||||
|
|
||||||
# Center window on screen
|
# Restore window geometry or center window on screen
|
||||||
self._center_window()
|
self._restore_window_state()
|
||||||
|
|
||||||
logger.info("Main window initialized")
|
logger.info("Main window initialized")
|
||||||
|
|
||||||
@@ -156,6 +156,24 @@ class MainWindow(QMainWindow):
|
|||||||
(screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2
|
(screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _restore_window_state(self):
|
||||||
|
"""Restore window geometry from settings or center window."""
|
||||||
|
settings = QSettings("microscopy_app", "object_detection")
|
||||||
|
geometry = settings.value("main_window/geometry")
|
||||||
|
|
||||||
|
if geometry:
|
||||||
|
self.restoreGeometry(geometry)
|
||||||
|
logger.debug("Restored window geometry from settings")
|
||||||
|
else:
|
||||||
|
self._center_window()
|
||||||
|
logger.debug("Centered window on screen")
|
||||||
|
|
||||||
|
def _save_window_state(self):
|
||||||
|
"""Save window geometry to settings."""
|
||||||
|
settings = QSettings("microscopy_app", "object_detection")
|
||||||
|
settings.setValue("main_window/geometry", self.saveGeometry())
|
||||||
|
logger.debug("Saved window geometry to settings")
|
||||||
|
|
||||||
def _show_settings(self):
|
def _show_settings(self):
|
||||||
"""Show settings dialog."""
|
"""Show settings dialog."""
|
||||||
logger.info("Opening settings dialog")
|
logger.info("Opening settings dialog")
|
||||||
@@ -276,6 +294,13 @@ class MainWindow(QMainWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if reply == QMessageBox.Yes:
|
if reply == QMessageBox.Yes:
|
||||||
|
# Save window state before closing
|
||||||
|
self._save_window_state()
|
||||||
|
|
||||||
|
# Save annotation tab state if it exists
|
||||||
|
if hasattr(self, "annotation_tab"):
|
||||||
|
self.annotation_tab.save_state()
|
||||||
|
|
||||||
logger.info("Application closing")
|
logger.info("Application closing")
|
||||||
event.accept()
|
event.accept()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from PySide6.QtWidgets import (
|
|||||||
QPushButton,
|
QPushButton,
|
||||||
QFileDialog,
|
QFileDialog,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
|
QSplitter,
|
||||||
)
|
)
|
||||||
from PySide6.QtCore import Qt, QSettings
|
from PySide6.QtCore import Qt, QSettings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -43,25 +44,13 @@ class AnnotationTab(QWidget):
|
|||||||
"""Setup user interface."""
|
"""Setup user interface."""
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
# Image loading section
|
# Main horizontal splitter to divide left (image) and right (controls)
|
||||||
load_group = QGroupBox("Image Loading")
|
self.main_splitter = QSplitter(Qt.Horizontal)
|
||||||
load_layout = QVBoxLayout()
|
self.main_splitter.setHandleWidth(10)
|
||||||
|
|
||||||
# Load image button
|
# { Left splitter for image display and zoom info
|
||||||
button_layout = QHBoxLayout()
|
self.left_splitter = QSplitter(Qt.Vertical)
|
||||||
self.load_image_btn = QPushButton("Load Image")
|
self.left_splitter.setHandleWidth(10)
|
||||||
self.load_image_btn.clicked.connect(self._load_image)
|
|
||||||
button_layout.addWidget(self.load_image_btn)
|
|
||||||
button_layout.addStretch()
|
|
||||||
|
|
||||||
load_layout.addLayout(button_layout)
|
|
||||||
|
|
||||||
# Image info label
|
|
||||||
self.image_info_label = QLabel("No image loaded")
|
|
||||||
load_layout.addWidget(self.image_info_label)
|
|
||||||
|
|
||||||
load_group.setLayout(load_layout)
|
|
||||||
layout.addWidget(load_group)
|
|
||||||
|
|
||||||
# Image display section
|
# Image display section
|
||||||
display_group = QGroupBox("Image Display")
|
display_group = QGroupBox("Image Display")
|
||||||
@@ -73,7 +62,21 @@ class AnnotationTab(QWidget):
|
|||||||
display_layout.addWidget(self.image_display_widget)
|
display_layout.addWidget(self.image_display_widget)
|
||||||
|
|
||||||
display_group.setLayout(display_layout)
|
display_group.setLayout(display_layout)
|
||||||
layout.addWidget(display_group)
|
self.left_splitter.addWidget(display_group)
|
||||||
|
|
||||||
|
# Zoom controls info
|
||||||
|
zoom_info = QLabel("Zoom: Mouse wheel or +/- keys to zoom in/out")
|
||||||
|
zoom_info.setStyleSheet("QLabel { color: #888; font-style: italic; }")
|
||||||
|
self.left_splitter.addWidget(zoom_info)
|
||||||
|
# }
|
||||||
|
|
||||||
|
# { Right splitter for annotation tools and controls
|
||||||
|
self.right_splitter = QSplitter(Qt.Vertical)
|
||||||
|
self.right_splitter.setHandleWidth(10)
|
||||||
|
|
||||||
|
# Image loading section
|
||||||
|
load_group = QGroupBox("Image Loading")
|
||||||
|
load_layout = QVBoxLayout()
|
||||||
|
|
||||||
# Future features info
|
# Future features info
|
||||||
info_group = QGroupBox("Annotation Tool (Future Feature)")
|
info_group = QGroupBox("Annotation Tool (Future Feature)")
|
||||||
@@ -86,18 +89,41 @@ class AnnotationTab(QWidget):
|
|||||||
"- Export annotations to YOLO format\n"
|
"- Export annotations to YOLO format\n"
|
||||||
"- Annotation verification"
|
"- Annotation verification"
|
||||||
)
|
)
|
||||||
|
info_label.setWordWrap(True)
|
||||||
info_layout.addWidget(info_label)
|
info_layout.addWidget(info_label)
|
||||||
info_group.setLayout(info_layout)
|
info_group.setLayout(info_layout)
|
||||||
|
|
||||||
layout.addWidget(info_group)
|
self.right_splitter.addWidget(info_group)
|
||||||
|
|
||||||
# Zoom controls info
|
# Load image button
|
||||||
zoom_info = QLabel("Zoom: Mouse wheel or +/- keys to zoom in/out")
|
button_layout = QHBoxLayout()
|
||||||
zoom_info.setStyleSheet("QLabel { color: #888; font-style: italic; }")
|
self.load_image_btn = QPushButton("Load Image")
|
||||||
layout.addWidget(zoom_info)
|
self.load_image_btn.clicked.connect(self._load_image)
|
||||||
|
button_layout.addWidget(self.load_image_btn)
|
||||||
|
button_layout.addStretch()
|
||||||
|
load_layout.addLayout(button_layout)
|
||||||
|
|
||||||
|
# Image info label
|
||||||
|
self.image_info_label = QLabel("No image loaded")
|
||||||
|
load_layout.addWidget(self.image_info_label)
|
||||||
|
|
||||||
|
load_group.setLayout(load_layout)
|
||||||
|
self.right_splitter.addWidget(load_group)
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Add both splitters to the main horizontal splitter
|
||||||
|
self.main_splitter.addWidget(self.left_splitter)
|
||||||
|
self.main_splitter.addWidget(self.right_splitter)
|
||||||
|
|
||||||
|
# Set initial sizes: 75% for left (image), 25% for right (controls)
|
||||||
|
self.main_splitter.setSizes([750, 250])
|
||||||
|
|
||||||
|
layout.addWidget(self.main_splitter)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
# Restore splitter positions from settings
|
||||||
|
self._restore_state()
|
||||||
|
|
||||||
def _load_image(self):
|
def _load_image(self):
|
||||||
"""Load and display an image file."""
|
"""Load and display an image file."""
|
||||||
# Get last opened directory from QSettings
|
# Get last opened directory from QSettings
|
||||||
@@ -171,6 +197,49 @@ class AnnotationTab(QWidget):
|
|||||||
"""Handle zoom level changes from the image display widget."""
|
"""Handle zoom level changes from the image display widget."""
|
||||||
self._update_image_info()
|
self._update_image_info()
|
||||||
|
|
||||||
|
def _restore_state(self):
|
||||||
|
"""Restore splitter positions from settings."""
|
||||||
|
settings = QSettings("microscopy_app", "object_detection")
|
||||||
|
|
||||||
|
# Restore main splitter state
|
||||||
|
main_state = settings.value("annotation_tab/main_splitter_state")
|
||||||
|
if main_state:
|
||||||
|
self.main_splitter.restoreState(main_state)
|
||||||
|
logger.debug("Restored main splitter state")
|
||||||
|
|
||||||
|
# Restore left splitter state
|
||||||
|
left_state = settings.value("annotation_tab/left_splitter_state")
|
||||||
|
if left_state:
|
||||||
|
self.left_splitter.restoreState(left_state)
|
||||||
|
logger.debug("Restored left splitter state")
|
||||||
|
|
||||||
|
# Restore right splitter state
|
||||||
|
right_state = settings.value("annotation_tab/right_splitter_state")
|
||||||
|
if right_state:
|
||||||
|
self.right_splitter.restoreState(right_state)
|
||||||
|
logger.debug("Restored right splitter state")
|
||||||
|
|
||||||
|
def save_state(self):
|
||||||
|
"""Save splitter positions to settings."""
|
||||||
|
settings = QSettings("microscopy_app", "object_detection")
|
||||||
|
|
||||||
|
# Save main splitter state
|
||||||
|
settings.setValue(
|
||||||
|
"annotation_tab/main_splitter_state", self.main_splitter.saveState()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save left splitter state
|
||||||
|
settings.setValue(
|
||||||
|
"annotation_tab/left_splitter_state", self.left_splitter.saveState()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save right splitter state
|
||||||
|
settings.setValue(
|
||||||
|
"annotation_tab/right_splitter_state", self.right_splitter.saveState()
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug("Saved annotation tab splitter states")
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
"""Refresh the tab."""
|
"""Refresh the tab."""
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user