Files
wire_controlsystem/UI/test.py
2026-01-07 18:11:27 +08:00

560 lines
22 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2025/12/8 14:19
# @Author : reenrr
# @File : ui.py
# @Description: 线条长度标记与电机位置控制系统主界面--测试修改代码
'''
import sys
import time
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QLabel, QPushButton,
QGroupBox, QMessageBox, QComboBox, QTextEdit,
QTableWidget, QTableWidgetItem)
from PySide6.QtCore import QTimer, Qt, Signal, Slot
from PySide6.QtGui import (QFont, QPalette, QColor)
from ui_3d import Target3DWidgetA, Target3DWidgetB
class LengthMotorController(QMainWindow):
"""线条长度标记与电机位置控制系统主界面"""
update_time_signal = Signal(str)
record_data_signal = Signal(float, float, float, float)
line_select_signal = Signal(str, float, float, float, float)
def __init__(self):
super().__init__()
self.setWindowTitle("线条长度标记与电机位置控制系统")
self.setMinimumSize(1200, 700)
self.font1 = QFont("Microsoft YaHei", 14)
self.font2 = QFont("Microsoft YaHei", 12)
self.recorded_data = []
# 线条A参数
self.line_a_params = {
"类型1": (0.5, 5, 0.1, 25),
"类型2": (1.0, 10, 0.2, 30),
"类型3": (1.2, 8, 0.15, 28),
"类型4": (1.8, 12, 0.25, 32),
"类型5": (0.8, 7, 0.12, 26),
"类型6": (1.4, 14, 0.18, 31),
"类型7": (1.6, 16, 0.22, 33),
"类型8": (2.0, 18, 0.28, 34)
}
# 线条B参数
self.line_b_params = {
"类型1": (1.5, 15, 0.3, 35),
"类型2": (2.0, 20, 0.4, 40),
"类型3": (1.6, 18, 0.35, 38),
"类型4": (2.2, 22, 0.45, 42),
"类型5": (1.7, 25, 0.32, 36),
"类型6": (1.9, 28, 0.38, 39),
"类型7": (2.1, 30, 0.42, 41),
"类型8": (2.3, 32, 0.48, 43)
}
# 当前选中的线条类型
self.selected_line_a = "类型1"
self.selected_line_b = "类型1"
self._setup_style()
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
main_layout.setSpacing(20)
main_layout.setContentsMargins(30, 30, 30, 30)
# 1. 顶部标题(替代原实时时间)
self._create_title(main_layout)
# 2. 下方左右分栏:左侧线条选择区,右侧(实时时间 + 参数 + 3D
bottom_h_layout = QHBoxLayout()
bottom_h_layout.setSpacing(20)
# 左侧:线条选择区(表格)
self._create_line_select_table(bottom_h_layout)
# 右侧:实时时间 + 参数设置 + 3D显示区
self._create_right_area(bottom_h_layout)
main_layout.addLayout(bottom_h_layout)
self._init_timer()
self._connect_signals()
def _setup_style(self):
"""设置界面样式"""
palette = QPalette()
palette.setColor(QPalette.Window, QColor(245, 245, 247))
palette.setColor(QPalette.WindowText, QColor(30, 30, 30))
palette.setColor(QPalette.Button, QColor(66, 133, 244))
palette.setColor(QPalette.ButtonText, Qt.white)
self.setPalette(palette)
self.setStyleSheet("""
QGroupBox {
font-weight: bold;
border: 2px solid #4285F4;
border-radius: 8px;
margin-top: 10px;
padding-top: 10px;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 8px 0 8px;
}
QPushButton {
border-radius: 6px;
padding: 8px 16px;
font-size: 12pt;
}
QPushButton:hover {
background-color: #5294FF;
}
QComboBox {
border: 2px solid #DDDDDD;
border-radius: 6px;
padding: 8px;
font-size: 10pt;
}
QComboBox:focus {
border-color: #4285F4;
outline: none;
}
QTextEdit {
border: 2px solid #DDDDDD;
border-radius: 6px;
background-color: white;
font-size: 11pt;
}
QTableWidget {
border: 2px solid #DDDDDD;
border-radius: 6px;
font-size: 11pt;
}
QTableWidget::item:selected {
background-color: #E1F5FE;
color: #212121;
}
""")
def _create_title(self, parent_layout):
"""顶部标题(替代原实时时间)"""
title_label = QLabel("线条长度标记与电机位置控制系统")
title_label.setFont(QFont("Microsoft YaHei", 20, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
parent_layout.addWidget(title_label)
def _create_line_select_table(self, parent_layout):
"""左侧线条选择区(表格)"""
line_select_group = QGroupBox("线条选择(参数预览)")
line_select_group.setFont(self.font1)
line_select_group.setMinimumWidth(self.width() * 0.5)
select_layout = QVBoxLayout(line_select_group)
select_layout.setSpacing(20)
select_layout.setContentsMargins(20, 20, 20, 20)
# 线条A表格
a_label = QLabel("线条A参数表")
a_label.setFont(self.font2)
self.table_line_a = QTableWidget()
self.table_line_a.setRowCount(len(self.line_a_params))
self.table_line_a.setColumnCount(5)
self.table_line_a.setHorizontalHeaderLabels(["类型", "参数a", "参数b", "参数c", "参数d"])
for row, (type_name, params) in enumerate(self.line_a_params.items()):
self.table_line_a.setItem(row, 0, QTableWidgetItem(type_name))
self.table_line_a.setItem(row, 1, QTableWidgetItem(str(params[0])))
self.table_line_a.setItem(row, 2, QTableWidgetItem(str(params[1])))
self.table_line_a.setItem(row, 3, QTableWidgetItem(str(params[2])))
self.table_line_a.setItem(row, 4, QTableWidgetItem(str(params[3])))
self.table_line_a.setFixedHeight(280)
self.table_line_a.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_line_a.setSelectionBehavior(QTableWidget.SelectRows)
self.table_line_a.selectRow(0)
self.table_line_a.itemSelectionChanged.connect(self._on_line_a_select)
# 线条B表格
b_label = QLabel("线条B参数表")
b_label.setFont(self.font2)
self.table_line_b = QTableWidget()
self.table_line_b.setRowCount(len(self.line_b_params))
self.table_line_b.setColumnCount(5)
self.table_line_b.setHorizontalHeaderLabels(["类型", "参数a", "参数b", "参数c", "参数d"])
for row, (type_name, params) in enumerate(self.line_b_params.items()):
self.table_line_b.setItem(row, 0, QTableWidgetItem(type_name))
self.table_line_b.setItem(row, 1, QTableWidgetItem(str(params[0])))
self.table_line_b.setItem(row, 2, QTableWidgetItem(str(params[1])))
self.table_line_b.setItem(row, 3, QTableWidgetItem(str(params[2])))
self.table_line_b.setItem(row, 4, QTableWidgetItem(str(params[3])))
self.table_line_b.setFixedHeight(260)
self.table_line_b.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_line_b.setSelectionBehavior(QTableWidget.SelectRows)
self.table_line_b.selectRow(0)
self.table_line_b.itemSelectionChanged.connect(self._on_line_b_select)
# 导入按钮
import_layout = QHBoxLayout()
import_a_btn = QPushButton("导入线条A选中参数")
import_a_btn.setFont(self.font2)
import_a_btn.clicked.connect(lambda: self._import_line_param("A"))
import_b_btn = QPushButton("导入线条B选中参数")
import_b_btn.setFont(self.font2)
import_b_btn.clicked.connect(lambda: self._import_line_param("B"))
import_layout.addWidget(import_a_btn)
import_layout.addWidget(import_b_btn)
select_layout.addWidget(a_label)
select_layout.addWidget(self.table_line_a)
select_layout.addWidget(b_label)
select_layout.addWidget(self.table_line_b)
select_layout.addLayout(import_layout)
select_layout.addStretch()
parent_layout.addWidget(line_select_group)
def _on_line_a_select(self):
"""线条A表格选中行变化"""
selected_rows = self.table_line_a.selectedItems()
if selected_rows:
# 获取选中行的第一列(类型列)文本
row = selected_rows[0].row()
self.selected_line_a = self.table_line_a.item(row, 0).text()
def _on_line_b_select(self):
"""线条B表格选中行变化"""
selected_rows = self.table_line_b.selectedItems()
if selected_rows:
row = selected_rows[0].row()
self.selected_line_b = self.table_line_b.item(row, 0).text()
def _create_right_area(self, parent_layout):
"""右侧区域:实时时间 → 线条类型设置 → 3D显示"""
right_v_layout = QVBoxLayout()
right_v_layout.setSpacing(20)
# 1. 实时时间(移到右侧顶部)
time_group = QGroupBox("实时时间")
time_group.setFont(self.font1)
time_layout = QHBoxLayout(time_group)
self.time_label = QLabel()
self.time_label.setAlignment(Qt.AlignCenter)
self.time_label.setFont(QFont("Microsoft YaHei", 14, QFont.Bold))
time_layout.addWidget(self.time_label)
right_v_layout.addWidget(time_group)
# 2. 线条类型设置区
control_group = QGroupBox("线条类型设置")
control_group.setFont(self.font1)
control_layout = QVBoxLayout(control_group)
control_layout.setSpacing(15)
control_layout.setContentsMargins(20, 20, 20, 20)
# 提取所有参数a/b/c/d的可能值
# 收集参数a的所有值
# 提取所有参数a/b/c/d的可能值统一格式
# 收集参数a的所有值保留2位小数去除末尾0
param_a_list = []
for params in self.line_a_params.values():
a = params[0]
a_str = f"{a:.2f}".rstrip('0').rstrip('.') if '.' in f"{a:.2f}" else f"{a:.2f}"
param_a_list.append(a_str)
for params in self.line_b_params.values():
a = params[0]
a_str = f"{a:.2f}".rstrip('0').rstrip('.') if '.' in f"{a:.2f}" else f"{a:.2f}"
param_a_list.append(a_str)
param_a_list = sorted(list(set(param_a_list)), key=lambda x: float(x))
# 收集参数b的所有值整数格式
param_b_list = []
for params in self.line_a_params.values():
b_str = f"{params[1]:.0f}"
param_b_list.append(b_str)
for params in self.line_b_params.values():
b_str = f"{params[1]:.0f}"
param_b_list.append(b_str)
param_b_list = sorted(list(set(param_b_list)), key=lambda x: int(x))
# 收集参数c的所有值保留2位小数去除末尾0
param_c_list = []
for params in self.line_a_params.values():
c = params[2]
c_str = f"{c:.2f}".rstrip('0').rstrip('.') if '.' in f"{c:.2f}" else f"{c:.2f}"
param_c_list.append(c_str)
for params in self.line_b_params.values():
c = params[2]
c_str = f"{c:.2f}".rstrip('0').rstrip('.') if '.' in f"{c:.2f}" else f"{c:.2f}"
param_c_list.append(c_str)
param_c_list = sorted(list(set(param_c_list)), key=lambda x: float(x))
# 收集参数d的所有值整数格式
param_d_list = []
for params in self.line_a_params.values():
d_str = f"{params[3]:.0f}"
param_d_list.append(d_str)
for params in self.line_b_params.values():
d_str = f"{params[3]:.0f}"
param_d_list.append(d_str)
param_d_list = sorted(list(set(param_d_list)), key=lambda x: int(x))
# 4个参数下拉框
param_layout = QHBoxLayout()
param_layout.setSpacing(20)
# 参数a
a_param_layout = QVBoxLayout()
label_a = QLabel("参数a:")
label_a.setFont(self.font2)
label_a.setAlignment(Qt.AlignCenter)
self.combo_a = QComboBox()
self.combo_a.addItems(param_a_list)
self.combo_a.setFixedWidth(100)
self.combo_a.setFont(self.font2)
a_param_layout.addWidget(label_a)
a_param_layout.addWidget(self.combo_a)
param_layout.addLayout(a_param_layout)
# 参数b
b_param_layout = QVBoxLayout()
label_b = QLabel("参数b:")
label_b.setFont(self.font2)
label_b.setAlignment(Qt.AlignCenter)
self.combo_b = QComboBox()
self.combo_b.addItems(param_b_list)
self.combo_b.setFixedWidth(100)
self.combo_b.setFont(self.font2)
b_param_layout.addWidget(label_b)
b_param_layout.addWidget(self.combo_b)
param_layout.addLayout(b_param_layout)
# 参数c
c_param_layout = QVBoxLayout()
label_c = QLabel("参数c:")
label_c.setFont(self.font2)
label_c.setAlignment(Qt.AlignCenter)
self.combo_c = QComboBox()
self.combo_c.addItems(param_c_list)
self.combo_c.setFixedWidth(100)
self.combo_c.setFont(self.font2)
c_param_layout.addWidget(label_c)
c_param_layout.addWidget(self.combo_c)
param_layout.addLayout(c_param_layout)
# 参数d
d_param_layout = QVBoxLayout()
label_d = QLabel("参数d:")
label_d.setFont(self.font2)
label_d.setAlignment(Qt.AlignCenter)
self.combo_d = QComboBox()
self.combo_d.addItems(param_d_list)
self.combo_d.setFixedWidth(100)
self.combo_d.setFont(self.font2)
d_param_layout.addWidget(label_d)
d_param_layout.addWidget(self.combo_d)
param_layout.addLayout(d_param_layout)
# 按钮行
button_layout = QHBoxLayout()
self.save_btn = QPushButton("保存设置")
self.save_btn.setFont(self.font2)
self.save_btn.setFixedSize(140, 45)
self.clear_btn = QPushButton("清空选择")
self.clear_btn.setFont(self.font2)
self.clear_btn.setFixedSize(140, 45)
self.export_btn = QPushButton("导出记录")
self.export_btn.setFont(self.font2)
self.export_btn.setFixedSize(140, 45)
button_layout.addStretch()
button_layout.addWidget(self.save_btn)
button_layout.addWidget(self.clear_btn)
button_layout.addWidget(self.export_btn)
button_layout.addStretch()
control_layout.addLayout(param_layout)
control_layout.addLayout(button_layout)
right_v_layout.addWidget(control_group)
# 3. 3D效果显示占位区
self._create_3d_placeholder(right_v_layout)
parent_layout.addLayout(right_v_layout)
def _create_3d_placeholder(self, parent_layout):
"""3D效果显示占位区缩小留白"""
display_group = QGroupBox("线条3D效果显示")
display_group.setFont(self.font1)
display_layout = QVBoxLayout(display_group)
display_layout.setContentsMargins(20, 20, 20, 20)
# 实例化ui_3d.py中的Target3DWidget
self.ui_3d_widget = Target3DWidgetA() # 创建3D绘图控件实例
self.ui_3d_widget.setMaximumSize(500, 330)
test_btn = QPushButton("测试参数传递")
test_btn.setFont(self.font2)
test_btn.setFixedWidth(150)
test_btn.clicked.connect(self._test_3d_param_pass)
display_layout.addWidget(self.ui_3d_widget)
display_layout.addWidget(test_btn, alignment=Qt.AlignCenter)
parent_layout.addWidget(display_group)
def _init_timer(self):
"""初始化定时器"""
self.timer = QTimer(self)
self.timer.timeout.connect(self._update_current_time)
self.timer.start(1000)
self._update_current_time()
def _connect_signals(self):
"""连接信号与槽函数"""
self.save_btn.clicked.connect(self._save_settings)
self.clear_btn.clicked.connect(self._clear_inputs)
self.export_btn.clicked.connect(self._export_records)
self.update_time_signal.connect(self.time_label.setText)
self.record_data_signal.connect(self._log_param_change)
self.line_select_signal.connect(self._set_line_params)
def _update_current_time(self):
"""更新当前时间"""
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.update_time_signal.emit(current_time)
@Slot(str)
def _import_line_param(self, line_type):
"""导入选中线条的参数"""
if line_type == "A":
selected_type = self.selected_line_a
params = self.line_a_params[selected_type]
line_name = f"线条A-{selected_type}"
else:
selected_type = self.selected_line_b
params = self.line_b_params[selected_type]
line_name = f"线条B-{selected_type}"
self.line_select_signal.emit(line_name, *params)
QMessageBox.information(self, "导入成功", f"已导入{line_name}的参数")
@Slot(str, float, float, float, float)
def _set_line_params(self, line_name, a, b, c, d):
"""设置参数到下拉框(统一浮点数格式)"""
# 根据参数特性设置小数位a/c保留2位b/d保留0位整数
a_str = f"{a:.2f}".rstrip('0').rstrip('.') if '.' in f"{a:.2f}" else f"{a:.2f}"
b_str = f"{b:.0f}" # 参数b是整数5/7/8等
c_str = f"{c:.2f}".rstrip('0').rstrip('.') if '.' in f"{c:.2f}" else f"{c:.2f}"
d_str = f"{d:.0f}" # 参数d是整数25/26/28等
"""设置参数到下拉框"""
self.combo_a.setCurrentText(str(a))
self.combo_b.setCurrentText(str(b))
self.combo_c.setCurrentText(str(c))
self.combo_d.setCurrentText(str(d))
@Slot()
def _save_settings(self):
"""保存参数并触发信号"""
try:
param_a = float(self.combo_a.currentText())
param_b = float(self.combo_b.currentText())
param_c = float(self.combo_c.currentText())
param_d = float(self.combo_d.currentText())
except ValueError:
QMessageBox.critical(self, "输入错误", "参数格式无效!")
return
if param_a <= 0 or param_b <= 0 or param_c < 0 or param_d < 0:
QMessageBox.warning(self, "参数错误", "参数a/b必须大于0c/d不能小于0")
return
self.record_data_signal.emit(param_a, param_b, param_c, param_d)
QMessageBox.information(self, "保存成功",
f"已保存设置:\n参数a{param_a}\n参数b{param_b}\n参数c{param_c}\n参数d{param_d}")
@Slot(float, float, float, float)
def _log_param_change(self, a, b, c, d):
"""记录参数变化"""
self.recorded_data.append({
"a": a, "b": b, "c": c, "d": d,
"time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
})
@Slot()
def _test_3d_param_pass(self):
"""测试参数传递"""
try:
param_a = float(self.combo_a.currentText())
param_b = float(self.combo_b.currentText())
param_c = float(self.combo_c.currentText())
param_d = float(self.combo_d.currentText())
except ValueError:
QMessageBox.critical(self, "测试失败", "当前参数格式无效!")
return
QMessageBox.information(
self, "参数传递测试成功",
f"当前参数已准备好传递给3D模块\n"
f"参数a半径{param_a}\n"
f"参数b长度{param_b}\n"
f"参数c颜色通道1{param_c}\n"
f"参数d颜色通道2{param_d}"
)
@Slot()
def _clear_inputs(self):
"""清空所有选择"""
self.combo_a.setCurrentIndex(0)
self.combo_b.setCurrentIndex(0)
self.combo_c.setCurrentIndex(0)
self.combo_d.setCurrentIndex(0)
self.table_line_a.selectRow(0)
self.table_line_b.selectRow(0)
@Slot()
def _export_records(self):
"""导出参数记录"""
if not self.recorded_data:
QMessageBox.warning(self, "导出提示", "暂无记录可导出!")
return
try:
filename = f"线条参数记录_{time.strftime('%Y%m%d_%H%M%S')}.txt"
with open(filename, 'w', encoding='utf-8') as f:
f.write("线条参数记录\n")
f.write("=" * 60 + "\n")
f.write(f"导出时间:{time.strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write("参数a\t参数b\t参数c\t参数d\t记录时间\n")
f.write("-" * 60 + "\n")
for data in self.recorded_data:
f.write(f"{data['a']:.2f}\t{data['b']:.2f}\t{data['c']:.2f}\t{data['d']:.2f}\t{data['time']}\n")
QMessageBox.information(self, "导出成功", f"记录已导出到:\n{filename}")
except Exception as e:
QMessageBox.critical(self, "导出失败", f"导出文件时出错:{str(e)}")
def closeEvent(self, event):
"""关闭窗口确认"""
reply = QMessageBox.question(self, "确认退出",
"是否确定退出程序?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
self.timer.stop()
event.accept()
else:
event.ignore()
# ----------界面对外接口-----------
def ui_main():
app = QApplication(sys.argv)
app.setApplicationName("长度电机控制器")
app.setApplicationVersion("1.0.0")
window = LengthMotorController()
window.show()
sys.exit(app.exec())
# ----------测试接口--------------
if __name__ == "__main__":
ui_main()