点位设置界面增加了状态设置,从数据库加载状态

This commit is contained in:
2025-09-10 20:27:51 +08:00
parent 3c9784b362
commit b90395ea24
3 changed files with 789 additions and 43 deletions

View File

@ -0,0 +1,382 @@
from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QHBoxLayout,
QFormLayout,
QGroupBox,
QDialog,
)
from qfluentwidgets import (
PushButton,
ComboBox,
DoubleSpinBox,
SpinBox,
setTheme,
Theme,
StrongBodyLabel,
EditableComboBox,
RadioButton,
isDarkTheme,
MessageBox,
)
from ...model.point_state import PointState
class StatusEditDialog(QDialog):
point_state_applied = Signal(int, PointState)
def __init__(self, pos_name, selected_row_idx, parent=None):
super().__init__(parent)
# 窗口基本设置
self.setWindowTitle("状态编辑") # 设置窗口标题
self.resize(600, 660) # 窗口大小
self.setMinimumSize(550, 560) # 最小尺寸限制
# 点位名称
self.pos_name = pos_name
# 选中行的行索引
self.selected_row_idx = selected_row_idx
self.__initWidget()
def __initWidget(self):
# 创建控件
self.__createWidget()
# 设置样式
self.__initStyles()
# 设置布局
self.__initLayout()
# 绑定
self.__bind()
# 创建相关控件
def __createWidget(self):
# 1. 点位名称输入
self.name_combo = EditableComboBox()
self.name_combo.addItems(
["抓取点", "破袋点", "震动点", "扔袋点", "相机/待抓点"]
)
# 检查点位名称在下拉框是否已经存在
target_pos_name = self.pos_name
pos_name_index = self.name_combo.findText(target_pos_name)
# 若未找到(索引=-1则添加 表单中 的点位名字
if pos_name_index == -1:
self.name_combo.addItem(self.pos_name)
# 选中新添加的这项
new_index = self.name_combo.count() - 1
self.name_combo.setCurrentIndex(new_index)
else:
# 已经存在的话就直接选中
self.name_combo.setCurrentIndex(pos_name_index)
self.name_combo.setPlaceholderText("请设置点位名称")
# 2. 工具坐标系id
self.tool_coord_spin = SpinBox()
self.tool_coord_spin.setRange(0, 99) # 0-99范围
self.tool_coord_spin.setValue(0) # 默认值
self.tool_coord_btn = PushButton("获取当前工具坐标id")
# 3. 工件坐标系id
self.work_coord_spin = SpinBox()
self.work_coord_spin.setRange(0, 99) # 0-99范围
self.work_coord_spin.setValue(0) # 默认值
self.work_coord_btn = PushButton("获取当前工件坐标id")
# 4-9. 关节坐标 J1 到 J6
self.j_spins = []
for _ in range(6):
spin = DoubleSpinBox()
spin.setRange(-180, 180) # 角度范围 (-180度到180度)
spin.setDecimals(3) # 保留3位小数
spin.setSingleStep(0.001) # 默认步长
self.j_spins.append(spin)
# 关节坐标默认值 (默认为无效值)
self.j_spins[0].setValue(-9999)
self.j_spins[1].setValue(-9999)
self.j_spins[2].setValue(-9999)
self.j_spins[3].setValue(-9999)
self.j_spins[4].setValue(-9999)
self.j_spins[5].setValue(-9999)
# 关节坐标设置 右侧的步长设置 和 获取关节坐标按钮
self.step_group = QGroupBox("单击步长设置")
self.step_input = DoubleSpinBox()
self.step_input.setRange(0.001, 180.0) # 步长范围
self.step_input.setDecimals(3) # 保留3位小数
self.step_input.setValue(0.001) # 默认步长
self.get_values_btn = PushButton("获取当前J1-J6值")
# 10. 速度 (移动速度)
self.approach_speed_spin = DoubleSpinBox()
self.approach_speed_spin.setRange(0, 100)
self.approach_speed_spin.setDecimals(0) # 小数点
self.approach_speed_spin.setValue(20)
self.approach_speed_spin.setSingleStep(10)
# 11. 运动类型(下拉选择)
self.motion_type_combo = ComboBox()
self.motion_type_combo.addItems(["直线", "曲线中间点", "曲线终点", "自由路径"])
# 12. 平滑选择
self.stop_radio = RadioButton("停止")
self.smooth_radio = RadioButton("平滑过渡")
self.smooth_ms_spin = DoubleSpinBox() # 平滑过渡的时间(毫秒)
self.smooth_ms_spin.setRange(0, 500) # 范围0 - 500 ms
self.smooth_ms_spin.setDecimals(0) # 整数毫秒
self.smooth_ms_spin.setValue(0) # 默认值0
self.smooth_ms_spin.setSingleStep(10) # 步长10毫秒
self.smooth_ms_spin.setEnabled(False) # 初始禁用(仅“平滑过渡”选中时启用)
self.stop_radio.setChecked(True) # 默认选“停止”
# 13. 应用按钮
self.apply_btn = PushButton("应用")
self.apply_btn.setMinimumWidth(160) # 按钮最小宽度
def __initStyles(self):
# 根据主题设置样式表
if isDarkTheme(): # 深色主题
self.step_group.setStyleSheet(
"""
QGroupBox {
color: white; /* 标题文字颜色 */
border: 1px solid white; /* 边框线条颜色和宽度 */
border-radius: 6px; /* 边框圆角 */
margin-top: 10px; /* 标题与边框的距离 */
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left; /* 标题位置 */
left: 10px; /* 标题左边距 */
padding: 0 3px 0 3px; /* 标题内边距 */
}
"""
)
self.setStyleSheet("background-color: rgb(32, 32, 32);")
else: # 浅色主题
self.step_group.setStyleSheet(
"""
QGroupBox {
color: black; /* 标题文字颜色 */
border: 1px solid black; /* 边框线条颜色和宽度 */
border-radius: 6px; /* 边框圆角 */
margin-top: 10px; /* 标题与边框的距离 */
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left; /* 标题位置 */
left: 10px; /* 标题左边距 */
padding: 0 3px 0 3px; /* 标题内边距 */
}
"""
)
self.setStyleSheet("background-color: rgb(243, 243, 243);")
def __initLayout(self):
# 主布局直接应用于当前Widget
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(24, 24, 24, 24) # 边距
main_layout.setSpacing(16) # 控件间距
# 表单布局(管理标签和输入框)
form_layout = QFormLayout()
form_layout.setRowWrapPolicy(QFormLayout.DontWrapRows) # 不自动换行
# 标签右对齐+垂直居中
form_layout.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter)
form_layout.setSpacing(12) # 表单行间距
# 1. 添加点位名称布局
form_layout.addRow(StrongBodyLabel("点位名称"), self.name_combo)
# 2. 添加工具坐标布局
tool_coord_layout = QHBoxLayout()
tool_coord_layout.addWidget(self.tool_coord_spin)
tool_coord_layout.addWidget(self.tool_coord_btn)
form_layout.addRow(StrongBodyLabel("工具坐标id"), tool_coord_layout)
# 3. 添加工件坐标布局
work_coord_layout = QHBoxLayout() # 工件坐标水平布局
work_coord_layout.addWidget(self.work_coord_spin)
work_coord_layout.addWidget(self.work_coord_btn)
form_layout.addRow(StrongBodyLabel("工件坐标id"), work_coord_layout)
# 4-9 关节坐标布局
joint_control_layout = QHBoxLayout()
# 左侧关节角输入J1-J6
joint_input_layout = QFormLayout()
joint_input_layout.setRowWrapPolicy(QFormLayout.DontWrapRows)
joint_input_layout.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter)
joint_input_layout.setSpacing(12)
for index in range(6):
joint_input_layout.addRow(
StrongBodyLabel(f"J{index + 1} (°)"), self.j_spins[index]
)
# 将关节坐标输入布局 添加到 关节坐标布局
joint_control_layout.addLayout(joint_input_layout)
# 右侧:步长设置和获取按钮
control_panel_layout = QVBoxLayout()
control_panel_layout.setSpacing(16)
step_layout = QVBoxLayout(self.step_group)
step_layout.setContentsMargins(10, 15, 10, 15)
step_layout.setSpacing(10)
step_layout.addWidget(self.step_input)
# step_layout添加到控制面板布局
control_panel_layout.addWidget(self.step_group)
control_panel_layout.addWidget(self.get_values_btn)
control_panel_layout.addStretch() # 拉伸项,使内容靠上
# 将 控制面板布局(右侧) 添加到 关节控制布局
joint_control_layout.addLayout(control_panel_layout)
# 将关节控制水平布局添加到表单布局
form_layout.addRow(StrongBodyLabel("关节坐标"), joint_control_layout)
# 10. 速度布局
form_layout.addRow(StrongBodyLabel("速度 (%)"), self.approach_speed_spin)
# 11. 运动类型(下拉选择)布局
form_layout.addRow(StrongBodyLabel("运动类型"), self.motion_type_combo)
# 12. "在此点" 平滑选择布局
stop_layout = QHBoxLayout()
stop_layout.addWidget(self.stop_radio)
stop_layout.addWidget(self.smooth_radio)
stop_layout.addWidget(self.smooth_ms_spin)
stop_layout.addWidget(StrongBodyLabel("ms"))
stop_layout.setAlignment(Qt.AlignLeft) # 与标签左对齐
form_layout.addRow(StrongBodyLabel("在此点"), stop_layout)
# 将表单布局添加到主布局
main_layout.addLayout(form_layout)
# 13. 底部按钮布局(居中显示)
btn_layout = QHBoxLayout()
btn_layout.setAlignment(Qt.AlignHCenter) # 水平居中
btn_layout.addWidget(self.apply_btn)
# 将底部按钮布局添加到主布局
main_layout.addLayout(btn_layout)
# 让表单控件顶部对齐
main_layout.addStretch(1)
def __bind(self):
# 更新 J1 到 J6 的步长
self.step_input.valueChanged.connect(self.onUpdateStepSize)
# 获取 J1 到 J6 的值(外部相关)
self.get_values_btn.clicked.connect(self.onGetJointValues)
# 调整平滑时间设置控件可不可用
self.stop_radio.toggled.connect(
lambda checked: self.smooth_ms_spin.setEnabled(not checked)
)
self.smooth_radio.toggled.connect(
lambda checked: self.smooth_ms_spin.setEnabled(checked)
)
# 应用按钮点击 (外部相关)
self.apply_btn.clicked.connect(self.onApplyBtnClicked)
# 设置状态编辑框中的 点位的状态
def setPointStateValue(self, pos_state_dict: dict):
# 设置除了点位名字之外的所有 点位状态的值
self.approach_speed_spin.setValue(pos_state_dict["speed"])
self.tool_coord_spin.setValue(pos_state_dict["tool_id"])
self.work_coord_spin.setValue(pos_state_dict["work_id"])
for index in range(6):
self.j_spins[index].setValue(pos_state_dict["joint_values"][index])
# 运动状态设置
# 查找目标文本对应的索引
target_motion_type = pos_state_dict["motion_type"]
# 1. 查找目标文本对应的索引
motion_index = self.motion_type_combo.findText(target_motion_type)
# 2. 若未找到(索引=-1默认选中第0项否则选中对应索引
if motion_index == -1:
self.motion_type_combo.setCurrentIndex(0)
else:
self.motion_type_combo.setCurrentIndex(motion_index)
if pos_state_dict["blend_time"] == -1: # 此时为 停止
self.stop_radio.setChecked(True)
else:
self.smooth_radio.setChecked(True)
self.smooth_ms_spin.setValue(pos_state_dict["blend_time"])
def onUpdateStepSize(self, value):
"""更新所有关节角输入框的步长"""
for spin in self.j_spins:
spin.setSingleStep(value)
def onGetJointValues(self):
"""获取J1-J6的值这里用示例值模拟"""
# 实际应用中,这里应该从设备或其他数据源获取值
# 这里用随机值模拟
import random
for i in range(6):
# 生成一个-180到180之间的随机数保留3位小数
value = round(random.uniform(-180, 180), 3)
self.j_spins[i].setValue(value)
print("已获取并更新J1-J6的值")
def onApplyBtnClicked(self):
"""应用按钮点击事件处理"""
# 1、获取点名称
pos_name = self.name_combo.text()
# 2、速度
speed = self.approach_speed_spin.value()
# 3、tool_id
tool_id = self.tool_coord_spin.value()
# 4、work_id
work_id = self.work_coord_spin.value()
# 5-10、所有关节坐标 J1 到 J6
joint_values = [spin.value() for spin in self.j_spins]
# 11、运动类型 (直线、 曲线中间点、 曲线终点、 自由路径)
motion_type = self.motion_type_combo.currentText()
# 12、平滑时间停止=-1否则取输入值
blend_time = -1 if self.stop_radio.isChecked() else self.smooth_ms_spin.value()
try:
point_state = PointState(
pos_name=pos_name,
speed=speed,
tool_id=tool_id,
work_id=work_id,
joint_values=joint_values,
motion_type=motion_type,
blend_time=blend_time,
)
# print("状态编辑结果:", point_state.__str__())
# 发送信号给 表单窗口 CoordinateTableWidget对象
self.point_state_applied.emit(self.selected_row_idx, point_state)
# 关闭状态编辑窗口
self.close()
except ValueError as e:
# 捕获校验错误,弹窗提示用户
MessageBox("状态错误", str(e), self).exec()
# if __name__ == "__main__":
# app = QApplication([])
# setTheme(Theme.DARK) # 设置浅色主题可选Theme.DARK
# widget = StatusEditWidget()
# widget.show() # 显示窗口
# app.exec()