fix(autocal): 将标定记录总览接入主窗口

合并旧占位页为标定记录页,并统一采集页的数据查看入口。通过45项相关测试、离屏布局检查及代码和文档门禁。
This commit is contained in:
ykcheungab
2026-10-11 19:35:25 +08:00
parent b200f3d55c
commit 432f45325f
8 changed files with 112 additions and 33 deletions
@@ -36,6 +36,7 @@ class CalibrationPanel(QWidget):
"""One operator page. No motion commands are issued by this widget."""
loadBundleRequested = Signal()
reviewRequested = Signal(str)
def __init__(self, source_panel: QWidget, parent: QWidget | None = None) -> None:
super().__init__(parent)
@@ -351,19 +352,13 @@ class CalibrationPanel(QWidget):
self._sync()
def _review(self) -> None:
from .record_overview_dialog import RecordOverviewDialog
session = self.trial.session
directory = QFileDialog.getExistingDirectory(
self, t("review.open"),
str(session.directory) if session is not None else self.output_path.text(),
)
if directory:
try:
dialog = RecordOverviewDialog(Path(directory), self)
dialog.exec()
except (OSError, ValueError, KeyError, TypeError) as exc:
self.result_label.setText(t("calibration.error").format(detail=exc))
self.reviewRequested.emit(directory)
def shutdown(self) -> None:
self._timer.stop()
@@ -8,7 +8,7 @@ from PySide6.QtCore import Qt
from PySide6.QtGui import QColor, QPainter
from PySide6.QtWidgets import (
QComboBox, QDialog, QFileDialog, QHBoxLayout, QHeaderView, QLabel,
QPushButton, QTableWidget, QTableWidgetItem, QVBoxLayout,
QPushButton, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget,
)
from ..record_overview import load_overview, overview_rows, read_plan, save_overview
@@ -16,7 +16,63 @@ from ..session_review import review_session
from .session_review_dialog import SessionReviewDialog
class RecordOverviewPage(QWidget):
"""Keep the existing record viewer inside the main task workspace."""
def __init__(self, parent=None):
super().__init__(parent)
self.overview = None
self.directory = Path.cwd()
self.content_layout = QVBoxLayout(self)
self.open_button = QPushButton(self)
self.open_button.setObjectName("openCalibrationRecords")
self.open_button.clicked.connect(self._open)
self.path_label = QLabel(self)
self.path_label.setWordWrap(True)
self.message = QLabel(self)
self.message.setWordWrap(True)
self.content_layout.addWidget(self.open_button)
self.content_layout.addWidget(self.path_label)
self.content_layout.addWidget(self.message)
self.content_layout.addStretch(1)
self.retranslate()
def retranslate(self):
self.open_button.setText(t("overview.open_session"))
if self.overview is None:
self.path_label.setText(t("overview.empty"))
def _open(self):
path = QFileDialog.getExistingDirectory(self, t("overview.open_session"), str(self.directory))
if path:
self.load_session(Path(path))
def load_session(self, directory: Path):
try:
overview = RecordOverviewDialog(directory, self)
except (OSError, ValueError, KeyError, TypeError) as exc:
self.message.setText(t("calibration.error").format(detail=exc))
return
overview.setWindowFlags(Qt.WindowType.Widget)
if self.overview is not None:
self.content_layout.removeWidget(self.overview)
self.overview.hide()
self.overview.deleteLater()
else:
self.content_layout.takeAt(self.content_layout.count() - 1)
self.overview = overview
self.directory = directory
self.path_label.setText(str(directory))
self.message.clear()
self.content_layout.addWidget(overview, 1)
overview.show()
class RecordOverviewDialog(QDialog):
def reject(self):
if self.isWindow():
super().reject()
def __init__(self, directory: Path, parent=None):
super().__init__(parent)
self.directory = directory
@@ -305,6 +305,7 @@ class AutoCalMainWindow(QMainWindow):
body,
sensor_panel=self.calibration_panel,
)
self.calibration_panel.reviewRequested.connect(self._on_review_records)
self.main_splitter = QSplitter(Qt.Orientation.Horizontal, body)
self.main_splitter.addWidget(self.left_rail)
@@ -325,6 +326,10 @@ class AutoCalMainWindow(QMainWindow):
self._wire_signals()
def _on_review_records(self, directory: str) -> None:
self.workspace.page("records").load_session(Path(directory))
self.workspace.set_current_key("records")
def _wire_signals(self) -> None:
self.connection_panel.connectRequested.connect(self._on_connect)
self.connection_panel.disconnectRequested.connect(self._on_disconnect)
@@ -4,10 +4,7 @@ One tab per task the operator does on the platform, with the motion status strip
living *outside* this widget so a tab change cannot hide the state that decides
whether it is safe to act.
Pages that are not built yet are present as labelled placeholders rather than
missing: the layout is being reviewed for operator use, and a tab that appears
only later would change the layout under review. Each placeholder names what
will fill it, so nobody mistakes an empty page for a broken one.
Calibration records share one page for coverage, sensitivity and window review.
"""
from __future__ import annotations
@@ -23,25 +20,23 @@ from PySide6.QtWidgets import (
from .axis_panel import AxisPanel
from .sequence_panel import SequencePanel
from .record_overview_dialog import RecordOverviewPage
#: Tab identity -> locale key for its label. Order is the display order, and it
#: follows the work: commission the axes, describe the sequence, watch the
#: sensor, look at the surface, then record calibration points.
#: sensor, capture data, then review calibration records.
TABS: tuple[tuple[str, str], ...] = (
("axes", "workspace.tab_axes"),
("sequence", "workspace.tab_sequence"),
("finger", "workspace.tab_finger"),
("sensor", "workspace.tab_sensor"),
("surface", "workspace.tab_surface"),
("points", "workspace.tab_points"),
("records", "workspace.tab_records"),
)
#: Tabs whose content does not exist yet, with the locale key that explains what
#: will appear there and when.
_PLACEHOLDERS: dict[str, str] = {
"sensor": "workspace.reserved_sensor",
"surface": "workspace.reserved_surface",
"points": "workspace.reserved_points",
}
@@ -93,6 +88,7 @@ class WorkspaceTabs(QTabWidget):
self._pages["finger"] = finger_panel
if sensor_panel is not None:
self._pages["sensor"] = sensor_panel
self._pages["records"] = RecordOverviewPage(self)
for key, locale_key in _PLACEHOLDERS.items():
if key in self._pages:
continue
@@ -134,6 +130,7 @@ class WorkspaceTabs(QTabWidget):
page = self._pages[key]
if isinstance(page, PlaceholderPage):
page.retranslate()
self._pages["records"].retranslate()
def _on_current_changed(self, index: int) -> None:
keys = self.page_keys()