#include "TearingDataTableWidget.h" #include #include #include #include #include #include #include #include TearingDataTableWidget::TearingDataTableWidget(QWidget *parent) : QWidget(parent) , m_tableWidget(nullptr) { // 初始化与服务端颜色协调的颜色数组 m_tearColors[0] = QColor(255, 105, 97); // 珊瑚红 m_tearColors[1] = QColor(255, 160, 122); // 浅鲑鱼色 m_tearColors[2] = QColor(173, 216, 230); // 浅蓝色 m_tearColors[3] = QColor(144, 238, 144); // 浅绿色 m_tearColors[4] = QColor(255, 182, 193); // 浅粉色 m_tearColors[5] = QColor(221, 160, 221); // 梅花色 m_tearColors[6] = QColor(255, 215, 0); // 金色 m_tearColors[7] = QColor(240, 128, 128); // 玫瑰色 m_tearColors[8] = QColor(135, 206, 250); // 天蓝色 m_tearColors[9] = QColor(127, 255, 212); // 碧绿色 setupUI(); setupTable(); } TearingDataTableWidget::~TearingDataTableWidget() { } void TearingDataTableWidget::setupUI() { QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); m_tableWidget = new QTableWidget(this); layout->addWidget(m_tableWidget); setLayout(layout); } void TearingDataTableWidget::setupTable() { // 设置表头标签 QStringList headers; // headers << "ID" << "等级" << "状态" << "类型" /*<< "起始行" << "结束行" */<< "深度" << "宽度" << "长度" << "老化"; headers << "设备" << "编号" << "状态" << "类型" << "深度(mm)" << "宽度(mm)" << "长度(mm)" << "时间"; // 设置表格属性 m_tableWidget->setColumnCount(headers.size()); m_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); m_tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); m_tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_tableWidget->verticalHeader()->setVisible(false); m_tableWidget->setHorizontalHeaderLabels(headers); #if 0 m_tableWidget->horizontalHeader()->setStretchLastSection(true); #else // 启用交互式列宽调整 m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); // 设置列宽 m_tableWidget->setColumnWidth(0, 85); // 名称 m_tableWidget->setColumnWidth(1, 62); // ID列 m_tableWidget->setColumnWidth(2, 50); // 状态列 m_tableWidget->setColumnWidth(3, 50); // 类型列 m_tableWidget->setColumnWidth(4, 65); // 深度列 m_tableWidget->setColumnWidth(5, 65); // 宽度列 m_tableWidget->setColumnWidth(6, 65); // 长度列 m_tableWidget->setColumnWidth(7, 100); // 时间列 #endif // 设置样式表 m_tableWidget->setStyleSheet( "QTableWidget {" " background-color: rgb(37,38,42);" " gridline-color: rgb(60,60,60);" " selection-background-color: rgb(80,80,80);" "}" "QTableWidget::item {" " color: white;" "}" "QHeaderView::section {" " background-color: rgb(45,45,45);" " color: white;" " padding: 4px;" "}" ); // 启用表格排序功能 m_tableWidget->setSortingEnabled(true); // 设置默认按ID列倒序排序 m_tableWidget->sortItems(1, Qt::DescendingOrder); } void TearingDataTableWidget::_AddDataToTable(const QString devName, const TearingData &data, int row) { QTableWidgetItem *nameItem = new QTableWidgetItem(devName); nameItem->setTextAlignment(Qt::AlignCenter); m_tableWidget->setItem(row, 0, nameItem); // 使用结构体数据填充表格,状态和类型显示中文,并设置居中对齐 NumericTableWidgetItem *idItem = new NumericTableWidgetItem(data.id); idItem->setTextAlignment(Qt::AlignCenter); // ID列文字居中显示 m_tableWidget->setItem(row, 1, idItem); QTableWidgetItem *statusItem = new QTableWidgetItem(getTearStatusText(data.tearStatus)); statusItem->setTextAlignment(Qt::AlignCenter); // 状态列文字居中显示 m_tableWidget->setItem(row, 2, statusItem); QTableWidgetItem *typeItem = new QTableWidgetItem(getTearTypeText(data.tearType)); typeItem->setTextAlignment(Qt::AlignCenter); // 类型列文字居中显示 m_tableWidget->setItem(row, 3, typeItem); m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearDepth)); m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearWidth)); m_tableWidget->setItem(row, 6, new QTableWidgetItem(data.tearLength)); // 添加时间列 QString currentTime = QString::fromStdString(CVrDateUtils::GetStrNowTime(false)); QTableWidgetItem *timeItem = new QTableWidgetItem(currentTime); timeItem->setTextAlignment(Qt::AlignCenter); m_tableWidget->setItem(row, 7, timeItem); // 设置item的文本颜色 for (int i = 0; i < m_tableWidget->horizontalHeader()->count(); i++) { QTableWidgetItem *item = m_tableWidget->item(row, i); if (item) { item->setForeground(QBrush(Qt::white)); } } } void TearingDataTableWidget::addData(const QString devName, const TearingData &data) { // 构造键值 QString key = devName + ":" + data.id; // 禁用排序以提高性能,批量处理后再启用 m_tableWidget->setSortingEnabled(false); // 查找是否已存在相同设备名称和ID的行 int existingRow = -1; if (m_devIdSet.contains(key)) { existingRow = findExistingRowById(devName, data.id); } int row; if (existingRow >= 0) { // 如果存在相同设备名称和ID,更新该行 row = existingRow; } else { // 如果不存在,插入新行 row = m_tableWidget->rowCount(); m_tableWidget->insertRow(row); // 添加到集合中 m_devIdSet.insert(key); } _AddDataToTable(devName, data, row); // 重新启用排序 m_tableWidget->setSortingEnabled(true); // 手动触发一次按ID列倒序排序 m_tableWidget->sortItems(1, Qt::DescendingOrder); // 检查是否需要限制行数 limitRowsIfNeeded(); } void TearingDataTableWidget::addData(const QString devName, const std::vector &dataList) { if (dataList.empty()) { return; } // 对于批量数据,禁用排序和更新以提高性能 m_tableWidget->setSortingEnabled(false); m_tableWidget->setUpdatesEnabled(false); // 遍历vector中的所有数据并添加到表格 for (const auto &data : dataList) { addData(devName, data); } // 重新启用更新和排序 m_tableWidget->setUpdatesEnabled(true); m_tableWidget->setSortingEnabled(true); // 手动触发一次按ID列倒序排序 m_tableWidget->sortItems(1, Qt::DescendingOrder); // 检查是否需要限制行数 limitRowsIfNeeded(); } void TearingDataTableWidget::addDataBatch(const QString devName, const std::vector &dataList) { if (dataList.empty()) { return; } // 对于大批量数据,采用更激进的优化策略 m_tableWidget->setSortingEnabled(false); m_tableWidget->setUpdatesEnabled(false); // 预先计算新行数 int currentRowCount = m_tableWidget->rowCount(); int newDataCount = dataList.size(); // 批量插入新行(如果有新数据需要插入) // 先找出需要新增的数据量 int rowsToAdd = 0; for (const auto &data : dataList) { QString key = devName + ":" + data.id; if (!m_devIdSet.contains(key)) { rowsToAdd++; } } // 批量插入新行 if (rowsToAdd > 0) { m_tableWidget->setRowCount(currentRowCount + rowsToAdd); } // 填充数据 for (const auto &data : dataList) { // 构造键值 QString key = devName + ":" + data.id; // 查找是否已存在相同设备名称和ID的行 int existingRow = -1; if (m_devIdSet.contains(key)) { existingRow = findExistingRowById(devName, data.id); } int row; if (existingRow >= 0) { // 如果存在相同设备名称和ID,更新该行 row = existingRow; } else { // 如果不存在,使用新行 row = m_tableWidget->rowCount() - rowsToAdd; rowsToAdd--; // 减少剩余需要分配的行数 // 添加到集合中 m_devIdSet.insert(key); } _AddDataToTable(devName, data, row); } // 重新启用更新和排序 m_tableWidget->setUpdatesEnabled(true); m_tableWidget->setSortingEnabled(true); // 手动触发一次按ID列倒序排序 m_tableWidget->sortItems(1, Qt::DescendingOrder); // 检查是否需要限制行数 limitRowsIfNeeded(); } void TearingDataTableWidget::clearData() { // 添加空指针检查,防止在m_tableWidget为nullptr时崩溃 if (m_tableWidget) { // 清除所有选择 m_tableWidget->clearSelection(); // 清除所有行数据 m_tableWidget->setRowCount(0); // 清空集合 m_devIdSet.clear(); // 重置排序状态,默认按ID列倒序排序 m_tableWidget->setSortingEnabled(false); m_tableWidget->setSortingEnabled(true); m_tableWidget->sortItems(1, Qt::DescendingOrder); } } void TearingDataTableWidget::setMaximumRows(int maxRows) { // 设置表格最大行数,防止内存占用过大 m_maxRows = maxRows; } void TearingDataTableWidget::removeRowFromSet(int row) { // 从表格中获取设备名称和ID if (row >= 0 && row < m_tableWidget->rowCount()) { QTableWidgetItem *devItem = m_tableWidget->item(row, 0); // 设备名称在第0列 QTableWidgetItem *idItem = m_tableWidget->item(row, 1); // ID在第1列 if (devItem && idItem) { QString key = devItem->text() + ":" + idItem->text(); m_devIdSet.remove(key); } } } void TearingDataTableWidget::limitRowsIfNeeded() { // 添加空指针检查,防止在m_tableWidget为nullptr时崩溃 if (!m_tableWidget) { return; } // 如果设置了最大行数限制,检查是否需要删除旧数据 if (m_maxRows > 0 && m_tableWidget->rowCount() > m_maxRows) { int rowsToDelete = m_tableWidget->rowCount() - m_maxRows; // 禁用更新以提高性能 m_tableWidget->setUpdatesEnabled(false); // 从后往前删除多余的行(假设新数据在后面) for (int i = 0; i < rowsToDelete; i++) { int rowToRemove = m_tableWidget->rowCount() - 1 - i; // 从集合中移除 removeRowFromSet(rowToRemove); m_tableWidget->removeRow(rowToRemove); } // 重新启用更新 m_tableWidget->setUpdatesEnabled(true); } } QString TearingDataTableWidget::getTearStatusText(const QString &status) { // 将ESG_tearStatus枚举值转换为中文显示 if (status == "0" || status.contains("Uknown")) { return "未知"; } else if (status == "1" || status.contains("New")) { return "新增"; } else if (status == "2" || status.contains("Growing")) { return "进行"; } else if (status == "3" || status.contains("Ended")) { return "结束"; } else if (status == "4" || status.contains("Invalid")) { return "无效"; } return status; // 如果无法识别,返回原值 } QString TearingDataTableWidget::getTearTypeText(const QString &type) { // 将ESG_tearType枚举值转换为中文显示 if (type == "0" || type.contains("Uknown")) { return "未知"; } else if (type == "1" || type.contains("MachineDir")) { return "纵撕"; } else if (type == "2" || type.contains("CrossWise")) { return "横撕"; } return type; // 如果无法识别,返回原值 } int TearingDataTableWidget::findExistingRowById(const QString &devName, const QString &id) { // 构造键值 QString key = devName + ":" + id; // 使用哈希表快速判断是否存在 if (!m_devIdSet.contains(key)) { return -1; // 不存在直接返回-1 } // 如果存在,则在表格中查找具体行号(虽然概率很小,但为了确保数据一致性仍需查找) int rowCount = m_tableWidget->rowCount(); for (int row = 0; row < rowCount; ++row) { QTableWidgetItem *devItem = m_tableWidget->item(row, 0); // 设备名称在第0列 QTableWidgetItem *idItem = m_tableWidget->item(row, 1); // ID在第1列 if (devItem && idItem && devItem->text() == devName && idItem->text() == id) { return row; } } return -1; // 未找到 } // NumericTableWidgetItem类的实现 NumericTableWidgetItem::NumericTableWidgetItem() : QTableWidgetItem() { } NumericTableWidgetItem::NumericTableWidgetItem(const QString &text) : QTableWidgetItem(text) { } bool NumericTableWidgetItem::operator<(const QTableWidgetItem &other) const { // 尝试将文本转换为数字进行比较 double thisValue = toDouble(); double otherValue = static_cast(&other)->toDouble(); // 如果两个值都有效,则按数字比较 if (thisValue != -1 && otherValue != -1) { return thisValue < otherValue; } // 否则按默认的字符串比较 return QTableWidgetItem::operator<(other); } QTableWidgetItem* NumericTableWidgetItem::clone() const { // 创建一个新的NumericTableWidgetItem实例并返回 return new NumericTableWidgetItem(text()); } double NumericTableWidgetItem::toDouble() const { bool ok; // 尝试直接转换为double double value = text().toDouble(&ok); if (ok) { return value; } // 如果直接转换失败,尝试提取数字部分 QRegExp rx("(\\d+)"); if (rx.indexIn(text()) != -1) { return rx.cap(1).toDouble(&ok); } // 如果所有方法都失败,返回-1表示无效值 return -1; }