"""参数补充对话框
对标 VBA print.vb 中的 InputBox 交互式参数补充逻辑:
- 口径 (DN) 补充 → 对标 确认口径() InputBox
- 压力 (PN) 补充 → 对标 确认压力() InputBox
- 温度补充 → 对标 print.vb 第659-664行
- 介质补充 → 对标 print.vb 第740-748行
- 材质补充 → 对标 print.vb 的 FaTiCaiZhi/FaGanCaiZhi/QiBiJianCaiZhi
v2.0 新增:
- 完整的 PySide6 对话框替代 VBA InputBox
- 下拉选项(材质牌号从 SQLite 读取)
- 自动预填已有值
- 支持批量跳过(一键全部留空)
"""
from __future__ import annotations
from typing import Any
from PySide6.QtCore import Signal
from PySide6.QtWidgets import (
QComboBox,
QDialog,
QDialogButtonBox,
QFormLayout,
QGroupBox,
QHBoxLayout,
QLabel,
QLineEdit,
QPushButton,
QVBoxLayout,
QWidget,
)
[文档]
class ParamSupplementDialog(QDialog):
"""参数补充对话框
对标 VBA print.vb 批量打印时的一连串 InputBox 交互:
1. 口径 InputBox(第635/671行)
2. 压力 InputBox(第651/703行)
3. 温度 InputBox(第660/716行)
4. 介质 InputBox(第741行)
Attributes:
params: 用户填写的参数字典
confirmed: 用户是否点击了"确认"
skip_all: 用户是否点击了"跳过全部"
"""
# 信号:确认补充完成
supplement_confirmed = Signal(dict)
def __init__(
self,
model: str = "",
prefill: dict[str, Any] | None = None,
material_grades: dict[str, list[str]] | None = None,
parent: QWidget | None = None,
) -> None:
"""初始化参数补充对话框
Args:
model: 当前产品型号,用于标题显示
prefill: 预填参数字典,键名:
- caliber: 口径
- pressure: 压力
- temperature: 温度
- medium: 介质
- test_standard: 试压标准
- inspector_id: 检验工号
- body_material: 阀体材质
- stem_material: 阀杆材质
- disc_material: 启闭件材质
material_grades: 材质牌号字典 {分类: [牌号列表]}
分类: "body" / "stem" / "disc" / "common"
parent: 父窗口
"""
super().__init__(parent)
self.model = model
self.prefill = prefill or {}
self.material_grades = material_grades or {}
self._confirmed: bool = False
self._skip_all: bool = False
self.setup_ui()
self.load_prefill()
@property
def confirmed(self) -> bool:
"""用户是否确认"""
return self._confirmed
@property
def skip_all(self) -> bool:
"""用户是否跳过全部(留空)"""
return self._skip_all
@property
def params(self) -> dict[str, str]:
"""获取用户填写的参数"""
return {
"caliber": self.caliber_input.text().strip(),
"pressure": self.pressure_input.text().strip(),
"temperature": self.temperature_input.text().strip(),
"medium": self.medium_input.text().strip(),
"test_standard": self.standard_input.text().strip(),
"inspector_id": self.inspector_input.text().strip(),
"body_material": self.body_material_combo.currentText().strip(),
"stem_material": self.stem_material_combo.currentText().strip(),
"disc_material": self.disc_material_combo.currentText().strip(),
}
# ============================================================
# UI 构建
# ============================================================
[文档]
def setup_ui(self) -> None:
"""构建对话框 UI"""
title = f"参数补充 - {self.model}" if self.model else "参数补充"
self.setWindowTitle(title)
self.setMinimumWidth(480)
self.resize(520, 560)
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(12, 12, 12, 12)
main_layout.setSpacing(10)
# 标题提示
title_label = QLabel(
f"产品型号:<b>{self.model}</b>\n以下参数缺失或需确认,请补充后继续打印:"
)
title_label.setWordWrap(True)
title_label.setStyleSheet("font-size: 12px; padding: 4px;")
main_layout.addWidget(title_label)
# === 基本参数组 ===
basic_group = QGroupBox("基本参数")
basic_layout = QFormLayout(basic_group)
basic_layout.setSpacing(6)
# 公称通径 (DN)
self.caliber_input = QLineEdit()
self.caliber_input.setPlaceholderText("如 DN100, 150")
basic_layout.addRow("公称通径 (DN):", self.caliber_input)
# 公称压力 (PN)
self.pressure_input = QLineEdit()
self.pressure_input.setPlaceholderText("如 2.5, 150Lb, 2.5MPa")
basic_layout.addRow("公称压力 (PN):", self.pressure_input)
# 工作温度
self.temperature_input = QLineEdit()
self.temperature_input.setPlaceholderText("如 ≤425℃, 常温")
basic_layout.addRow("工作温度:", self.temperature_input)
# 适用介质
self.medium_input = QLineEdit()
self.medium_input.setPlaceholderText("如 水、蒸汽、油品")
basic_layout.addRow("适用介质:", self.medium_input)
main_layout.addWidget(basic_group)
# === 检验参数组 ===
inspect_group = QGroupBox("检验参数")
inspect_layout = QFormLayout(inspect_group)
inspect_layout.setSpacing(6)
# 试压标准
self.standard_input = QLineEdit()
self.standard_input.setPlaceholderText("如 GB/T 13927-2008")
inspect_layout.addRow("试压标准:", self.standard_input)
# 检验工号
self.inspector_input = QLineEdit()
self.inspector_input.setPlaceholderText("检验员工号")
inspect_layout.addRow("检验工号:", self.inspector_input)
main_layout.addWidget(inspect_group)
# === 材质参数组 ===
material_group = QGroupBox("材质参数")
material_layout = QFormLayout(material_group)
material_layout.setSpacing(6)
# 阀体材质
self.body_material_combo = self._create_material_combo("body")
material_layout.addRow("阀体材质:", self.body_material_combo)
# 阀杆材质
self.stem_material_combo = self._create_material_combo("stem")
material_layout.addRow("阀杆材质:", self.stem_material_combo)
# 启闭件材质
self.disc_material_combo = self._create_material_combo("disc")
material_layout.addRow("启闭件材质:", self.disc_material_combo)
main_layout.addWidget(material_group)
# === 按钮区域 ===
button_layout = QHBoxLayout()
button_layout.setSpacing(8)
# 跳过全部按钮
self.skip_btn = QPushButton("跳过全部(留空)")
self.skip_btn.setToolTip("所有参数留空,继续打印")
self.skip_btn.clicked.connect(self._on_skip_all)
button_layout.addWidget(self.skip_btn)
button_layout.addStretch()
# 确认/取消
self.button_box = QDialogButtonBox(
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
)
self.button_box.button(QDialogButtonBox.StandardButton.Ok).setText("确认并打印")
self.button_box.button(QDialogButtonBox.StandardButton.Cancel).setText("取消")
self.button_box.accepted.connect(self._on_confirm)
self.button_box.rejected.connect(self.reject)
button_layout.addWidget(self.button_box)
main_layout.addLayout(button_layout)
def _create_material_combo(self, category: str) -> QComboBox:
"""创建材质下拉框(可编辑)
Args:
category: 材质分类 (body/stem/disc)
Returns:
QComboBox: 可编辑下拉框
"""
combo = QComboBox()
combo.setEditable(True)
combo.setInsertPolicy(QComboBox.InsertPolicy.NoInsert)
# 从预置数据填充
grades = self.material_grades.get(category, [])
# 也添加 common 通用材质
common_grades = self.material_grades.get("common", [])
all_grades = sorted(set(grades + common_grades))
combo.addItem("") # 空选项
for grade in all_grades:
combo.addItem(grade)
return combo
# ============================================================
# 预填数据
# ============================================================
[文档]
def load_prefill(self) -> None:
"""加载预填数据"""
prefill = self.prefill
# 基本参数
self._set_text_if(self.caliber_input, prefill.get("caliber"))
self._set_text_if(self.pressure_input, prefill.get("pressure"))
self._set_text_if(self.temperature_input, prefill.get("temperature"))
self._set_text_if(self.medium_input, prefill.get("medium"))
# 检验参数
self._set_text_if(self.standard_input, prefill.get("test_standard"))
self._set_text_if(self.inspector_input, prefill.get("inspector_id"))
# 材质(可编辑下拉框)
self._set_combo(self.body_material_combo, prefill.get("body_material"))
self._set_combo(self.stem_material_combo, prefill.get("stem_material"))
self._set_combo(self.disc_material_combo, prefill.get("disc_material"))
# 自动聚焦第一个空字段
self._focus_first_empty()
@staticmethod
def _set_text_if(widget: QLineEdit, value: Any) -> None:
if value:
widget.setText(str(value))
@staticmethod
def _set_combo(combo: QComboBox, value: Any) -> None:
if value:
idx = combo.findText(str(value))
if idx >= 0:
combo.setCurrentIndex(idx)
else:
combo.setEditText(str(value))
def _focus_first_empty(self) -> None:
if not self.caliber_input.text():
self.caliber_input.setFocus()
elif not self.pressure_input.text():
self.pressure_input.setFocus()
else:
self.caliber_input.setFocus()
# ============================================================
# 事件处理
# ============================================================
def _on_confirm(self) -> None:
"""确认按钮点击"""
self._confirmed = True
self.accept()
def _on_skip_all(self) -> None:
"""跳过全部(留空)"""
self._skip_all = True
self._confirmed = True # 也算确认(只是参数为空)
self.accept()
# ============================================================
# 静态工厂方法
# ============================================================
[文档]
@staticmethod
def get_parameters(
model: str = "",
prefill: dict[str, Any] | None = None,
material_grades: dict[str, list[str]] | None = None,
parent: QWidget | None = None,
) -> tuple[bool, bool, dict[str, str]]:
"""弹出参数补充对话框并返回结果
对标 VBA 的 InputBox 调用模式,提供便捷的静态方法。
Args:
model: 产品型号
prefill: 预填参数
material_grades: 材质牌号选项
parent: 父窗口
Returns:
(confirmed, skip_all, params) 元组
- confirmed: 用户是否确认(含跳过)
- skip_all: 是否跳过全部留空
- params: 填写的参数字典
"""
dialog = ParamSupplementDialog(
model=model,
prefill=prefill,
material_grades=material_grades,
parent=parent,
)
dialog.exec()
return dialog.confirmed, dialog.skip_all, dialog.params