feat: 完善一级关系编辑 UI 与视图体验
This commit is contained in:
+187
-19
@@ -8,6 +8,7 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
import vtk
|
||||
import vtkmodules.vtkInteractionWidgets # noqa: F401
|
||||
import vtkmodules.vtkInteractionStyle # noqa: F401
|
||||
import vtkmodules.vtkRenderingFreeType # noqa: F401
|
||||
import vtkmodules.vtkRenderingOpenGL2 # noqa: F401
|
||||
@@ -57,6 +58,7 @@ from .window_state import WindowStateMixin
|
||||
|
||||
|
||||
_CRASH_LOG_HANDLE = None
|
||||
_VTK_OUTPUT_WINDOW = None
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
APP_USER_MODEL_ID = "GeometryParametric.StepEditor"
|
||||
ISOLATED_EDIT_WORKER_ARG = "--isolated-edit-worker"
|
||||
@@ -119,6 +121,18 @@ def _set_windows_taskbar_identity() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def _suppress_vtk_output_window() -> None:
|
||||
"""Keep VTK warnings from opening transient native output windows."""
|
||||
global _VTK_OUTPUT_WINDOW
|
||||
try:
|
||||
vtk.vtkObject.GlobalWarningDisplayOff()
|
||||
output_window = vtk.vtkStringOutputWindow()
|
||||
vtk.vtkOutputWindow.SetInstance(output_window)
|
||||
_VTK_OUTPUT_WINDOW = output_window
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _isolated_edit_worker_request(argv: list[str]) -> Path | None:
|
||||
if ISOLATED_EDIT_WORKER_ARG not in argv:
|
||||
return None
|
||||
@@ -132,6 +146,7 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
ui_task_requested = Signal(object)
|
||||
|
||||
def __init__(self, step_path: str | Path, *, background_load: bool = False):
|
||||
_suppress_vtk_output_window()
|
||||
super().__init__()
|
||||
self.ui_task_requested.connect(self._run_ui_task, Qt.ConnectionType.QueuedConnection)
|
||||
self.setWindowTitle("几何参数化")
|
||||
@@ -149,6 +164,16 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
|
||||
self.model_actor = None
|
||||
self.edge_actor = None
|
||||
self.scene_axes_renderer = None
|
||||
self.orientation_marker_widget = None
|
||||
self.orientation_marker_prop = None
|
||||
self.step_coordinate_axes_actor = None
|
||||
self.hide_edges_during_camera_interaction = False
|
||||
self.edge_visibility_before_camera_interaction: int | None = None
|
||||
self.prefer_fxaa_antialiasing = True
|
||||
self.fallback_multi_samples = 2
|
||||
self.interactive_multi_samples = 0
|
||||
self.still_multi_samples = 0
|
||||
self.highlight_actor = None
|
||||
self.edge_highlight_actor = None
|
||||
self.highlight_signature: tuple[object, ...] | None = None
|
||||
@@ -160,6 +185,7 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
self.pending_hover_position: tuple[int, int] | None = None
|
||||
self.last_hover_pick_position: tuple[int, int] | None = None
|
||||
self.camera_interaction_active = False
|
||||
self.camera_interaction_visual_changed = False
|
||||
self.last_camera_interaction_ended_at: datetime | None = None
|
||||
self.hover_after_camera_cooldown_ms = 420
|
||||
self.pointer_button_down = False
|
||||
@@ -233,9 +259,9 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
self.auto_load_on_show = bool(background_load)
|
||||
self.vtk_interactor_started = False
|
||||
self.first_show_handled = False
|
||||
self.preview_load_deflection = 1.0
|
||||
self.initial_load_deflection = 0.035
|
||||
self.edit_result_deflection = 0.035
|
||||
self.preview_load_deflection = 0.35
|
||||
self.initial_load_deflection = 0.35
|
||||
self.edit_result_deflection = 0.35
|
||||
self.last_id_kind = "Feature"
|
||||
self.feature_detection_level = "current-only"
|
||||
self.property_editor_updating = False
|
||||
@@ -244,7 +270,10 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
self._selected_action_info_cache_value: dict[str, object] | None = None
|
||||
self.property_editor_specs: list[dict[str, object]] = []
|
||||
self.property_table_expanded = False
|
||||
self.property_table_collapsed_rows = 6
|
||||
self.property_table_collapsed_rows = 8
|
||||
self.property_editor_selected_row: int | None = None
|
||||
self.property_command_active_key = ""
|
||||
self.property_command_buttons: dict[str, QPushButton] = {}
|
||||
|
||||
self._build_ui()
|
||||
self._build_vtk()
|
||||
@@ -487,8 +516,8 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
border-radius: 5px;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
min-height: 18px;
|
||||
padding: 1px 3px;
|
||||
min-height: 26px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
QPushButton#propertyRowEditButton:hover {
|
||||
background: #f97316;
|
||||
@@ -646,6 +675,109 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
padding-left: 1px;
|
||||
padding-right: 1px;
|
||||
}
|
||||
QLabel#propertyCommandSummary {
|
||||
color: #334155;
|
||||
font-size: 11px;
|
||||
padding: 0 2px 1px 2px;
|
||||
}
|
||||
QLabel#propertyCommandHelp {
|
||||
background: #fff7ed;
|
||||
border: 1px solid #fed7aa;
|
||||
border-radius: 6px;
|
||||
color: #7c2d12;
|
||||
font-size: 11px;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
QFrame#propertyCommandBar {
|
||||
background: #eef2f7;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 6px;
|
||||
}
|
||||
QPushButton#propertyCommandButton {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
color: #334155;
|
||||
font-weight: 700;
|
||||
min-height: 34px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
QPushButton#propertyCommandButton:hover {
|
||||
background: #e2e8f0;
|
||||
}
|
||||
QPushButton#propertyCommandButton[active="true"] {
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
border: 1px solid #f59e0b;
|
||||
}
|
||||
QScrollArea#propertyCardScroll {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
QWidget#propertyCardContainer {
|
||||
background: transparent;
|
||||
}
|
||||
QFrame#propertyCard {
|
||||
background: #ffffff;
|
||||
border: 1px solid #d8e0eb;
|
||||
border-radius: 6px;
|
||||
}
|
||||
QFrame#propertyCard[compact="true"] {
|
||||
background: #ffffff;
|
||||
}
|
||||
QFrame#propertyCard[editable="true"] {
|
||||
background: #fffaf2;
|
||||
border-color: #f4c58a;
|
||||
}
|
||||
QFrame#propertyCard[selected="true"] {
|
||||
background: #fffaf2;
|
||||
border-color: #f59e0b;
|
||||
}
|
||||
QFrame#propertyCard[changed="true"] {
|
||||
background: #f0fdf4;
|
||||
border-color: #16a34a;
|
||||
}
|
||||
QFrame#propertyCard[invalid="true"] {
|
||||
background: #fff1f2;
|
||||
border-color: #ef4444;
|
||||
}
|
||||
QFrame#propertyCard[pinTop="true"] {
|
||||
background: #eef6ff;
|
||||
border-color: #b7d3f5;
|
||||
}
|
||||
QLabel#propertyCardTitle {
|
||||
color: #172033;
|
||||
font-weight: 700;
|
||||
}
|
||||
QLabel#propertyCardMetaLabel {
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
QLabel#propertyCardValue {
|
||||
color: #172033;
|
||||
}
|
||||
QLabel#propertyCardCompactValue {
|
||||
color: #172033;
|
||||
font-weight: 600;
|
||||
}
|
||||
QLabel#propertyCardHint {
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
}
|
||||
QLabel#propertyCardCompactMeta {
|
||||
color: #475569;
|
||||
font-size: 11px;
|
||||
}
|
||||
QLineEdit#propertyCardTargetEditor {
|
||||
background: #ffffff;
|
||||
border: 1px solid #c8d2df;
|
||||
border-radius: 4px;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
QLineEdit#propertyCardTargetEditor:focus {
|
||||
border-color: #2563eb;
|
||||
}
|
||||
QTabWidget::pane {
|
||||
border: 1px solid #d8e0eb;
|
||||
border-radius: 6px;
|
||||
@@ -920,20 +1052,20 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
self.object_edit_box.setObjectName("editSection")
|
||||
help_tip(
|
||||
self.object_edit_box,
|
||||
"选择特征后,这里只列出可可靠修改的语义尺寸;面积、中心和拓扑数据位于下方诊断信息。",
|
||||
"选择对象后,这里以参数卡片显示当前值、建模意图、目标值和应用按钮;诊断信息默认折叠在后面。",
|
||||
)
|
||||
object_edit_layout = QVBoxLayout(self.object_edit_box)
|
||||
object_edit_layout.setContentsMargins(0, 8, 0, 4)
|
||||
object_edit_layout.setSpacing(4)
|
||||
self.property_table = QTableWidget(0, 5)
|
||||
self.property_table = QTableWidget(0, 5, self.object_edit_box)
|
||||
self.property_table.setObjectName("propertyTable")
|
||||
self.property_table.setHorizontalHeaderLabels(["尺寸参数", "当前值", "建模意图", "目标值", "操作"])
|
||||
self.property_table.setHorizontalHeaderLabels(["参数", "当前值", "建模意图", "目标值", "操作"])
|
||||
self.property_table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.property_table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.property_table.setAlternatingRowColors(True)
|
||||
self.property_table.setMinimumHeight(180)
|
||||
self.property_table.setWordWrap(False)
|
||||
self.property_table.setTextElideMode(Qt.TextElideMode.ElideMiddle)
|
||||
self.property_table.setTextElideMode(Qt.TextElideMode.ElideRight)
|
||||
self.property_table.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
self.property_table.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
self.property_table.verticalHeader().setVisible(False)
|
||||
@@ -946,21 +1078,51 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
property_header.setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed)
|
||||
property_header.setSectionResizeMode(2, QHeaderView.ResizeMode.Fixed)
|
||||
property_header.setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed)
|
||||
property_header.setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch)
|
||||
self.property_table.setColumnWidth(0, 148)
|
||||
self.property_table.setColumnWidth(1, 68)
|
||||
self.property_table.setColumnWidth(2, 96)
|
||||
self.property_table.setColumnWidth(3, 72)
|
||||
self.property_table.setColumnWidth(4, 54)
|
||||
property_header.setSectionResizeMode(4, QHeaderView.ResizeMode.Fixed)
|
||||
self._resize_property_table_columns()
|
||||
self.property_table.installEventFilter(self)
|
||||
help_tip(
|
||||
self.property_table,
|
||||
"特征模式显示当前特征及局部关联特征的可变尺寸;建模意图决定这次修改是局部重建、拉伸/切除、端面移动还是整体缩放。",
|
||||
)
|
||||
self.property_table.itemChanged.connect(self._on_property_table_item_changed)
|
||||
object_edit_layout.addWidget(self.property_table)
|
||||
self.property_expand_button = QPushButton("展开全部参数")
|
||||
self.property_table.setVisible(False)
|
||||
self.property_table.setMaximumHeight(0)
|
||||
self.property_command_summary_label = QLabel("未选择可编辑对象")
|
||||
self.property_command_summary_label.setObjectName("propertyCommandSummary")
|
||||
self.property_command_summary_label.setWordWrap(True)
|
||||
object_edit_layout.addWidget(self.property_command_summary_label)
|
||||
self.property_command_bar = QFrame()
|
||||
self.property_command_bar.setObjectName("propertyCommandBar")
|
||||
self.property_command_layout = QHBoxLayout(self.property_command_bar)
|
||||
self.property_command_layout.setContentsMargins(3, 3, 3, 3)
|
||||
self.property_command_layout.setSpacing(2)
|
||||
object_edit_layout.addWidget(self.property_command_bar)
|
||||
self.property_command_help_label = QLabel("")
|
||||
self.property_command_help_label.setObjectName("propertyCommandHelp")
|
||||
self.property_command_help_label.setWordWrap(True)
|
||||
self.property_command_help_label.setVisible(False)
|
||||
object_edit_layout.addWidget(self.property_command_help_label)
|
||||
self.property_card_scroll = QScrollArea()
|
||||
self.property_card_scroll.setObjectName("propertyCardScroll")
|
||||
self.property_card_scroll.setWidgetResizable(True)
|
||||
self.property_card_scroll.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.property_card_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
self.property_card_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||
self.property_card_container = QWidget()
|
||||
self.property_card_container.setObjectName("propertyCardContainer")
|
||||
self.property_card_layout = QVBoxLayout(self.property_card_container)
|
||||
self.property_card_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.property_card_layout.setSpacing(6)
|
||||
self.property_card_scroll.setWidget(self.property_card_container)
|
||||
help_tip(
|
||||
self.property_card_scroll,
|
||||
"每张卡片对应一个参数;修改目标值后,点击卡片右上角的按钮只应用这一项。",
|
||||
)
|
||||
object_edit_layout.addWidget(self.property_card_scroll)
|
||||
self.property_expand_button = QPushButton("更多诊断信息")
|
||||
self.property_expand_button.setObjectName("propertyExpandBar")
|
||||
help_tip(self.property_expand_button, "参数较多时默认只显示前 6 行;点击这里展开或收起完整参数列表。")
|
||||
help_tip(self.property_expand_button, "默认优先显示可编辑参数和关键说明;点击这里展开或收起完整诊断信息。")
|
||||
self.property_expand_button.clicked.connect(self.toggle_property_table_expanded)
|
||||
self.property_expand_button.setVisible(False)
|
||||
self.property_expand_button.setMaximumHeight(22)
|
||||
@@ -969,6 +1131,7 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
property_action_row = QHBoxLayout()
|
||||
property_action_row.setContentsMargins(0, 0, 0, 0)
|
||||
self.apply_property_button = QPushButton("参数化建模")
|
||||
self.apply_property_button.setVisible(False)
|
||||
help_tip(self.apply_property_button, "按当前属性表里修改过的目标值执行参数化建模;一次只执行一个几何修改,成功后可撤销。")
|
||||
self.apply_property_button.clicked.connect(self.apply_current_property_edit)
|
||||
self.quick_export_all_button = QPushButton("导出当前完整STEP")
|
||||
@@ -1465,6 +1628,10 @@ class StepEditorWindow(WindowCoreMixin, WindowStateMixin, WindowActionMixin, Inf
|
||||
self.vtk_widget.setMouseTracking(True)
|
||||
self.vtk_widget.installEventFilter(self)
|
||||
root_layout.addWidget(self.vtk_widget, stretch=1)
|
||||
app = QApplication.instance()
|
||||
if app is not None and not getattr(self, "_global_tooltip_filter_installed", False):
|
||||
app.installEventFilter(self)
|
||||
self._global_tooltip_filter_installed = True
|
||||
|
||||
self.statusBar().showMessage("请选择 STEP 文件,或点击“读取模型”加载到可视化区域。")
|
||||
|
||||
@@ -1495,6 +1662,7 @@ def main() -> int:
|
||||
_enable_crash_log()
|
||||
path, smoke_test = _parse_args(sys.argv)
|
||||
_set_windows_taskbar_identity()
|
||||
_suppress_vtk_output_window()
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("几何参数化")
|
||||
app.setApplicationDisplayName("几何参数化")
|
||||
|
||||
Reference in New Issue
Block a user