GrabBag/App/BeltTearing/BeltTearingApp/widgets/TearingDataTableWidget.cpp

440 lines
14 KiB
C++
Raw Permalink 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.

#include "TearingDataTableWidget.h"
#include <QVBoxLayout>
#include <QHeaderView>
#include <QTableWidgetItem>
#include <QBrush>
#include <QColor>
#include <QApplication>
#include <QStyle>
#include <QRegExp>
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<TearingData> &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<TearingData> &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<const NumericTableWidgetItem*>(&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;
}