update server
This commit is contained in:
@@ -0,0 +1,593 @@
|
||||
# control_tab.py
|
||||
"""页面2:系统状态栏(三卡片) + 控制参数(Section 卡片)
|
||||
|
||||
重构要点:
|
||||
- 状态栏:三张横向并排卡片,每张含圆形图标 + 大字数值 + 右上角色点
|
||||
- 控制参数区:Section 卡片(蓝竖线装饰),QGridLayout 双列布局,输入列拉伸占满约 2/3 页宽
|
||||
"""
|
||||
|
||||
import os
|
||||
from PySide6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QLabel, QLineEdit, QComboBox, QPushButton,
|
||||
QRadioButton, QCheckBox, QFrame, QButtonGroup, QSizePolicy,
|
||||
QGraphicsDropShadowEffect,
|
||||
)
|
||||
from PySide6.QtCore import Qt, Signal, QSize
|
||||
from PySide6.QtGui import QColor, QIcon
|
||||
from PySide6.QtSvgWidgets import QSvgWidget
|
||||
|
||||
from ui.connection_tab import _make_section_card
|
||||
|
||||
_SRC_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||
|
||||
# ==========================================
|
||||
# 工具函数:透明容器
|
||||
# ==========================================
|
||||
def _transparent_widget() -> QWidget:
|
||||
"""创建一个透明的空容器(用于包裹多个控件)。"""
|
||||
w = QWidget()
|
||||
w.setProperty("cssClass", "transparentBg")
|
||||
w.style().unpolish(w)
|
||||
w.style().polish(w)
|
||||
return w
|
||||
|
||||
|
||||
# ==========================================
|
||||
# 工具函数:三点状态栏卡片
|
||||
# ==========================================
|
||||
def _make_status_card(parent, title: str, value: str, unit: str,
|
||||
value_color: str, circle_bg: str,
|
||||
icon_path: str, dot_color: str):
|
||||
"""创建单张状态卡片(圆形图标 + 大字数值 + 右上角圆点)。
|
||||
|
||||
返回 (card, value_label)。
|
||||
"""
|
||||
card = QFrame(parent)
|
||||
card.setProperty("cssClass", "sectionCard")
|
||||
card.style().unpolish(card)
|
||||
card.style().polish(card)
|
||||
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
|
||||
shadow = QGraphicsDropShadowEffect(card)
|
||||
shadow.setColor(QColor(0, 0, 0, 10))
|
||||
shadow.setBlurRadius(14)
|
||||
shadow.setOffset(0, 2)
|
||||
card.setGraphicsEffect(shadow)
|
||||
|
||||
inner = QVBoxLayout(card)
|
||||
inner.setContentsMargins(16, 12, 16, 14)
|
||||
inner.setSpacing(0)
|
||||
|
||||
# ---- 右上角圆点 ----
|
||||
dot_row = QHBoxLayout()
|
||||
dot_row.setContentsMargins(0, 0, 0, 6)
|
||||
dot_row.addStretch()
|
||||
dot = QWidget()
|
||||
dot.setFixedSize(8, 8)
|
||||
dot.setStyleSheet(f"background: {dot_color}; border-radius: 4px;")
|
||||
dot_row.addWidget(dot)
|
||||
inner.addLayout(dot_row)
|
||||
|
||||
# ---- 主体:圆形图标 + 文本 ----
|
||||
body = QHBoxLayout()
|
||||
body.setSpacing(30)
|
||||
|
||||
# 圆形图标容器
|
||||
icon_circle = QWidget()
|
||||
icon_circle.setFixedSize(82, 82)
|
||||
icon_circle.setStyleSheet(
|
||||
f"background: {circle_bg}; border-radius: 41px;"
|
||||
)
|
||||
icon_inner = QVBoxLayout(icon_circle)
|
||||
icon_inner.setContentsMargins(0, 0, 0, 0)
|
||||
icon_inner.setAlignment(Qt.AlignCenter)
|
||||
|
||||
svg = QSvgWidget(icon_path)
|
||||
svg.setFixedSize(48, 48)
|
||||
icon_inner.addWidget(svg, alignment=Qt.AlignCenter)
|
||||
|
||||
body.addWidget(icon_circle)
|
||||
|
||||
# 文本列
|
||||
text_col = QVBoxLayout()
|
||||
text_col.setSpacing(4)
|
||||
|
||||
title_lbl = QLabel(title)
|
||||
title_lbl.setStyleSheet(
|
||||
"color: #555555; font-size: 15px; background: transparent; border: none;"
|
||||
)
|
||||
text_col.addWidget(title_lbl)
|
||||
|
||||
value_row = QHBoxLayout()
|
||||
value_row.setSpacing(4)
|
||||
|
||||
val_lbl = QLabel(value)
|
||||
val_lbl.setStyleSheet(
|
||||
f"color: {value_color}; font-size: 56px; font-weight: bold;"
|
||||
"background: transparent; border: none;"
|
||||
)
|
||||
value_row.addWidget(val_lbl)
|
||||
|
||||
unit_lbl = QLabel(unit)
|
||||
unit_lbl.setStyleSheet(
|
||||
f"color: {value_color}; font-size: 24px; background: transparent;"
|
||||
"border: none; padding-top: 14px;"
|
||||
)
|
||||
value_row.addWidget(unit_lbl)
|
||||
value_row.addStretch()
|
||||
|
||||
text_col.addLayout(value_row)
|
||||
body.addLayout(text_col, 1)
|
||||
inner.addLayout(body, 1)
|
||||
|
||||
return card, val_lbl
|
||||
|
||||
|
||||
# ==========================================
|
||||
# 工具函数:行级标签
|
||||
# ==========================================
|
||||
def _label(text: str, parent=None) -> QLabel:
|
||||
"""紧凑表单标签。"""
|
||||
lbl = QLabel(text, parent)
|
||||
lbl.setStyleSheet(
|
||||
"color: #333333; font-size: 14px; font-weight: bold; background: transparent;"
|
||||
)
|
||||
lbl.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||
return lbl
|
||||
|
||||
|
||||
def _unit_label(unit: str, parent=None) -> QLabel:
|
||||
"""单位标签(灰色小字)。"""
|
||||
lbl = QLabel(unit, parent)
|
||||
lbl.setStyleSheet(
|
||||
"color: #94A3B8; font-size: 12px; background: transparent;"
|
||||
)
|
||||
return lbl
|
||||
|
||||
|
||||
# ==========================================
|
||||
# 主类
|
||||
# ==========================================
|
||||
class ControlTab(QWidget):
|
||||
"""控制设置页面"""
|
||||
|
||||
# ---- 信号 ----
|
||||
target_set_requested = Signal(float)
|
||||
mode_changed = Signal(str)
|
||||
pid_update_requested = Signal(float, float, float)
|
||||
model_load_requested = Signal(str)
|
||||
models_refresh_requested = Signal()
|
||||
control_toggle_requested = Signal()
|
||||
plot_requested = Signal()
|
||||
manual_valve_set_requested = Signal(float)
|
||||
log_message_requested = Signal(str)
|
||||
|
||||
def __init__(self, colors: dict, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setProperty("cssClass", "tabPage")
|
||||
self.colors = colors
|
||||
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(20, 16, 20, 16)
|
||||
main_layout.setSpacing(14)
|
||||
|
||||
# ==========================================
|
||||
# A. 系统状态栏(三卡片)
|
||||
# ==========================================
|
||||
status_bar = QHBoxLayout()
|
||||
status_bar.setSpacing(14)
|
||||
|
||||
self._pressure_card, self.current_pressure_lbl = _make_status_card(
|
||||
self,
|
||||
title="当前系统压力",
|
||||
value="0.0",
|
||||
unit="kPa",
|
||||
value_color="#0F955D",
|
||||
circle_bg="#E2F5ED",
|
||||
icon_path=os.path.join(_SRC_DIR, "pressure.svg"),
|
||||
dot_color="#0F955D",
|
||||
)
|
||||
|
||||
self._target_card, self.target_pressure_lbl = _make_status_card(
|
||||
self,
|
||||
title="设置目标压力",
|
||||
value="0.0",
|
||||
unit="kPa",
|
||||
value_color="#0960D1",
|
||||
circle_bg="#EBF3FE",
|
||||
icon_path=os.path.join(_SRC_DIR, "target.svg"),
|
||||
dot_color="#0960D1",
|
||||
)
|
||||
|
||||
self._valve_card, self.valve_opening_lbl = _make_status_card(
|
||||
self,
|
||||
title="控制阀门开度",
|
||||
value="0.0",
|
||||
unit="%",
|
||||
value_color="#E67E22",
|
||||
circle_bg="#FFF2E8",
|
||||
icon_path=os.path.join(_SRC_DIR, "valve.svg"),
|
||||
dot_color="#E67E22",
|
||||
)
|
||||
|
||||
status_bar.addWidget(self._pressure_card)
|
||||
status_bar.addWidget(self._target_card)
|
||||
status_bar.addWidget(self._valve_card)
|
||||
main_layout.addLayout(status_bar)
|
||||
|
||||
# ==========================================
|
||||
# B. 控制参数设置区(Section 卡片)
|
||||
# ==========================================
|
||||
ctrl_card, ctrl_grid = _make_section_card(self, "控制设置", colors)
|
||||
self._build_control_section(ctrl_grid)
|
||||
main_layout.addWidget(ctrl_card)
|
||||
|
||||
main_layout.addStretch()
|
||||
|
||||
# 信号连接
|
||||
self.mode_group.buttonClicked.connect(self._on_mode_changed_internal)
|
||||
|
||||
# ==========================================
|
||||
# 控制设置 — QGridLayout 双列布局,输入列拉伸占满 2/3 页宽
|
||||
# ==========================================
|
||||
def _build_control_section(self, grid: QGridLayout):
|
||||
# 沿用 _make_section_card 的列配置:col 0 标签固定 148px,col 1 输入区拉伸
|
||||
grid.setVerticalSpacing(16)
|
||||
|
||||
# --- B1: 物理工况 (容积 + 流量) ---
|
||||
row = 0
|
||||
grid.addWidget(_label("物理工况:"), row, 0)
|
||||
b1 = _transparent_widget()
|
||||
b1h = QHBoxLayout(b1)
|
||||
b1h.setContentsMargins(0, 0, 0, 0)
|
||||
b1h.setSpacing(6)
|
||||
b1h.addWidget(_label("容积"))
|
||||
self.volume_entry = QLineEdit()
|
||||
self.volume_entry.setFixedWidth(120)
|
||||
b1h.addWidget(self.volume_entry)
|
||||
b1h.addWidget(_unit_label("L"))
|
||||
b1h.addSpacing(32)
|
||||
b1h.addWidget(_label("流量"))
|
||||
self.flow_entry = QLineEdit("100")
|
||||
self.flow_entry.setFixedWidth(120)
|
||||
b1h.addWidget(self.flow_entry)
|
||||
b1h.addWidget(_unit_label("L/min"))
|
||||
b1h.addStretch()
|
||||
grid.addWidget(b1, row, 1)
|
||||
|
||||
# --- B2: 目标压力 + 按钮 ---
|
||||
row = 1
|
||||
grid.addWidget(_label("目标压力:"), row, 0)
|
||||
b2 = _transparent_widget()
|
||||
b2h = QHBoxLayout(b2)
|
||||
b2h.setContentsMargins(0, 0, 0, 0)
|
||||
b2h.setSpacing(6)
|
||||
self.target_entry = QLineEdit("80.0")
|
||||
self.target_entry.setFixedWidth(200)
|
||||
b2h.addWidget(self.target_entry)
|
||||
b2h.addWidget(_unit_label("kPa"))
|
||||
b2h.addSpacing(10)
|
||||
self.set_target_btn = QPushButton("设置目标")
|
||||
self.set_target_btn.setIcon(QIcon(os.path.join(_SRC_DIR, "target.svg")))
|
||||
self.set_target_btn.setIconSize(QSize(18, 18))
|
||||
self.set_target_btn.setStyleSheet(
|
||||
"QPushButton { background: white; color: #0960D1; border: 1.5px solid #0960D1;"
|
||||
"border-radius: 6px; padding: 9px 20px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background: #EBF3FE; }"
|
||||
)
|
||||
self.set_target_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.set_target_btn.clicked.connect(self._on_set_target)
|
||||
b2h.addWidget(self.set_target_btn)
|
||||
b2h.addStretch()
|
||||
grid.addWidget(b2, row, 1)
|
||||
|
||||
# --- B3: 控制模式单选 ---
|
||||
row = 2
|
||||
grid.addWidget(_label("控制方式:"), row, 0)
|
||||
b3 = _transparent_widget()
|
||||
b3h = QHBoxLayout(b3)
|
||||
b3h.setContentsMargins(0, 0, 0, 0)
|
||||
b3h.setSpacing(24)
|
||||
self.mode_group = QButtonGroup(self)
|
||||
self.radio_rl = QRadioButton("智能自动")
|
||||
self.radio_pid = QRadioButton("手动PID")
|
||||
self.radio_manual = QRadioButton("设置开度")
|
||||
self.mode_group.addButton(self.radio_rl, 0)
|
||||
self.mode_group.addButton(self.radio_pid, 1)
|
||||
self.mode_group.addButton(self.radio_manual, 2)
|
||||
self.radio_rl.setChecked(True)
|
||||
b3h.addWidget(self.radio_rl)
|
||||
b3h.addWidget(self.radio_pid)
|
||||
b3h.addWidget(self.radio_manual)
|
||||
b3h.addStretch()
|
||||
grid.addWidget(b3, row, 1)
|
||||
|
||||
# --- B4: 模型面板(跨两列,内部标签固定148px与外层col0对齐) ---
|
||||
row = 3
|
||||
self.rl_panel = QWidget()
|
||||
self.rl_panel.setStyleSheet("background: transparent;")
|
||||
rl_layout = QHBoxLayout(self.rl_panel)
|
||||
rl_layout.setContentsMargins(0, 0, 0, 0)
|
||||
rl_layout.setSpacing(8)
|
||||
rl_lbl = _label("决策模型:")
|
||||
rl_lbl.setFixedWidth(148)
|
||||
rl_layout.addWidget(rl_lbl)
|
||||
self.model_combobox = QComboBox()
|
||||
self.model_combobox.setFixedWidth(280)
|
||||
self.model_combobox.setFixedHeight(36)
|
||||
rl_layout.addWidget(self.model_combobox)
|
||||
self.load_model_btn = QPushButton("加载模型")
|
||||
self.load_model_btn.setStyleSheet(
|
||||
"QPushButton { background: #0960D1; color: white; border: none;"
|
||||
"border-radius: 6px; padding: 7px 16px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background: #0856B8; }"
|
||||
)
|
||||
self.load_model_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.load_model_btn.clicked.connect(self._on_load_model)
|
||||
rl_layout.addWidget(self.load_model_btn)
|
||||
self.refresh_models_btn = QPushButton("🔄 刷新")
|
||||
self.refresh_models_btn.setProperty("cssClass", "refresh")
|
||||
self.refresh_models_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.refresh_models_btn.clicked.connect(self._on_refresh_models)
|
||||
rl_layout.addWidget(self.refresh_models_btn)
|
||||
rl_layout.addStretch()
|
||||
grid.addWidget(self.rl_panel, row, 0, 1, 2)
|
||||
|
||||
# --- B5: PID 面板(跨两列,内部标签固定148px) ---
|
||||
row = 4
|
||||
self.pid_panel = QWidget()
|
||||
self.pid_panel.setStyleSheet("background: transparent;")
|
||||
self.pid_panel.hide()
|
||||
pid_layout = QHBoxLayout(self.pid_panel)
|
||||
pid_layout.setContentsMargins(0, 0, 0, 0)
|
||||
pid_layout.setSpacing(6)
|
||||
pid_lbl = _label("PID 调节:")
|
||||
pid_lbl.setFixedWidth(148)
|
||||
pid_layout.addWidget(pid_lbl)
|
||||
pid_layout.addWidget(_label("Kp:"))
|
||||
self.Kp_entry = QLineEdit("1.0")
|
||||
self.Kp_entry.setFixedWidth(80)
|
||||
pid_layout.addWidget(self.Kp_entry)
|
||||
pid_layout.addWidget(_label("Ki:"))
|
||||
self.Ki_entry = QLineEdit("0.4")
|
||||
self.Ki_entry.setFixedWidth(80)
|
||||
pid_layout.addWidget(self.Ki_entry)
|
||||
pid_layout.addWidget(_label("Kd:"))
|
||||
self.Kd_entry = QLineEdit("0")
|
||||
self.Kd_entry.setFixedWidth(80)
|
||||
pid_layout.addWidget(self.Kd_entry)
|
||||
self.update_pid_btn = QPushButton("更新PID参数")
|
||||
self.update_pid_btn.setStyleSheet(
|
||||
"QPushButton { background: #0960D1; color: white; border: none;"
|
||||
"border-radius: 6px; padding: 7px 16px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background: #0856B8; }"
|
||||
)
|
||||
self.update_pid_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.update_pid_btn.clicked.connect(self._on_update_pid)
|
||||
pid_layout.addWidget(self.update_pid_btn)
|
||||
pid_layout.addStretch()
|
||||
grid.addWidget(self.pid_panel, row, 0, 1, 2)
|
||||
|
||||
# --- B6: 手动开度面板(跨两列,内部标签固定148px) ---
|
||||
row = 5
|
||||
self.manual_panel = QWidget()
|
||||
self.manual_panel.setStyleSheet("background: transparent;")
|
||||
self.manual_panel.hide()
|
||||
man_layout = QHBoxLayout(self.manual_panel)
|
||||
man_layout.setContentsMargins(0, 0, 0, 0)
|
||||
man_layout.setSpacing(6)
|
||||
man_lbl = _label("设置开度:")
|
||||
man_lbl.setFixedWidth(148)
|
||||
man_layout.addWidget(man_lbl)
|
||||
self.valve_entry = QLineEdit()
|
||||
self.valve_entry.setFixedWidth(160)
|
||||
man_layout.addWidget(self.valve_entry)
|
||||
man_layout.addWidget(_unit_label("%"))
|
||||
self.set_valve_btn = QPushButton("设置")
|
||||
self.set_valve_btn.setStyleSheet(
|
||||
"QPushButton { background: #0960D1; color: white; border: none;"
|
||||
"border-radius: 6px; padding: 7px 16px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background: #0856B8; }"
|
||||
)
|
||||
self.set_valve_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.set_valve_btn.clicked.connect(self._on_set_valve)
|
||||
man_layout.addWidget(self.set_valve_btn)
|
||||
man_layout.addStretch()
|
||||
grid.addWidget(self.manual_panel, row, 0, 1, 2)
|
||||
|
||||
# --- B7: 控制启停行(跨两列) ---
|
||||
row = 6
|
||||
b7 = _transparent_widget()
|
||||
b7h = QHBoxLayout(b7)
|
||||
b7h.setContentsMargins(0, 0, 0, 0)
|
||||
b7h.setSpacing(12)
|
||||
self.start_btn = QPushButton("开始控制")
|
||||
self.start_btn.setIcon(QIcon(os.path.join(_SRC_DIR, "start_control.svg")))
|
||||
self.start_btn.setIconSize(QSize(18, 18))
|
||||
self.start_btn.setProperty("cssClass", "action")
|
||||
self.start_btn.setStyleSheet(
|
||||
"QPushButton { background-color: #0F955D; color: white; border: none;"
|
||||
"border-radius: 6px; padding: 9px 24px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background-color: #0D8250; }"
|
||||
)
|
||||
self.start_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.start_btn.clicked.connect(self._on_toggle_control)
|
||||
self.plot_btn = QPushButton("绘制图线")
|
||||
self.plot_btn.setIcon(QIcon(os.path.join(_SRC_DIR, "plot.svg")))
|
||||
self.plot_btn.setIconSize(QSize(18, 18))
|
||||
self.plot_btn.setStyleSheet(
|
||||
"QPushButton { background: white; color: #0960D1; border: 1.5px solid #0960D1;"
|
||||
"border-radius: 6px; padding: 9px 20px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background: #EBF3FE; }"
|
||||
)
|
||||
self.plot_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.plot_btn.clicked.connect(self._on_plot)
|
||||
self.collect_data_cb = QCheckBox("同步收集数据集")
|
||||
b7h.addWidget(self.start_btn)
|
||||
b7h.addWidget(self.plot_btn)
|
||||
b7h.addWidget(self.collect_data_cb)
|
||||
grid.addWidget(b7, row, 0, 1, 2)
|
||||
|
||||
# ============================================================
|
||||
# 以下方法完全兼容旧版 API,main_window.py 无需变动
|
||||
# ============================================================
|
||||
|
||||
# ---- 模式切换 ----
|
||||
def _on_mode_changed_internal(self, btn):
|
||||
if btn == self.radio_pid:
|
||||
mode = "PID"
|
||||
self.rl_panel.hide()
|
||||
self.manual_panel.hide()
|
||||
self.pid_panel.show()
|
||||
self.collect_data_cb.setEnabled(True)
|
||||
self.model_combobox.setEnabled(False)
|
||||
self.load_model_btn.setEnabled(False)
|
||||
self.refresh_models_btn.setEnabled(False)
|
||||
elif btn == self.radio_rl:
|
||||
mode = "RL"
|
||||
self.pid_panel.hide()
|
||||
self.manual_panel.hide()
|
||||
self.rl_panel.show()
|
||||
self.collect_data_cb.setEnabled(True)
|
||||
self.model_combobox.setEnabled(True)
|
||||
self.load_model_btn.setEnabled(True)
|
||||
self.refresh_models_btn.setEnabled(True)
|
||||
elif btn == self.radio_manual:
|
||||
mode = "MANUAL"
|
||||
self.rl_panel.hide()
|
||||
self.pid_panel.hide()
|
||||
self.manual_panel.show()
|
||||
self.collect_data_cb.setChecked(False)
|
||||
self.collect_data_cb.setEnabled(False)
|
||||
else:
|
||||
mode = "RL"
|
||||
self.mode_changed.emit(mode)
|
||||
|
||||
def init_mode_ui(self):
|
||||
self.rl_panel.show()
|
||||
self.pid_panel.hide()
|
||||
self.manual_panel.hide()
|
||||
|
||||
def set_mode_switch_enabled(self, enabled: bool):
|
||||
self.radio_pid.setEnabled(enabled)
|
||||
self.radio_rl.setEnabled(enabled)
|
||||
self.radio_manual.setEnabled(enabled)
|
||||
|
||||
# ---- 信号处理 ----
|
||||
def _on_set_target(self):
|
||||
try:
|
||||
target = float(self.target_entry.text())
|
||||
if 0 <= target <= 3000:
|
||||
self.target_set_requested.emit(target)
|
||||
else:
|
||||
self.target_set_requested.emit(-1)
|
||||
except ValueError:
|
||||
self.target_set_requested.emit(-1)
|
||||
|
||||
def _on_load_model(self):
|
||||
selected = self.model_combobox.currentText()
|
||||
self.model_load_requested.emit(selected)
|
||||
|
||||
def _on_refresh_models(self):
|
||||
self.models_refresh_requested.emit()
|
||||
|
||||
def _on_update_pid(self):
|
||||
try:
|
||||
kp = float(self.Kp_entry.text())
|
||||
ki = float(self.Ki_entry.text())
|
||||
kd = float(self.Kd_entry.text())
|
||||
self.pid_update_requested.emit(kp, ki, kd)
|
||||
except ValueError:
|
||||
self.log_message_requested.emit("错误: PID参数输入无效,请输入有效数字")
|
||||
|
||||
def _on_set_valve(self):
|
||||
try:
|
||||
valve = float(self.valve_entry.text())
|
||||
if 0 <= valve <= 120:
|
||||
self.manual_valve_set_requested.emit(valve)
|
||||
else:
|
||||
self.manual_valve_set_requested.emit(-1)
|
||||
except ValueError:
|
||||
self.manual_valve_set_requested.emit(-2)
|
||||
|
||||
def _on_toggle_control(self):
|
||||
self.control_toggle_requested.emit()
|
||||
|
||||
def _on_plot(self):
|
||||
self.plot_requested.emit()
|
||||
|
||||
# ---- 公开方法 (由 main_window 调用) ----
|
||||
def set_control_running(self, running: bool):
|
||||
if running:
|
||||
self.start_btn.setText("停止控制")
|
||||
self.start_btn.setIcon(QIcon())
|
||||
self.start_btn.setProperty("cssClass", "danger")
|
||||
self.start_btn.setStyleSheet(
|
||||
"QPushButton { background-color: #EF4444; color: white; border: none;"
|
||||
"border-radius: 6px; padding: 9px 24px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background-color: #DC2626; }"
|
||||
)
|
||||
else:
|
||||
self.start_btn.setText("开始控制")
|
||||
self.start_btn.setIcon(QIcon(os.path.join(_SRC_DIR, "start_control.svg")))
|
||||
self.start_btn.setIconSize(QSize(18, 18))
|
||||
self.start_btn.setProperty("cssClass", "action")
|
||||
self.start_btn.setStyleSheet(
|
||||
"QPushButton { background-color: #0F955D; color: white; border: none;"
|
||||
"border-radius: 6px; padding: 9px 24px; font-weight: bold; font-size: 14px; }"
|
||||
"QPushButton:hover { background-color: #0D8250; }"
|
||||
)
|
||||
self.start_btn.style().unpolish(self.start_btn)
|
||||
self.start_btn.style().polish(self.start_btn)
|
||||
|
||||
def update_display(self, pressure: float, target: float, valve: float):
|
||||
self.current_pressure_lbl.setText(f"{pressure:.1f}")
|
||||
self.target_pressure_lbl.setText(f"{target:.1f}")
|
||||
self.valve_opening_lbl.setText(f"{valve:.1f}")
|
||||
|
||||
def update_pid_entries(self, kp: float, ki: float, kd: float):
|
||||
self.Kp_entry.setText(f"{kp:.3f}")
|
||||
self.Ki_entry.setText(f"{ki:.3f}")
|
||||
self.Kd_entry.setText(f"{kd:.3f}")
|
||||
|
||||
def update_model_list(self, files: list):
|
||||
self.model_combobox.clear()
|
||||
if files:
|
||||
self.model_combobox.addItems(files)
|
||||
else:
|
||||
self.model_combobox.addItem("无模型文件")
|
||||
|
||||
def get_mode(self) -> str:
|
||||
if self.radio_pid.isChecked():
|
||||
return "PID"
|
||||
elif self.radio_manual.isChecked():
|
||||
return "MANUAL"
|
||||
return "RL"
|
||||
|
||||
def get_collect_data(self) -> bool:
|
||||
return self.collect_data_cb.isChecked()
|
||||
|
||||
def get_control_params(self) -> dict:
|
||||
return {
|
||||
"volume": float(self.volume_entry.text() or "0"),
|
||||
"flow": float(self.flow_entry.text() or "100"),
|
||||
}
|
||||
|
||||
def get_pid_params(self) -> tuple:
|
||||
return (
|
||||
float(self.Kp_entry.text() or "1.0"),
|
||||
float(self.Ki_entry.text() or "0.4"),
|
||||
float(self.Kd_entry.text() or "0"),
|
||||
)
|
||||
|
||||
def get_manual_valve(self) -> float:
|
||||
return float(self.valve_entry.text() or "0")
|
||||
|
||||
def enable_plot_button(self, enable: bool):
|
||||
self.plot_btn.setEnabled(enable)
|
||||
|
||||
def set_pid_entries_text(self, kp, ki, kd):
|
||||
self.Kp_entry.setText(str(kp))
|
||||
self.Ki_entry.setText(str(ki))
|
||||
self.Kd_entry.setText(str(kd))
|
||||
Reference in New Issue
Block a user