#include "WindowAppVariableTable.h" #include "GvlManager.h" // extern VariablesManager m_VariablesManager; // 列数 #define GVL_COLUMN_COUNT 6 #define DB_COLUMN_COUNT 7 // 表示正确状态的颜色 #define COLOR_ITEM_OK qRgb(198,239,206) #define COLOR_ITEM_ERROR qRgb(255,199,206) WindowAppVariableTable::WindowAppVariableTable(QWidget *parent) : QTableWidget(parent) , m_gvlMode( GVL_MODE::GVL_BASIC ) { ui.setupUi(this); } WindowAppVariableTable::~WindowAppVariableTable() { } /// /// 初始化变量表格 /// void WindowAppVariableTable::initTable(const QString& strGroup, GVL_MODE gvlMode) { this->m_strGroup = strGroup; m_gvlMode = gvlMode; // 创建变量表格 // 根据不同模式初始化不同的表格 if (m_gvlMode != GVL_MODE::GVL_DB) { this->initStandardTableHeader(); } else { this->initDBTableHeader(); } //设置表头字体 QFont font = this->horizontalHeader()->font(); font.setBold(true); this->horizontalHeader()->setFont(font); // 设置文字左对齐 this->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter); // 设置为不可编辑 //this->setEditTriggers(QAbstractItemView::NoEditTriggers); // 设置为整行选中模式 this->setSelectionBehavior(QAbstractItemView::SelectRows); this->setSelectionMode(QAbstractItemView::SingleSelection); // 设置最左侧的序号不用显示 this->verticalHeader()->setVisible(false); //设置行高 this->verticalHeader()->setDefaultSectionSize(10); //点击表时不对表头行光亮(获取焦点)当表格只有一行的时候,则表头会出现塌陷问题 this->horizontalHeader()->setHighlightSections(false); } /// /// 按标准模式初始化变量表格Header /// void WindowAppVariableTable::initStandardTableHeader() { // 列数 this->setColumnCount(GVL_COLUMN_COUNT); // 设置表头文字 QStringList headers; headers << ("Index") << ("Name") << ("Type") << ("Value") << ("Serialized") << ("Comment"); this->setHorizontalHeaderLabels(headers); } /// /// 按DB模式初始化变量表格Header /// void WindowAppVariableTable::initDBTableHeader() { // 列数 this->setColumnCount(DB_COLUMN_COUNT); // 设置表头文字 QStringList headers; headers << ("Index") << ("Name") << ("Type") << ("Value") << ("Comm. Address") << ("Access") << ("Comment"); this->setHorizontalHeaderLabels(headers); } /// /// 添加新的一行 /// /// int WindowAppVariableTable::insertTableLine( bool bSerialized, QString strName, QString strFullName, QString strType, QString strValue, QString strComment ) { // 防止消息被循环触发 this->blockSignals(true); // 获取当前行数 int nRowCount = this->rowCount(); // 添加新的一行 this->insertRow(nRowCount); // ---Index QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(nRowCount + 1)); indexItem->setTextAlignment(Qt::AlignCenter); // 本列不可编辑 indexItem->setFlags(indexItem->flags() & (~Qt::ItemIsEditable)); this->setItem(nRowCount, GVL_COL_INDEX, indexItem); // ---Name QTableWidgetItem* nameItem = new QTableWidgetItem(strName); this->setItem(nRowCount, GVL_COL_NAME, nameItem); nameItem->setTextAlignment(Qt::AlignCenter); // 不可编辑 nameItem->setFlags(nameItem->flags() & (~Qt::ItemIsEditable)); // ---Type QTableWidgetItem* typeItem = new QTableWidgetItem(strType); this->setItem(nRowCount, GVL_COL_TYPE, typeItem); typeItem->setTextAlignment(Qt::AlignCenter); // 不可编辑 typeItem->setFlags(typeItem->flags() & (~Qt::ItemIsEditable)); // ---Value QTableWidgetItem* valueItem = new QTableWidgetItem(strValue); valueItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); this->setItem(nRowCount, GVL_COL_VALUE, valueItem); // 保存一下当前输入的值 m_LastValues.push_back(strValue); // 2022-2-22 改为仅基础模式的可编辑 if (m_gvlMode != GVL_MODE::GVL_BASIC) { valueItem->setFlags(valueItem->flags() & (~Qt::ItemIsEditable)); } //// 设置单元格状态 //this->setItemOK(nRowCount, GVL_COL_VALUE); // ---Serialized (CheckBox) // 创建单元格的CheckBox QCheckBox* checkSerialized = new QCheckBox(); if (bSerialized) { checkSerialized->setCheckState(Qt::Checked); } else { checkSerialized->setCheckState(Qt::Unchecked); } // 创建Widget和布局 QWidget* checkContainer = new QWidget(this); // 设置为透明,否则看起来很奇怪(两种不同的透明效果可以任意选择) checkContainer->setStyleSheet("background-color:transparent "); //w->setAttribute(Qt::WA_TranslucentBackground, true); // // 建立水平布局 QHBoxLayout* checkLayout = new QHBoxLayout(); checkLayout->addWidget(checkSerialized); checkLayout->setMargin(0); checkLayout->setAlignment(checkSerialized, Qt::AlignCenter); checkContainer->setLayout(checkLayout); // 设置单元格为居中的Checkbox this->setCellWidget(nRowCount, GVL_COL_SERIALIZED, checkContainer); // 保存指针 m_cellCheckbox.insert(checkSerialized, nRowCount); // ---Comment if (strComment.isEmpty()) { strComment = "Type here to input comment."; } QTableWidgetItem* commentItem = new QTableWidgetItem(strComment); this->setItem(nRowCount, GVL_COL_COMMENT, commentItem); // 设置关联信号 connect( checkSerialized, SIGNAL(toggled(bool)), this, SLOT(onTableSerializedChanged(bool)) ); connect( this, &QTableWidget::cellChanged, this, &WindowAppVariableTable::onTableCellChanged ); // 防止消息被循环触发 this->blockSignals(false); // 保存变量和行数的对应关系 m_VariablesRows.insert(strFullName, nRowCount); return nRowCount; } /// /// 表格中添加新的一行(DB模式) /// /// /// /// /// /// /// /// /// int WindowAppVariableTable::insertTableLine( QString strName, QString strFullName, QString strType, QString strValue, QString strCommAddress, VPEnum::GVL_ACCESS_MODE accessMode, QString strComment ) { // 防止消息被循环触发 this->blockSignals(true); // 获取当前行数 int nRowCount = this->rowCount(); // 添加新的一行 this->insertRow(nRowCount); // ---Index QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(nRowCount + 1)); indexItem->setTextAlignment(Qt::AlignCenter); // 本列不可编辑 indexItem->setFlags(indexItem->flags() & (~Qt::ItemIsEditable)); this->setItem(nRowCount, DB_COL_INDEX, indexItem); // ---Name QTableWidgetItem* nameItem = new QTableWidgetItem(strName); this->setItem(nRowCount, DB_COL_NAME, nameItem); nameItem->setTextAlignment(Qt::AlignCenter); // 不可编辑 nameItem->setFlags(nameItem->flags() & (~Qt::ItemIsEditable)); // ---Type QTableWidgetItem* typeItem = new QTableWidgetItem(strType); this->setItem(nRowCount, DB_COL_TYPE, typeItem); typeItem->setTextAlignment(Qt::AlignCenter); // 不可编辑 typeItem->setFlags(typeItem->flags() & (~Qt::ItemIsEditable)); // ---Value QTableWidgetItem* valueItem = new QTableWidgetItem(strValue); valueItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); this->setItem(nRowCount, DB_COL_VALUE, valueItem); // 保存一下当前输入的值(为防止信号重复触发) m_LastValues.push_back(strValue); // ---Address QTableWidgetItem* addressItem = new QTableWidgetItem(strCommAddress); addressItem->setTextAlignment(Qt::AlignCenter); this->setItem(nRowCount, DB_COL_ADDRESS, addressItem); // ---Access QTableWidgetItem* accessItem = new QTableWidgetItem(emGvlAccess.key((short)accessMode)); accessItem->setTextAlignment(Qt::AlignCenter); this->setItem(nRowCount, DB_COL_ACCESS, accessItem); // 不可编辑 accessItem->setFlags(accessItem->flags() & (~Qt::ItemIsEditable)); // ---Comment if (strComment.isEmpty()) { strComment = "Type here to input comment."; } QTableWidgetItem* commentItem = new QTableWidgetItem(strComment); this->setItem(nRowCount, DB_COL_COMMENT, commentItem); // 设置单元格变动的关联信号 connect( this, &QTableWidget::cellChanged, this, &WindowAppVariableTable::onTableCellChanged ); // 防止消息被循环触发 this->blockSignals(false); // 保存变量和行数的对应关系 m_VariablesRows.insert(strFullName, nRowCount); return nRowCount; } /// /// Toolbar - MoveUp /// void WindowAppVariableTable::onVariableMoveUp() { // qDebug() << "WindowAppVariableTable::onToolMoveUp"; // 获取行号 int rowIndex = this->currentRow(); if (rowIndex <= 0) { return; } int rowIndex2 = rowIndex - 1; // 从数据结构中移动 g_pGvlManager->exchangeVariable(m_strGroup, rowIndex, rowIndex2); // 从界面中移动 swapRows(rowIndex, rowIndex2); // 需要移动一下焦点 this->selectRow(rowIndex2); } /// /// Toolbar - MoveDown /// void WindowAppVariableTable::onVariableMoveDown() { // qDebug() << "WindowAppVariableTable::onToolMoveDown"; // 获取行号 int rowIndex = this->currentRow(); if (rowIndex < 0 || rowIndex == this->rowCount() - 1) { return; } int rowIndex2 = rowIndex + 1; // 从数据结构中移动 g_pGvlManager->exchangeVariable(m_strGroup, rowIndex, rowIndex2); // 从界面中移动 swapRows(rowIndex, rowIndex2); // 需要移动一下焦点 this->selectRow(rowIndex2); } /// /// Toolbar - Delete /// void WindowAppVariableTable::onVariableDelete() { // qDebug() << "WindowAppVariableTable::onToolDelete"; // g_pGvlManager->debugAllVariables(); // 获取要删除的行号 int rowIndex = this->currentRow(); if (rowIndex < 0) { return; } int nVariablesCount = g_pGvlManager->getVariablesCountByGroup(m_strGroup); // 计算局部变量的数量 int nLocalVarSize = nVariablesCount - this->rowCount(); this->blockSignals(true); // 首先需要检查引用计数,确定没有引用才允许删除 int nRefCount = g_pGvlManager->getRefCount(m_strGroup, rowIndex + nLocalVarSize); if (nRefCount > 0) { Utility::VPCriticalMessageBox("Can't delete this variable for reference count is " + QString::number(nRefCount)); return; } // 提示确认 int nRet = Utility::VPQuesitonMessageBox("Are you sure to delete this variable? "); if (nRet == QMessageBox::No) { return; } // 从数据结构中删除 g_pGvlManager->delVariable(m_strGroup, rowIndex + nLocalVarSize); // 从界面中删除 this->removeRow(rowIndex); // 重写删除当前行之后的Index for (int i = rowIndex; i < this->rowCount(); i++) { this->item(i, GVL_COL_INDEX)->setText(QString::number(i + 1)); } // 还需要删除对应的QCheckBox数据结构信息 QHash::iterator iter2 = m_cellCheckbox.begin(); while (iter2 != m_cellCheckbox.end()) { if (iter2.value() == rowIndex) { m_cellCheckbox.erase(iter2); break; } else { iter2++; } } // 删除保存的上次变量信息 QVector::iterator iter3 = m_LastValues.begin(); m_LastValues.erase(iter3 + rowIndex); // 还需要删除变量和行数的数据结构信息 QHash::iterator iter4 = m_VariablesRows.begin(); while (iter4 != m_VariablesRows.end()) { if (iter4.value() == rowIndex) { m_VariablesRows.erase(iter4); break; } else { iter4++; } } this->blockSignals(false); } /// /// 调整大小的消息中改变表格栏的宽度 /// /// void WindowAppVariableTable::resizeEvent(QResizeEvent* event) { Q_UNUSED(event); // qDebug() << "WindowAppVariableTable::resizeEvent"; int nTotalSize = this->size().width(); if (m_gvlMode != GVL_MODE::GVL_DB) { this->setColumnWidth(GVL_COL_INDEX, nTotalSize * 0.05); this->setColumnWidth(GVL_COL_NAME, nTotalSize * 0.20); this->setColumnWidth(GVL_COL_TYPE, nTotalSize * 0.15); this->setColumnWidth(GVL_COL_VALUE, nTotalSize * 0.20); this->setColumnWidth(GVL_COL_SERIALIZED, nTotalSize * 0.10); this->setColumnWidth(GVL_COL_COMMENT, nTotalSize * 0.30); } else { this->setColumnWidth(DB_COL_INDEX, nTotalSize * 0.05); this->setColumnWidth(DB_COL_NAME, nTotalSize * 0.20); this->setColumnWidth(DB_COL_TYPE, nTotalSize * 0.10); this->setColumnWidth(DB_COL_VALUE, nTotalSize * 0.20); this->setColumnWidth(DB_COL_ADDRESS, nTotalSize * 0.10); this->setColumnWidth(DB_COL_ACCESS, nTotalSize * 0.10); this->setColumnWidth(DB_COL_COMMENT, nTotalSize * 0.25); } } /// /// 当表格单元改变时 /// /// /// //int nLastrow = 0; //int nLastCol = 0; void WindowAppVariableTable::onTableCellChanged(int row, int col) { // 屏蔽Signal,防止在编辑的时候嵌套触发死循环 this->blockSignals(true); qDebug() << "WindowAppVariableTable::onTableCellChanged (" << row << "," << col << ")"; switch (col) { case GVL_COL_VALUE: { QString strNewValue = this->item(row, GVL_COL_VALUE)->text(); QString strOldValue = m_LastValues.value(row); // 由于本消息会多次触发,不得不在这里处理一下了 if (strNewValue == strOldValue) { this->blockSignals(false); qDebug() << "WindowAppVariableTable::onTableCellChanged - updateValue duplicated."; return; } bool bRet = g_pGvlManager->updateValue(m_strGroup, row, strNewValue); // 如果值无效,则报错,并且还原用户输入 if (!bRet) { Utility::VPCriticalMessageBox("Invalid value at (" + QString::number(row) + "," + QString::number(col) + ")"); this->item(row, GVL_COL_VALUE)->setText(strOldValue); } else { m_LastValues[row] = strNewValue; } // 2022-3-8,如果本表格是DB类型变量,还需要额外通知到Dll端执行对应更新 // 将值写入到dll的工具中 if (m_gvlMode == GVL_MODE::GVL_DB) { // TODO:此处获取到对应的DllTool指针将最新的值写入 TOOL* pTool = g_pGvlManager->getHdwToolByDbName(m_strGroup); if (pTool) { pTool->pDllPtr->updateValue(row); } } //if (!bRet) //{ // this->blockSignals(false); // this->setItemError(row, GVL_COL_VALUE); // return; //} //else //{ // this->setItemOK(row, GVL_COL_VALUE); //} } break; // 此处还有可能是 DB_COL_ACCESS(尚未启用) case GVL_COL_COMMENT: { // 修改了标准模式的注释项 if (m_gvlMode != GVL_MODE::GVL_DB) { QString strNewComment = this->item(row, GVL_COL_COMMENT)->text(); g_pGvlManager->updateComment(m_strGroup, row, strNewComment); } // 修改了DB模式的ACCESS项(尚未启用) else { // 修改了DB模式的通讯地址项 if (m_gvlMode == GVL_MODE::GVL_DB) { QString strNewAddress = this->item(row, DB_COL_ADDRESS)->text(); g_pGvlManager->updateComment(m_strGroup, row, strNewAddress); } } } break; case DB_COL_COMMENT: { QString strNewComment = this->item(row, DB_COL_COMMENT)->text(); g_pGvlManager->updateComment(m_strGroup, row, strNewComment); } break; default: qDebug() << "WindowAppVariableTable::onTableCellChanged - invalid column : " << col; break; } this->blockSignals(false); } ///// ///// 更新变量值 ///// ///// ///// //bool WindowAppVariableTable::updateValue(int row) //{ // return false; //} // // ///// ///// 更新注释 ///// ///// ///// //bool WindowAppVariableTable::updateComment(int row) //{ // return false; //} /// /// 当Serialized状态发生改变时 /// /// void WindowAppVariableTable::onTableSerializedChanged(bool bChecked) { // 这里只能通过Sender来找到第几行的Checkbox被编辑了 QCheckBox* checkSerialized = qobject_cast(sender()); int row = m_cellCheckbox.value(checkSerialized); qDebug() << "WindowAppVariableTable::onTableSerializedChanged [" << row << "] - " << bChecked; g_pGvlManager->updatePersit( m_strGroup, row, checkSerialized->checkState() == Qt::Checked ); // 还需要将对应的行帮Table选中 this->selectRow(row); //QList selItems = this->selectedItems(); //// 获取选中的行号 //int row = this->row(selItems.at(0)); //int row = this->currentItem()->row(); } /// /// 更新表格中指定变量的值 /// /// void WindowAppVariableTable::updateTableValue(const QString& strVarFullName, const QString& strNewValue) { QHash::iterator iter = m_VariablesRows.find(strVarFullName); int nRow = -1; if (iter != m_VariablesRows.end()) { nRow = m_VariablesRows.value(strVarFullName); } else { qDebug() << "[ERROR][WindowAppVariableTable::updateTableValue] - Invalid Variable*"; return; } // QString strNewValue = pVar->getValueByString(); // debugTableVariables(); this->item(nRow, GVL_COL_VALUE)->setText(strNewValue); qDebug() << "[updateTableValue] Update tableUI - " << strVarFullName << " to " << strNewValue; } ///// ///// 将指定的表格设置为错误状态 ///// ///// ///// //void WindowAppVariableTable::setItemError(int row, int col) //{ // this->item(row, col)->setBackgroundColor(COLOR_ITEM_ERROR); //} // // ///// ///// 将指定的表格设置为正常状态 ///// ///// ///// //void WindowAppVariableTable::setItemOK(int row, int col) //{ // this->item(row, col)->setBackgroundColor(COLOR_ITEM_OK); //} /// /// 交换两行的数据 /// /// /// bSerialized void WindowAppVariableTable::swapRows(int selectRow, int targetRow) { this->blockSignals(true); QStringList selectRowLine, targetRowLine; // 跳过Index列不需要交换 for (int i = 1; i < GVL_COLUMN_COUNT; i++) { if (i != GVL_COL_SERIALIZED) { QString strSelect = this->item(selectRow, i)->text(); QString strTarget = this->item(targetRow, i)->text(); this->item(selectRow, i)->setText(strTarget); this->item(targetRow, i)->setText(strSelect); } else { // 交换Checkbox控件的值,这个比较麻烦一些 QWidget* selectWidget = (QWidget*)this->cellWidget(selectRow, GVL_COL_SERIALIZED); QCheckBox* selectCheckSerialzied = qobject_cast(selectWidget->children().at(1)); bool bSelectSerialized = selectCheckSerialzied->checkState() == Qt::Checked; QWidget* targetWidget = (QWidget*)this->cellWidget(targetRow, GVL_COL_SERIALIZED); QCheckBox* targetCheckSerialized = qobject_cast(targetWidget->children().at(1)); bool bTargetSerialized = targetCheckSerialized->checkState() == Qt::Checked; selectCheckSerialzied->setChecked(bTargetSerialized); targetCheckSerialized->setChecked(bSelectSerialized); selectRowLine.append(""); targetRowLine.append(""); } } //for (int i = 0; i < GVL_COLUMN_COUNT; i++) //{ // if (i != GVL_COL_PERSISTENT) // { // //this->setItem(selectRow, i, new QTableWidgetItem(targetRowLine.at(i))); // //this->setItem(targetRow, i, new QTableWidgetItem(selectRowLine.at(i))); // } //} // 交换变量和行数的数据结构 QHash::iterator iter = m_VariablesRows.begin(); QString strSelectValue, strTargetValue; while (iter != m_VariablesRows.end()) { if (iter.value() == selectRow) { // m_TableVariables.erase(iter); strSelectValue = iter.key(); } else if (iter.value() == targetRow) { strTargetValue = iter.key();; } iter++; } m_VariablesRows[strSelectValue] = targetRow; m_VariablesRows[strTargetValue] = selectRow; this->blockSignals(false); }