All pastes #4QGQdn3SfJ Raw Edit

text paste

public text v1 · immutable
#4QGQdn3SfJ ·published 2026-08-17 09:34 UTC ·by SFXYY
rendered paste body
#include "view_configGenerator.h"#include <QCheckBox>#include <QComboBox>#include <QFileDialog>#include <QFormLayout>#include <QGroupBox>#include <QHeaderView>#include <QLabel>#include <QLineEdit>#include <QMessageBox>#include <QPushButton>#include <QSpinBox>#include <QTableWidget>#include <QListWidget>#include <QTabWidget>#include <QJsonDocument>#include <QFile>#include "e3d_configManager_equipment.h"view_configGenerator::view_configGenerator(QWidget *parent)	: QWidget(parent), currentData(new data_equipment)	, ui(new Ui::e3d_configGenaraterClass()){	ui->setupUi(this);	if (this->layout()) {		delete this->layout();	}	initUI();}view_configGenerator::~view_configGenerator(){	delete currentData;	delete ui;}void view_configGenerator::initUI() {	auto *mainLayout = new QVBoxLayout(this);	// 1. 顶部文件操作栏	auto *gb_file = new QGroupBox(tr("Config File Operations"), this);	auto *hl_file = new QHBoxLayout(gb_file);	le_configPath = new QLineEdit(gb_file);	pb_loadConfig = new QPushButton(tr("Load Config File"), gb_file);	pb_saveConfigToFile = new QPushButton(tr("Save Config to File"), gb_file);	pb_saveConfigToTemp = new QPushButton(tr("Save to Memory"), gb_file);	hl_file->addWidget(le_configPath);	hl_file->addWidget(pb_loadConfig);	hl_file->addWidget(pb_saveConfigToFile);	hl_file->addWidget(pb_saveConfigToTemp);	mainLayout->addWidget(gb_file);	// 2. Tab 页面容器	auto *tabWidget = new QTabWidget(this);	tabWidget->addTab(createMotionControllerTab(), tr("Motion Controllers & I/O / Axes"));	tabWidget->addTab(createCommsTab(), tr("Comms Config"));	tabWidget->addTab(createHeightSensorTab(), tr("Height Sensor Config"));	tabWidget->addTab(createDispenserTab(), tr("Dispenser Config"));	tabWidget->addTab(createExternalDeviceTab(), tr("Global External Devices"));	tabWidget->addTab(createToolheadTab(), tr("Toolhead Config"));	tabWidget->addTab(createCommonTab(), tr("Common Config"));	mainLayout->addWidget(tabWidget);	// 3. 信号槽绑定	connect(pb_loadConfig, &QPushButton::clicked, this, &view_configGenerator::onLoadConfigFromFile);	connect(pb_saveConfigToFile, &QPushButton::clicked, this, &view_configGenerator::onSaveConfigToFile);	connect(pb_saveConfigToTemp, &QPushButton::clicked, this, &view_configGenerator::onSaveTempClicked);	// 初始化右侧面板状态(为空时不可编辑)	updateControllerRightPanel();	updateToolheadRightPanel();}void view_configGenerator::updateTableRows(QTableWidget *table, int targetCount) {	int current = table->rowCount();	if (targetCount > current) {		for (int i = current; i < targetCount; ++i) {			table->insertRow(i);		}	}	else if (targetCount < current) {		for (int i = current - 1; i >= targetCount; --i) {			table->removeRow(i);		}	}}// ============================================================================// 1. 控制卡 Master-Detail 页面构建// ============================================================================QWidget* view_configGenerator::createMotionControllerTab() {	auto *widget = new QWidget();	auto *mainLayout = new QHBoxLayout(widget);	auto *leftGroup = new QGroupBox(tr("Controller List"), widget);	auto *leftLayout = new QVBoxLayout(leftGroup);	m_cardListWidget = new QListWidget(leftGroup);	auto *btnLayout = new QHBoxLayout();	auto *btnAddCard = new QPushButton(tr("Add Card"), leftGroup);	auto *btnDelCard = new QPushButton(tr("Delete Card"), leftGroup);	btnLayout->addWidget(btnAddCard);	btnLayout->addWidget(btnDelCard);	leftLayout->addWidget(m_cardListWidget);	leftLayout->addLayout(btnLayout);	// 使用成员变量管理右侧面板 GroupBox	m_controllerRightGroup = new QGroupBox(tr("Controller Properties & Sub-Devices"), widget);	auto *rightLayout = new QVBoxLayout(m_controllerRightGroup);	auto *formLayout = new QFormLayout();	m_editCardName = new QLineEdit();	m_comboBrand = new QComboBox();	m_comboBrand->addItem("ZMOTION","ZMOTION");	m_comboBrand->addItem("ACS","ACS");	m_editIP = new QLineEdit("127.0.0.1");	m_spinPort = new QSpinBox();	m_spinPort->setRange(1, 65535);	m_spinPort->setValue(8080);	m_editAllAxisHomePath = new QLineEdit("AllAxisHomePath");	m_showSub = new QCheckBox();	formLayout->addRow(tr("Controller Name (userName):"), m_editCardName);	formLayout->addRow(tr("Brand:"), m_comboBrand);	formLayout->addRow(tr("IP Address:"), m_editIP);	formLayout->addRow(tr("Port:"), m_spinPort);	formLayout->addRow(tr("AllAxisHomePath:"), m_editAllAxisHomePath);	formLayout->addRow(tr("showSub:"), m_showSub);	rightLayout->addLayout(formLayout);	m_subConfigTab = new QTabWidget(m_controllerRightGroup);	auto *axisTabWidget = new QWidget();	auto *axisLayout = new QVBoxLayout(axisTabWidget);	m_axisTable = new QTableWidget(0, 9);	m_axisTable->setSelectionBehavior(QAbstractItemView::SelectRows);	m_axisTable->setSelectionMode(QAbstractItemView::SingleSelection);	m_axisTable->setHorizontalHeaderLabels({		tr("Axis Name (userName)"), tr("Axis No"), tr("Left Limit"), tr("Right Limit"),		tr("Acc"), tr("Dec"), tr("Fast Dec"), tr("Enable Left Limit"), tr("Enable Right Limit")		});	m_axisTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);	auto *axisBtnLayout = new QHBoxLayout();	auto *btnAddAxis = new QPushButton(tr("Add Axis"));	auto *btnDelAxis = new QPushButton(tr("Delete Axis"));	axisBtnLayout->addWidget(btnAddAxis);	axisBtnLayout->addWidget(btnDelAxis);	axisBtnLayout->addStretch();	axisLayout->addLayout(axisBtnLayout);	axisLayout->addWidget(m_axisTable);	m_subConfigTab->addTab(axisTabWidget, tr("Axes (AxisInfo)"));	auto createIOTab = [this](QTableWidget*& table, const QString& title, bool isDigital) {		auto *w = new QWidget();		auto *ly = new QVBoxLayout(w);		table = new QTableWidget(0, isDigital ? 3 : 2);		table->setSelectionBehavior(QAbstractItemView::SelectRows);		table->setSelectionMode(QAbstractItemView::SingleSelection);		if (isDigital) {			table->setHorizontalHeaderLabels({ tr("IO Name (userName)"), tr("Main IO (Port)"), tr("Sub IO (Pin)") });		}		else {			table->setHorizontalHeaderLabels({ tr("IO Name (userName)"), tr("Address") });		}		table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);		auto *bLy = new QHBoxLayout();		auto *bAdd = new QPushButton(tr("Add IO"));		auto *bDel = new QPushButton(tr("Delete IO"));		bLy->addWidget(bAdd); bLy->addWidget(bDel); bLy->addStretch();		ly->addLayout(bLy); ly->addWidget(table);		connect(bAdd, &QPushButton::clicked, this, [this, table]() { onAddIO(table); });		connect(bDel, &QPushButton::clicked, this, [this, table]() { onDeleteIO(table); });		m_subConfigTab->addTab(w, title);	};	createIOTab(m_dinTable, tr("Digital Input (DIN)"), true);	createIOTab(m_doutTable, tr("Digital Output (DOUT)"), true);	createIOTab(m_ainTable, tr("Analog Input (AIN)"), false);	createIOTab(m_aoutTable, tr("Analog Output (AOUT)"), false);	rightLayout->addWidget(m_subConfigTab);	mainLayout->addWidget(leftGroup, 1);	mainLayout->addWidget(m_controllerRightGroup, 3);	connect(btnAddCard, &QPushButton::clicked, this, &view_configGenerator::onAddController);	connect(btnDelCard, &QPushButton::clicked, this, &view_configGenerator::onDeleteController);	connect(m_cardListWidget, &QListWidget::currentRowChanged, this, &view_configGenerator::onControllerSelected);	connect(btnAddAxis, &QPushButton::clicked, this, &view_configGenerator::onAddAxis);	connect(btnDelAxis, &QPushButton::clicked, this, &view_configGenerator::onDeleteAxis);	return widget;}// ============================================================================// 2. 通讯模块页构建 (Comms Config)// ============================================================================QWidget* view_configGenerator::createCommsTab() {	auto *widget = new QWidget();	auto *layout = new QVBoxLayout(widget);	auto *hl_comms = new QHBoxLayout();	auto *btnAdd = new QPushButton(tr("Add Comms Module"), widget);	auto *btnDel = new QPushButton(tr("Delete Selected"), widget);	hl_comms->addWidget(btnAdd);	hl_comms->addWidget(btnDel);	hl_comms->addSpacing(20);	hl_comms->addWidget(new QLabel(tr("Comms Module Count:")));	sb_count_Comms = new QSpinBox();	sb_count_Comms->setRange(0, 50);	hl_comms->addWidget(sb_count_Comms);	hl_comms->addStretch();	layout->addLayout(hl_comms);	tw_Comms = new QTableWidget(0, 12);	tw_Comms->setSelectionBehavior(QAbstractItemView::SelectRows);	tw_Comms->setSelectionMode(QAbstractItemView::SingleSelection);	tw_Comms->setHorizontalHeaderLabels({		tr("Comms Name"), tr("Type"), tr("Port Name"), tr("Baud Rate"),		tr("Parity"), tr("Data Bits"), tr("Stop Bits"), tr("IP Address"),		tr("TCP Port"), tr("Slave Addr"), tr("Timeout(ms)"), tr("Retry Times")		});	tw_Comms->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);	layout->addWidget(tw_Comms);	auto addCommsRow = [this](int r) {		tw_Comms->setItem(r, 0, new QTableWidgetItem(QString("Comms_%1").arg(r + 1)));		auto *cbType = new QComboBox();		cbType->addItems(toStringList<data_CommsConfig::CommsType>());		tw_Comms->setCellWidget(r, 1, cbType);		tw_Comms->setItem(r, 2, new QTableWidgetItem("COM1"));		tw_Comms->setItem(r, 3, new QTableWidgetItem("115200"));		tw_Comms->setItem(r, 4, new QTableWidgetItem("N"));		tw_Comms->setItem(r, 5, new QTableWidgetItem("8"));		tw_Comms->setItem(r, 6, new QTableWidgetItem("1"));		tw_Comms->setItem(r, 7, new QTableWidgetItem("192.168.1.100"));		tw_Comms->setItem(r, 8, new QTableWidgetItem("8080"));		tw_Comms->setItem(r, 9, new QTableWidgetItem("1"));		tw_Comms->setItem(r, 10, new QTableWidgetItem("1000"));		tw_Comms->setItem(r, 11, new QTableWidgetItem("2"));	};	connect(btnAdd, &QPushButton::clicked, [this, addCommsRow]() {		int r = tw_Comms->rowCount();		tw_Comms->insertRow(r);		addCommsRow(r);		sb_count_Comms->blockSignals(true);		sb_count_Comms->setValue(tw_Comms->rowCount());		sb_count_Comms->blockSignals(false);	});	connect(btnDel, &QPushButton::clicked, [this]() {		int r = tw_Comms->currentRow();		if (r >= 0) {			tw_Comms->removeRow(r);			sb_count_Comms->blockSignals(true);			sb_count_Comms->setValue(tw_Comms->rowCount());			sb_count_Comms->blockSignals(false);		}	});	connect(sb_count_Comms, QOverload<int>::of(&QSpinBox::valueChanged), [this, addCommsRow](int val) {		int oldRow = tw_Comms->rowCount();		updateTableRows(tw_Comms, val);		for (int i = oldRow; i < val; ++i) {			addCommsRow(i);		}	});	return widget;}// ============================================================================// 3. 测距传感器配置页构建 (Height Sensor Config) - 新增 m_commsChannelName 列// ============================================================================QWidget* view_configGenerator::createHeightSensorTab() {	auto *widget = new QWidget();	auto *layout = new QVBoxLayout(widget);	auto *hl = new QHBoxLayout();	auto *btnAdd = new QPushButton(tr("Add Height Sensor"), widget);	auto *btnDel = new QPushButton(tr("Delete Selected"), widget);	hl->addWidget(btnAdd);	hl->addWidget(btnDel);	hl->addSpacing(20);	hl->addWidget(new QLabel(tr("Height Sensor Count:")));	sb_count_HeightSensor = new QSpinBox();	sb_count_HeightSensor->setRange(0, 20);	hl->addWidget(sb_count_HeightSensor);	hl->addStretch();	layout->addLayout(hl);	tw_HeightSensor = new QTableWidget(0, 9);	tw_HeightSensor->setSelectionBehavior(QAbstractItemView::SelectRows);	tw_HeightSensor->setSelectionMode(QAbstractItemView::SingleSelection);	tw_HeightSensor->setHorizontalHeaderLabels({		tr("Sensor Name"),		tr("Comms Channel Name"),		tr("Comm Type"),		tr("MSR Addr (Hex/Dec)"),		tr("Status Addr (Hex/Dec)"),		tr("Same Dir with Axis"),		tr("Min Range"),		tr("Max Range"),		tr("Offset")		});	tw_HeightSensor->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);	layout->addWidget(tw_HeightSensor);	auto addSensorRow = [this](int r) {		tw_HeightSensor->setItem(r, 0, new QTableWidgetItem(QString("HeightSensor_%1").arg(r + 1)));		tw_HeightSensor->setItem(r, 1, new QTableWidgetItem("COM_Channel_1"));		auto *cbComm = new QComboBox();		cbComm->addItems(toStringList<data_HeightSensorConfig::HeightSensorType>());		tw_HeightSensor->setCellWidget(r, 2, cbComm);		tw_HeightSensor->setItem(r, 3, new QTableWidgetItem("0x6000"));		tw_HeightSensor->setItem(r, 4, new QTableWidgetItem("0x6001"));		auto *chk = new QCheckBox();		auto *pContainer = new QWidget();		auto *pLayout = new QHBoxLayout(pContainer);		pLayout->addWidget(chk);		pLayout->setAlignment(Qt::AlignCenter);		pLayout->setContentsMargins(0, 0, 0, 0);		tw_HeightSensor->setCellWidget(r, 5, pContainer);		tw_HeightSensor->setItem(r, 6, new QTableWidgetItem("0.0"));		tw_HeightSensor->setItem(r, 7, new QTableWidgetItem("100.0"));		tw_HeightSensor->setItem(r, 8, new QTableWidgetItem("0.0"));	};	connect(btnAdd, &QPushButton::clicked, [this, addSensorRow]() {		int r = tw_HeightSensor->rowCount();		tw_HeightSensor->insertRow(r);		addSensorRow(r);		sb_count_HeightSensor->blockSignals(true);		sb_count_HeightSensor->setValue(tw_HeightSensor->rowCount());		sb_count_HeightSensor->blockSignals(false);	});	connect(btnDel, &QPushButton::clicked, [this]() {		int r = tw_HeightSensor->currentRow();		if (r >= 0) {			tw_HeightSensor->removeRow(r);			sb_count_HeightSensor->blockSignals(true);			sb_count_HeightSensor->setValue(tw_HeightSensor->rowCount());			sb_count_HeightSensor->blockSignals(false);		}	});	connect(sb_count_HeightSensor, QOverload<int>::of(&QSpinBox::valueChanged), [this, addSensorRow](int val) {		int oldRow = tw_HeightSensor->rowCount();		updateTableRows(tw_HeightSensor, val);		for (int i = oldRow; i < val; ++i) {			addSensorRow(i);		}	});	return widget;}// ============================================================================// 4. 点胶机配置页构建 (Dispenser Config) - 新增 m_commsChannelName 列// ============================================================================QWidget* view_configGenerator::createDispenserTab() {	auto *widget = new QWidget();	auto *layout = new QVBoxLayout(widget);	auto *hl = new QHBoxLayout();	auto *btnAdd = new QPushButton(tr("Add Dispenser"), widget);	auto *btnDel = new QPushButton(tr("Delete Selected"), widget);	hl->addWidget(btnAdd);	hl->addWidget(btnDel);	hl->addSpacing(20);	hl->addWidget(new QLabel(tr("Dispenser Count:")));	sb_count_Dispenser = new QSpinBox();	sb_count_Dispenser->setRange(0, 20);	hl->addWidget(sb_count_Dispenser);	hl->addStretch();	layout->addLayout(hl);	tw_Dispenser = new QTableWidget(0, 17);	tw_Dispenser->setSelectionBehavior(QAbstractItemView::SelectRows);	tw_Dispenser->setSelectionMode(QAbstractItemView::SingleSelection);	tw_Dispenser->setHorizontalHeaderLabels({		tr("Dispenser Name"),		tr("Comms Channel/Controller Name"), tr("CommType"), tr("Port"), tr("BaudRate"), tr("Parity"), tr("DataBits"), tr("StopBits"),		tr("Analog Addr"), tr("Min Pressure"), tr("Max Pressure"),		tr("Default Pressure"), tr("Default Time(s)"), tr("Switch IO"), tr("Switch State"),		tr("MainIO OpenGas"), tr("SubIO OpenGas")		});	tw_Dispenser->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);	layout->addWidget(tw_Dispenser);	auto addDispenserRow = [this](int r) {		int i = 0;		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("Dispenser1"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("ZMOTION_1"));		auto *cbComm = new QComboBox();		cbComm->addItems(toStringList<data_DispenserConfig::DispenserType>());		tw_Dispenser->setCellWidget(r, i++, cbComm);		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("COM1"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("9600"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("N"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("8"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("1"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("0"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("0.0"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("100.0"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("0.2"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("0.5"));		tw_Dispenser->setItem(r, i++, new QTableWidgetItem("0"));		auto *chk = new QCheckBox();		auto *pContainer = new QWidget();		auto *pLayout = new QHBoxLayout(pContainer);		pLayout->addWidget(chk);		pLayout->setAlignment(Qt::AlignCenter);		pLayout->setContentsMargins(0, 0, 0, 0);		tw_Dispenser->setCellWidget(r, i++, pContainer);		tw_Dispenser->setItem(r,i++, new QTableWidgetItem("0"));		tw_Dispenser->setItem(r,i++, new QTableWidgetItem("0"));	};	connect(btnAdd, &QPushButton::clicked, [this, addDispenserRow]() {		int r = tw_Dispenser->rowCount();		tw_Dispenser->insertRow(r);		addDispenserRow(r);		sb_count_Dispenser->blockSignals(true);		sb_count_Dispenser->setValue(tw_Dispenser->rowCount());		sb_count_Dispenser->blockSignals(false);	});	connect(btnDel, &QPushButton::clicked, [this]() {		int r = tw_Dispenser->currentRow();		if (r >= 0) {			tw_Dispenser->removeRow(r);			sb_count_Dispenser->blockSignals(true);			sb_count_Dispenser->setValue(tw_Dispenser->rowCount());			sb_count_Dispenser->blockSignals(false);		}	});	connect(sb_count_Dispenser, QOverload<int>::of(&QSpinBox::valueChanged), [this, addDispenserRow](int val) {		int oldRow = tw_Dispenser->rowCount();		updateTableRows(tw_Dispenser, val);		for (int i = oldRow; i < val; ++i) {			addDispenserRow(i);		}	});	return widget;}// ============================================================================// 5. 全局外设配置页构建 (External Device Config) - 追加 m_commsChannelName 列// ============================================================================QWidget* view_configGenerator::createExternalDeviceTab() {	auto *widget = new QWidget();	auto *layout = new QVBoxLayout(widget);	auto *hl = new QHBoxLayout();	auto *btnAdd = new QPushButton(tr("Add External Device"), widget);	auto *btnDel = new QPushButton(tr("Delete Selected"), widget);	hl->addWidget(btnAdd);	hl->addWidget(btnDel);	hl->addSpacing(20);	hl->addWidget(new QLabel(tr("External Device Count:")));	sb_count_ExternalDevice = new QSpinBox();	sb_count_ExternalDevice->setRange(0, 50);	hl->addWidget(sb_count_ExternalDevice);	hl->addStretch();	layout->addLayout(hl);	tw_ExternalDevice = new QTableWidget(0, 6);	tw_ExternalDevice->setSelectionBehavior(QAbstractItemView::SelectRows);	tw_ExternalDevice->setSelectionMode(QAbstractItemView::SingleSelection);	tw_ExternalDevice->setHorizontalHeaderLabels({		tr("Device Name (userName)"),		tr("Device Type"),		tr("Comms Channel Name"),		tr("Pos X"),		tr("Pos Y"),		tr("Pos Z")		});	tw_ExternalDevice->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);	layout->addWidget(tw_ExternalDevice);	auto addExtDevRow = [this](int r) {		tw_ExternalDevice->setItem(r, 0, new QTableWidgetItem(QString("ExtDevice_%1").arg(r + 1)));		tw_ExternalDevice->setItem(r, 1, new QTableWidgetItem("HeightSensor"));		tw_ExternalDevice->setItem(r, 2, new QTableWidgetItem("Comms_Channel_1"));		tw_ExternalDevice->setItem(r, 3, new QTableWidgetItem("0.0"));		tw_ExternalDevice->setItem(r, 4, new QTableWidgetItem("0.0"));		tw_ExternalDevice->setItem(r, 5, new QTableWidgetItem("0.0"));	};	connect(btnAdd, &QPushButton::clicked, [this, addExtDevRow]() {		int r = tw_ExternalDevice->rowCount();		tw_ExternalDevice->insertRow(r);		addExtDevRow(r);		sb_count_ExternalDevice->blockSignals(true);		sb_count_ExternalDevice->setValue(tw_ExternalDevice->rowCount());		sb_count_ExternalDevice->blockSignals(false);	});	connect(btnDel, &QPushButton::clicked, [this]() {		int r = tw_ExternalDevice->currentRow();		if (r >= 0) {			tw_ExternalDevice->removeRow(r);			sb_count_ExternalDevice->blockSignals(true);			sb_count_ExternalDevice->setValue(tw_ExternalDevice->rowCount());			sb_count_ExternalDevice->blockSignals(false);		}	});	connect(sb_count_ExternalDevice, QOverload<int>::of(&QSpinBox::valueChanged), [this, addExtDevRow](int val) {		int oldRow = tw_ExternalDevice->rowCount();		updateTableRows(tw_ExternalDevice, val);		for (int i = oldRow; i < val; ++i) {			addExtDevRow(i);		}	});	return widget;}// ============================================================================// 6. 工作头配置页构建 (Toolhead Config)// ============================================================================QWidget* view_configGenerator::createToolheadTab() {	auto *widget = new QWidget();	auto *mainLayout = new QHBoxLayout(widget);	auto *leftGroup = new QGroupBox(tr("Toolhead List"), widget);	auto *leftLayout = new QVBoxLayout(leftGroup);	m_toolheadListWidget = new QListWidget(leftGroup);	auto *btnLayout = new QHBoxLayout();	auto *btnAddToolhead = new QPushButton(tr("Add Toolhead"), leftGroup);	auto *btnDelToolhead = new QPushButton(tr("Delete Toolhead"), leftGroup);	btnLayout->addWidget(btnAddToolhead);	btnLayout->addWidget(btnDelToolhead);	leftLayout->addWidget(m_toolheadListWidget);	leftLayout->addLayout(btnLayout);	m_toolheadRightGroup = new QGroupBox(tr("Toolhead Properties & Mounted Devices"), widget);	auto *rightLayout = new QVBoxLayout(m_toolheadRightGroup);	auto *formLayout = new QFormLayout();	m_editToolheadName = new QLineEdit();	m_chkIsVirtualToolhead = new QCheckBox(tr("Is Virtual Toolhead (Z-axis does not move)"));	m_editBindMotionGroup = new QLineEdit("XY_Stage_1");	m_editBindZAxis = new QLineEdit("Z_Axis_1");	formLayout->addRow(tr("Toolhead Name (userName):"), m_editToolheadName);	formLayout->addRow(tr("Virtual Flag:"), m_chkIsVirtualToolhead);	formLayout->addRow(tr("Bind Motion Group (XY Stage):"), m_editBindMotionGroup);	formLayout->addRow(tr("Bind Z Axis Name:"), m_editBindZAxis);	rightLayout->addLayout(formLayout);	auto *gbMountedDevs = new QGroupBox(tr("Mounted Devices List (mountedDevices)"), m_toolheadRightGroup);	auto *mountedLayout = new QVBoxLayout(gbMountedDevs);	m_mountedDevicesTable = new QTableWidget(0, 3);	m_mountedDevicesTable->setSelectionBehavior(QAbstractItemView::SelectRows);	m_mountedDevicesTable->setSelectionMode(QAbstractItemView::SingleSelection);	m_mountedDevicesTable->setHorizontalHeaderLabels({		tr("Device Name (userName)"),		tr("Device Type"),		tr("Comms Channel Name")		});	m_mountedDevicesTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);	auto *mDevBtnLayout = new QHBoxLayout();	auto *btnAddMDev = new QPushButton(tr("Add Mounted Device"));	auto *btnDelMDev = new QPushButton(tr("Delete Mounted Device"));	mDevBtnLayout->addWidget(btnAddMDev);	mDevBtnLayout->addWidget(btnDelMDev);	mDevBtnLayout->addStretch();	mountedLayout->addLayout(mDevBtnLayout);	mountedLayout->addWidget(m_mountedDevicesTable);	rightLayout->addWidget(gbMountedDevs);	mainLayout->addWidget(leftGroup, 1);	mainLayout->addWidget(m_toolheadRightGroup, 3);	connect(btnAddToolhead, &QPushButton::clicked, this, &view_configGenerator::onAddToolhead);	connect(btnDelToolhead, &QPushButton::clicked, this, &view_configGenerator::onDeleteToolhead);	connect(m_toolheadListWidget, &QListWidget::currentRowChanged, this, &view_configGenerator::onToolheadSelected);	connect(btnAddMDev, &QPushButton::clicked, this, &view_configGenerator::onAddMountedDevice);	connect(btnDelMDev, &QPushButton::clicked, this, &view_configGenerator::onDeleteMountedDevice);	return widget;}// ============================================================================// 7. 通用配置页构建 (Common Config)// ============================================================================QWidget* view_configGenerator::createCommonTab() {	auto *widget = new QWidget();	auto *layout = new QFormLayout(widget);	le_softwareName = new QLineEdit("ConfigGeneratorApp", widget);	layout->addRow(tr("Software Name:"), le_softwareName);	return widget;}// ============================================================================// 控制卡 UI 交互槽实现// ============================================================================void view_configGenerator::onAddController() {	saveCurrentControllerFromUI();	data_motion_controller newCard;	newCard.m_userName = QString("Card_%1").arg(m_controllerList.size() + 1);	m_controllerList.append(newCard);	m_cardListWidget->addItem(newCard.m_userName);	m_cardListWidget->setCurrentRow(m_controllerList.size() - 1);}void view_configGenerator::onDeleteController() {	int row = m_cardListWidget->currentRow();	if (row < 0 || row >= m_controllerList.size()) return;	m_controllerList.removeAt(row);	delete m_cardListWidget->takeItem(row);	m_currentCardIndex = -1;	if (!m_controllerList.isEmpty()) {		int nextRow = qMin(row, m_controllerList.size() - 1);		m_cardListWidget->setCurrentRow(nextRow);	}	else {		updateControllerRightPanel();	}}void view_configGenerator::onControllerSelected(int currentRow) {	if (currentRow == m_currentCardIndex) return;	saveCurrentControllerFromUI();	m_currentCardIndex = currentRow;	updateControllerRightPanel();}void view_configGenerator::saveCurrentControllerFromUI() {	if (m_currentCardIndex < 0 || m_currentCardIndex >= m_controllerList.size()) return;	data_motion_controller &card = m_controllerList[m_currentCardIndex];	card.m_userName = m_editCardName->text().trimmed();	card.motionControllerType = toEnum<data_motion_controller::MotionControllerType>(m_comboBrand->currentData().toString());	card.ipAddress = m_editIP->text().trimmed();	card.port = m_spinPort->value();	card.homePath_total = m_editAllAxisHomePath->text().trimmed();	card.b_showSub = m_showSub->isChecked();	if (auto *item = m_cardListWidget->item(m_currentCardIndex)) {		item->setText(card.m_userName);	}	card.data_axisInfo.clear();	for (int r = 0; r < m_axisTable->rowCount(); ++r) {		data_AxisInfo axis;		axis.m_userName = m_axisTable->item(r, 0) ? m_axisTable->item(r, 0)->text() : "";		axis.axisNo = m_axisTable->item(r, 1) ? m_axisTable->item(r, 1)->text().toInt() : 0;		axis.soft_leftLimit = m_axisTable->item(r, 2) ? m_axisTable->item(r, 2)->text().toDouble() : 0;		axis.soft_rightLimit = m_axisTable->item(r, 3) ? m_axisTable->item(r, 3)->text().toDouble() : 0;		axis.acc = m_axisTable->item(r, 4) ? m_axisTable->item(r, 4)->text().toDouble() : 500;		axis.dec = m_axisTable->item(r, 5) ? m_axisTable->item(r, 5)->text().toDouble() : 500;		axis.fastDec = m_axisTable->item(r, 6) ? m_axisTable->item(r, 6)->text().toDouble() : 500;		if (auto *chkL = qobject_cast<QCheckBox*>(m_axisTable->cellWidget(r, 7)))			axis.enable_leftSoftWareLimit = chkL->isChecked();		if (auto *chkR = qobject_cast<QCheckBox*>(m_axisTable->cellWidget(r, 8)))			axis.enable_rightSoftWareLimit = chkR->isChecked();		axis.currentControllerName = card.m_userName;		card.data_axisInfo.append(axis);	}	auto saveDigitalIO = [&](QTableWidget* table, QList<data_DoInfo>& list) {		list.clear();		for (int r = 0; r < table->rowCount(); ++r) {			data_DoInfo io;			io.m_userName = table->item(r, 0) ? table->item(r, 0)->text() : "";			io.mainIO = table->item(r, 1) ? table->item(r, 1)->text().toInt() : 0;			io.subIO = table->item(r, 2) ? table->item(r, 2)->text().toInt() : 0;			io.currentControllerName = card.m_userName;			io.showSub = card.b_showSub;			list.append(io);		}	};	saveDigitalIO(m_dinTable, card.data_Din);	saveDigitalIO(m_doutTable, card.data_Dout);	auto saveAnalogIO = [&](QTableWidget* table, QList<data_AoInfo>& list) {		list.clear();		for (int r = 0; r < table->rowCount(); ++r) {			data_AoInfo io;			io.m_userName = table->item(r, 0) ? table->item(r, 0)->text() : "";			io.address = table->item(r, 1) ? table->item(r, 1)->text().toInt() : 0;			io.currentControllerName = card.m_userName;			io.showSub = card.b_showSub;			list.append(io);		}	};	saveAnalogIO(m_ainTable, card.data_Ain);	saveAnalogIO(m_aoutTable, card.data_Aout);}void view_configGenerator::clearControllerRightPanel() {	m_editCardName->clear();	m_editIP->clear();	m_spinPort->setValue(8080);	m_axisTable->setRowCount(0);	m_dinTable->setRowCount(0);	m_doutTable->setRowCount(0);	m_ainTable->setRowCount(0);	m_aoutTable->setRowCount(0);}void view_configGenerator::updateControllerRightPanel() {	if (m_currentCardIndex < 0 || m_currentCardIndex >= m_controllerList.size()) {		m_controllerRightGroup->setEnabled(false);		clearControllerRightPanel();		return;	}	m_controllerRightGroup->setEnabled(true);	const data_motion_controller &card = m_controllerList[m_currentCardIndex];	m_editCardName->setText(card.m_userName);	int brandIdx = m_comboBrand->findData(toString(card.motionControllerType));	m_comboBrand->setCurrentIndex(brandIdx >= 0 ? brandIdx : 0);	m_editIP->setText(card.ipAddress);	m_spinPort->setValue(card.port);	m_editAllAxisHomePath->setText(card.homePath_total);	m_showSub->setChecked(card.b_showSub);	m_axisTable->setRowCount(0);	for (const auto& axis : card.data_axisInfo) {		int r = m_axisTable->rowCount();		m_axisTable->insertRow(r);		m_axisTable->setItem(r, 0, new QTableWidgetItem(axis.m_userName));		m_axisTable->setItem(r, 1, new QTableWidgetItem(QString::number(axis.axisNo)));		m_axisTable->setItem(r, 2, new QTableWidgetItem(QString::number(axis.soft_leftLimit)));		m_axisTable->setItem(r, 3, new QTableWidgetItem(QString::number(axis.soft_rightLimit)));		m_axisTable->setItem(r, 4, new QTableWidgetItem(QString::number(axis.acc)));		m_axisTable->setItem(r, 5, new QTableWidgetItem(QString::number(axis.dec)));		m_axisTable->setItem(r, 6, new QTableWidgetItem(QString::number(axis.fastDec)));		auto *chkL = new QCheckBox(); chkL->setChecked(axis.enable_leftSoftWareLimit);		m_axisTable->setCellWidget(r, 7, chkL);		auto *chkR = new QCheckBox(); chkR->setChecked(axis.enable_rightSoftWareLimit);		m_axisTable->setCellWidget(r, 8, chkR);	}	auto fillDigitalIO = [](QTableWidget* table, const QList<data_DoInfo>& list) {		table->setRowCount(0);		for (const auto& io : list) {			int r = table->rowCount();			table->insertRow(r);			table->setItem(r, 0, new QTableWidgetItem(io.m_userName));			table->setItem(r, 1, new QTableWidgetItem(QString::number(io.mainIO)));			table->setItem(r, 2, new QTableWidgetItem(QString::number(io.subIO)));		}	};	fillDigitalIO(m_dinTable, card.data_Din);	fillDigitalIO(m_doutTable, card.data_Dout);	auto fillAnalogIO = [](QTableWidget* table, const QList<data_AoInfo>& list) {		table->setRowCount(0);		for (const auto& io : list) {			int r = table->rowCount();			table->insertRow(r);			table->setItem(r, 0, new QTableWidgetItem(io.m_userName));			table->setItem(r, 1, new QTableWidgetItem(QString::number(io.address)));		}	};	fillAnalogIO(m_ainTable, card.data_Ain);	fillAnalogIO(m_aoutTable, card.data_Aout);}void view_configGenerator::onAddAxis() {	int r = m_axisTable->rowCount();	m_axisTable->insertRow(r);	m_axisTable->setItem(r, 0, new QTableWidgetItem(QString("Axis_%1").arg(r + 1)));	m_axisTable->setItem(r, 1, new QTableWidgetItem(QString::number(r)));	m_axisTable->setItem(r, 2, new QTableWidgetItem("-1000.0"));	m_axisTable->setItem(r, 3, new QTableWidgetItem("1000.0"));	m_axisTable->setItem(r, 4, new QTableWidgetItem("500.0"));	m_axisTable->setItem(r, 5, new QTableWidgetItem("500.0"));	m_axisTable->setItem(r, 6, new QTableWidgetItem("1000.0"));	m_axisTable->setCellWidget(r, 7, new QCheckBox());	m_axisTable->setCellWidget(r, 8, new QCheckBox());}void view_configGenerator::onDeleteAxis() {	int r = m_axisTable->currentRow();	if (r >= 0) m_axisTable->removeRow(r);}void view_configGenerator::onAddIO(QTableWidget* table) {	int r = table->rowCount();	table->insertRow(r);	table->setItem(r, 0, new QTableWidgetItem(QString("IO_%1").arg(r + 1)));	table->setItem(r, 1, new QTableWidgetItem("0"));	if (table->columnCount() > 2) {		table->setItem(r, 2, new QTableWidgetItem("0"));	}}void view_configGenerator::onDeleteIO(QTableWidget* table) {	int r = table->currentRow();	if (r >= 0) table->removeRow(r);}// ============================================================================// 工作头 (Toolhead) Master-Detail UI 交互槽实现// ============================================================================void view_configGenerator::onAddToolhead() {	saveCurrentToolheadFromUI();	data_ToolheadConfig newToolhead;	newToolhead.m_userName = QString("Toolhead_%1").arg(m_toolheadList.size() + 1);	m_toolheadList.append(newToolhead);	m_toolheadListWidget->addItem(newToolhead.m_userName);	m_toolheadListWidget->setCurrentRow(m_toolheadList.size() - 1);}void view_configGenerator::onDeleteToolhead() {	int row = m_toolheadListWidget->currentRow();	if (row < 0 || row >= m_toolheadList.size()) return;	m_toolheadList.removeAt(row);	delete m_toolheadListWidget->takeItem(row);	m_currentToolheadIndex = -1;	if (!m_toolheadList.isEmpty()) {		int nextRow = qMin(row, m_toolheadList.size() - 1);		m_toolheadListWidget->setCurrentRow(nextRow);	}	else {		updateToolheadRightPanel();	}}void view_configGenerator::onToolheadSelected(int currentRow) {	if (currentRow == m_currentToolheadIndex) return;	saveCurrentToolheadFromUI();	m_currentToolheadIndex = currentRow;	updateToolheadRightPanel();}void view_configGenerator::saveCurrentToolheadFromUI() {	if (m_currentToolheadIndex < 0 || m_currentToolheadIndex >= m_toolheadList.size()) return;	data_ToolheadConfig &th = m_toolheadList[m_currentToolheadIndex];	th.m_userName = m_editToolheadName->text().trimmed();	th.b_isVirtual = m_chkIsVirtualToolhead->isChecked();	th.bindMotionGroup = m_editBindMotionGroup->text().trimmed();	th.bindZAxisName = m_editBindZAxis->text().trimmed();	if (auto *item = m_toolheadListWidget->item(m_currentToolheadIndex)) {		item->setText(th.m_userName);	}	th.mountedDevices.clear();	for (int r = 0; r < m_mountedDevicesTable->rowCount(); ++r) {		data_externalDevice dev;		dev.m_userName = m_mountedDevicesTable->item(r, 0) ? m_mountedDevicesTable->item(r, 0)->text() : "";		dev.m_deviceType = toEnum<data_externalDevice::ExternalDeviceType>( m_mountedDevicesTable->item(r, 1) ? m_mountedDevicesTable->item(r, 1)->text() : "");		dev.m_commsChannelName = m_mountedDevicesTable->item(r, 2) ? m_mountedDevicesTable->item(r, 2)->text() : "";		th.mountedDevices.append(dev);	}}void view_configGenerator::clearToolheadRightPanel() {	m_editToolheadName->clear();	m_chkIsVirtualToolhead->setChecked(false);	m_editBindMotionGroup->clear();	m_editBindZAxis->clear();	m_mountedDevicesTable->setRowCount(0);}void view_configGenerator::updateToolheadRightPanel() {	if (m_currentToolheadIndex < 0 || m_currentToolheadIndex >= m_toolheadList.size()) {		m_toolheadRightGroup->setEnabled(false);		clearToolheadRightPanel();		return;	}	m_toolheadRightGroup->setEnabled(true);	const data_ToolheadConfig &th = m_toolheadList[m_currentToolheadIndex];	m_editToolheadName->setText(th.m_userName);	m_chkIsVirtualToolhead->setChecked(th.b_isVirtual);	m_editBindMotionGroup->setText(th.bindMotionGroup);	m_editBindZAxis->setText(th.bindZAxisName);	m_mountedDevicesTable->setRowCount(0);	for (const auto& dev : th.mountedDevices) {		int r = m_mountedDevicesTable->rowCount();		m_mountedDevicesTable->insertRow(r);		m_mountedDevicesTable->setItem(r, 0, new QTableWidgetItem(dev.m_userName));		m_mountedDevicesTable->setItem(r, 1, new QTableWidgetItem(toString( dev.m_deviceType)));		m_mountedDevicesTable->setItem(r, 2, new QTableWidgetItem(dev.m_commsChannelName));	}}void view_configGenerator::onAddMountedDevice() {	int r = m_mountedDevicesTable->rowCount();	m_mountedDevicesTable->insertRow(r);	m_mountedDevicesTable->setItem(r, 0, new QTableWidgetItem(QString("MountedDev_%1").arg(r + 1)));	m_mountedDevicesTable->setItem(r, 1, new QTableWidgetItem("DispenserNozzle"));	m_mountedDevicesTable->setItem(r, 2, new QTableWidgetItem("Comms_Channel_1"));}void view_configGenerator::onDeleteMountedDevice() {	int r = m_mountedDevicesTable->currentRow();	if (r >= 0) m_mountedDevicesTable->removeRow(r);}// ============================================================================// 数据同步与 JSON 序列化读写// ============================================================================QJsonObject view_configGenerator::saveToTempJson() {	saveCurrentControllerFromUI();	saveCurrentToolheadFromUI();	data_equipment config;	config.deviceName = le_softwareName->text().trimmed();	// 1. 读取 Motion Controller 列表	config.data_motion_controller_configs = m_controllerList;	// 2. 读取 通讯模块 列表	for (int i = 0; i < tw_Comms->rowCount(); ++i) {		data_CommsConfig comm;		comm.m_userName = tw_Comms->item(i, 0) ? tw_Comms->item(i, 0)->text() : "";		if (auto *cbType = qobject_cast<QComboBox*>(tw_Comms->cellWidget(i, 1))) {			comm.commsType =toEnum<data_CommsConfig::CommsType>(cbType->currentText()) ;		}		comm.portName = tw_Comms->item(i, 2) ? tw_Comms->item(i, 2)->text() : "COM1";		comm.baudRate = tw_Comms->item(i, 3) ? tw_Comms->item(i, 3)->text().toInt() : 115200;		QString parityStr = tw_Comms->item(i, 4) ? tw_Comms->item(i, 4)->text() : "N";		comm.parity = parityStr.isEmpty() ? 'N' : parityStr.at(0).toLatin1();		comm.dataBits = tw_Comms->item(i, 5) ? tw_Comms->item(i, 5)->text().toInt() : 8;		comm.stopBits = tw_Comms->item(i, 6) ? tw_Comms->item(i, 6)->text().toInt() : 1;		comm.ip = tw_Comms->item(i, 7) ? tw_Comms->item(i, 7)->text() : "192.168.1.100";		comm.tcpPort = tw_Comms->item(i, 8) ? tw_Comms->item(i, 8)->text().toInt() : 8080;		comm.slaveAddress = tw_Comms->item(i, 9) ? tw_Comms->item(i, 9)->text().toInt() : 1;		comm.timeoutMs = tw_Comms->item(i, 10) ? tw_Comms->item(i, 10)->text().toInt() : 1000;		comm.retryTimes = tw_Comms->item(i, 11) ? tw_Comms->item(i, 11)->text().toInt() : 2;		config.data_comms_configs.append(comm);	}	// 3. 读取 测距传感器 列表 (Height Sensor)	for (int i = 0; i < tw_HeightSensor->rowCount(); ++i) {		data_HeightSensorConfig sensor;				sensor.m_userName = tw_HeightSensor->item(i, 0) ? tw_HeightSensor->item(i, 0)->text() : "";		sensor.m_commsChannelName = tw_HeightSensor->item(i, 1) ? tw_HeightSensor->item(i, 1)->text() : "";			sensor.m_deviceType =data_externalDevice::HEIGHT_SENSOR;		if (auto *cbComm = qobject_cast<QComboBox*>(tw_HeightSensor->cellWidget(i, 2))) {			sensor.commType = cbComm->currentText();		}		QString msrAddrStr = tw_HeightSensor->item(i, 3) ? tw_HeightSensor->item(i, 3)->text() : "0x6000";		bool ok = false;		sensor.msrAddress = msrAddrStr.toUInt(&ok, 0);		QString statusAddrStr = tw_HeightSensor->item(i, 4) ? tw_HeightSensor->item(i, 4)->text() : "0x6001";		sensor.statusAddress = statusAddrStr.toUInt(&ok, 0);		if (auto *pContainer = tw_HeightSensor->cellWidget(i, 5)) {			if (auto *chk = pContainer->findChild<QCheckBox*>()) {				sensor.b_same_direction_with_axis = chk->isChecked();			}		}		sensor.minRange = tw_HeightSensor->item(i, 6) ? tw_HeightSensor->item(i, 6)->text().toDouble() : 0.0;		sensor.maxRange = tw_HeightSensor->item(i, 7) ? tw_HeightSensor->item(i, 7)->text().toDouble() : 0.0;		sensor.offset = tw_HeightSensor->item(i, 8) ? tw_HeightSensor->item(i, 8)->text().toDouble() : 0.0;		config.data_heightSensor_configs.append(sensor);	}	// 4. 读取 Dispenser 列表	for (int i = 0; i < tw_Dispenser->rowCount(); ++i) {		data_DispenserConfig disp;		int j = 0;		disp.m_userName = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text() : "";		j++;		disp.m_commsChannelName = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text() : "";		j++;		disp.m_deviceType = data_externalDevice::ExternalDeviceType::DISPENSOR;		if (auto *cbComm = qobject_cast<QComboBox*>(tw_Dispenser->cellWidget(i, j))) {			disp.commType = cbComm->currentText();		}		j++;		disp.port = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text() : "COM1";		j++;		disp.baudRate = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toInt() : 9600;		j++;		QString parityStr = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text() : "N";		disp.parity = parityStr.isEmpty() ? 'N' : parityStr.at(0).toLatin1();		j++;		disp.dataBits = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toInt() : 8;		j++;		disp.stopBits = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toInt() : 1;		j++;		disp.analogAddress = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toInt() : 0;		j++;		disp.minPressure = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toFloat() : 0.0f;		j++;		disp.maxPressure = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toFloat() : 100.0f;		j++;		disp.defaultPressure = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toDouble() : 0.2;		j++;		disp.defaultDispenseTime = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toDouble() : 0.5;		j++;		disp.outputSwitchIO = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toInt() : 0;		j++;		if (auto *pContainer = tw_Dispenser->cellWidget(i, j)) {			if (auto *chk = pContainer->findChild<QCheckBox*>()) {				disp.state_outputSwitch = chk->isChecked();			}		}		j++;		disp.mainIO_openGas = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i, j)->text().toInt() : 0;		j++;		disp.subIO_openGas = tw_Dispenser->item(i, j) ? tw_Dispenser->item(i,j)->text().toInt() : 0;		j++;		config.data_dispenser_configs.append(disp);	}	// 5. 读取 External Devices 全局外设列表	for (int i = 0; i < tw_ExternalDevice->rowCount(); ++i) {		data_externalDevice dev;		dev.m_userName = tw_ExternalDevice->item(i, 0) ? tw_ExternalDevice->item(i, 0)->text() : "";		dev.m_deviceType =toEnum<data_externalDevice::ExternalDeviceType>( tw_ExternalDevice->item(i, 1) ? tw_ExternalDevice->item(i, 1)->text() : "");		dev.m_commsChannelName = tw_ExternalDevice->item(i, 2) ? tw_ExternalDevice->item(i, 2)->text() : "";		dev.pos_x = tw_ExternalDevice->item(i, 3) ? tw_ExternalDevice->item(i, 3)->text().toDouble() : 0.0;		dev.pos_y = tw_ExternalDevice->item(i, 4) ? tw_ExternalDevice->item(i, 4)->text().toDouble() : 0.0;		dev.pos_z = tw_ExternalDevice->item(i, 5) ? tw_ExternalDevice->item(i, 5)->text().toDouble() : 0.0;		config.data_external_device_configs.append(dev);	}	// 6. 读取 Toolhead 工作头列表	config.data_toolhead_configs = m_toolheadList;	*currentData = config;	return config.toJson();}void view_configGenerator::loadFromTempJson(const QJsonObject& json) {	data_equipment config;	config.fromJson(json);	*currentData = config;	le_softwareName->setText(config.deviceName);	// 1. 加载 Motion Controller 数组	m_controllerList = config.data_motion_controller_configs;	m_cardListWidget->clear();	for (const auto& card : m_controllerList) {		m_cardListWidget->addItem(card.m_userName);	}	m_currentCardIndex = -1;	if (!m_controllerList.isEmpty()) {		m_cardListWidget->setCurrentRow(0);	}	else {		updateControllerRightPanel();	}	// 2. 加载 通讯模块	sb_count_Comms->setValue(config.data_comms_configs.size());	for (int i = 0; i < config.data_comms_configs.size(); ++i) {		const auto &comm = config.data_comms_configs[i];		tw_Comms->setItem(i, 0, new QTableWidgetItem(comm.m_userName));		if (auto *cbType = qobject_cast<QComboBox*>(tw_Comms->cellWidget(i, 1))) {			cbType->setCurrentText(toString(comm.commsType) );		}		tw_Comms->setItem(i, 2, new QTableWidgetItem(comm.portName));		tw_Comms->setItem(i, 3, new QTableWidgetItem(QString::number(comm.baudRate)));		tw_Comms->setItem(i, 4, new QTableWidgetItem(QString(comm.parity)));		tw_Comms->setItem(i, 5, new QTableWidgetItem(QString::number(comm.dataBits)));		tw_Comms->setItem(i, 6, new QTableWidgetItem(QString::number(comm.stopBits)));		tw_Comms->setItem(i, 7, new QTableWidgetItem(comm.ip));		tw_Comms->setItem(i, 8, new QTableWidgetItem(QString::number(comm.tcpPort)));		tw_Comms->setItem(i, 9, new QTableWidgetItem(QString::number(comm.slaveAddress)));		tw_Comms->setItem(i, 10, new QTableWidgetItem(QString::number(comm.timeoutMs)));		tw_Comms->setItem(i, 11, new QTableWidgetItem(QString::number(comm.retryTimes)));	}	// 3. 加载 测距传感器 (Height Sensor)	sb_count_HeightSensor->setValue(config.data_heightSensor_configs.size());	for (int i = 0; i < config.data_heightSensor_configs.size(); ++i) {		const auto &sensor = config.data_heightSensor_configs[i];		tw_HeightSensor->setItem(i, 0, new QTableWidgetItem(sensor.m_userName));		tw_HeightSensor->setItem(i, 1, new QTableWidgetItem(sensor.m_commsChannelName));		if (auto *cbComm = qobject_cast<QComboBox*>(tw_HeightSensor->cellWidget(i, 2))) {			cbComm->setCurrentText(sensor.commType);		}		tw_HeightSensor->setItem(i, 3, new QTableWidgetItem(QString("0x%1").arg(sensor.msrAddress, 4, 16, QChar('0'))));		tw_HeightSensor->setItem(i, 4, new QTableWidgetItem(QString("0x%1").arg(sensor.statusAddress, 4, 16, QChar('0'))));		if (auto *pContainer = tw_HeightSensor->cellWidget(i, 5)) {			if (auto *chk = pContainer->findChild<QCheckBox*>()) {				chk->setChecked(sensor.b_same_direction_with_axis);			}		}		tw_HeightSensor->setItem(i, 6, new QTableWidgetItem(QString::number(sensor.minRange)));		tw_HeightSensor->setItem(i, 7, new QTableWidgetItem(QString::number(sensor.maxRange)));		tw_HeightSensor->setItem(i, 8, new QTableWidgetItem(QString::number(sensor.offset)));	}	// 4. 加载 Dispenser	sb_count_Dispenser->setValue(config.data_dispenser_configs.size());	for (int i = 0; i < config.data_dispenser_configs.size(); ++i) {		const auto &disp = config.data_dispenser_configs[i];		int j = 0;		tw_Dispenser->setItem(i, j++, new QTableWidgetItem(disp.m_userName));		tw_Dispenser->setItem(i, j++, new QTableWidgetItem(disp.m_commsChannelName));		if (auto *cbComm = qobject_cast<QComboBox*>(tw_Dispenser->cellWidget(i, j++))) {			cbComm->setCurrentText(disp.commType);		}		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(disp.port));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.baudRate)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString(disp.parity)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.dataBits)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.stopBits)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.analogAddress)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.minPressure)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.maxPressure)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.defaultPressure)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.defaultDispenseTime)));		tw_Dispenser->setItem(i,j++, new QTableWidgetItem(QString::number(disp.outputSwitchIO)));		if (auto *pContainer = tw_Dispenser->cellWidget(i, j++)) {			if (auto *chk = pContainer->findChild<QCheckBox*>()) {				chk->setChecked(disp.state_outputSwitch);			}		}		tw_Dispenser->setItem(i, j++, new QTableWidgetItem(QString::number(disp.mainIO_openGas)));		tw_Dispenser->setItem(i, j++, new QTableWidgetItem(QString::number(disp.subIO_openGas)));	}	// 5. 加载 External Devices 全局外设	sb_count_ExternalDevice->setValue(config.data_external_device_configs.size());	for (int i = 0; i < config.data_external_device_configs.size(); ++i) {		const auto &dev = config.data_external_device_configs[i];		tw_ExternalDevice->setItem(i, 0, new QTableWidgetItem(dev.m_userName));		tw_ExternalDevice->setItem(i, 1, new QTableWidgetItem(dev.m_deviceType));		tw_ExternalDevice->setItem(i, 2, new QTableWidgetItem(dev.m_commsChannelName));		tw_ExternalDevice->setItem(i, 3, new QTableWidgetItem(QString::number(dev.pos_x)));		tw_ExternalDevice->setItem(i, 4, new QTableWidgetItem(QString::number(dev.pos_y)));		tw_ExternalDevice->setItem(i, 5, new QTableWidgetItem(QString::number(dev.pos_z)));	}	// 6. 加载 Toolhead 工作头数组	m_toolheadList = config.data_toolhead_configs;	m_toolheadListWidget->clear();	for (const auto& th : m_toolheadList) {		m_toolheadListWidget->addItem(th.m_userName);	}	m_currentToolheadIndex = -1;	if (!m_toolheadList.isEmpty()) {		m_toolheadListWidget->setCurrentRow(0);	}	else {		updateToolheadRightPanel();	}}// 文件加载与保存槽函数void view_configGenerator::onLoadConfigFromFile() {	QString path = QFileDialog::getOpenFileName(this, tr("Open Config File"), "", tr("e3d Files (*.e3d *.json)"));	if (path.isEmpty()) return;	QFile file(path);	if (!file.open(QIODevice::ReadOnly)) {		QMessageBox::critical(this, tr("Error"), tr("Failed to open configuration file!"));		return;	}	QJsonDocument doc = QJsonDocument::fromJson(file.readAll());	file.close();	le_configPath->setText(path);	loadFromTempJson(doc.object());	QMessageBox::information(this, tr("Information"), tr("Configuration file loaded successfully!"));}void view_configGenerator::onSaveConfigToFile() {	saveToTempJson();	if (!e3d_configManager_Equipment::Instance()->saveToFile_dialog(currentData)) {		return;	}}void view_configGenerator::onSaveTempClicked() {	saveToTempJson();	QMessageBox::information(this, tr("Information"), tr("Configuration saved to temporary memory!"));}