GrabBag/App/BeltTearing/BeltTearingApp/widgets/TearingDataTableWidget.cpp
2025-09-29 00:56:53 +08:00

397 lines
13 KiB
C++
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.

#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)
{
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 << "ID" << "状态" << "类型" << "深度(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, 62); // ID列
m_tableWidget->setColumnWidth(1, 100); // 状态列
m_tableWidget->setColumnWidth(2, 80); // 类型列
m_tableWidget->setColumnWidth(3, 100); // 深度列
m_tableWidget->setColumnWidth(4, 100); // 宽度列
m_tableWidget->setColumnWidth(5, 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(0, Qt::AscendingOrder);
}
void TearingDataTableWidget::addData(const TearingData &data)
{
// 禁用排序以提高性能,批量处理后再启用
m_tableWidget->setSortingEnabled(false);
// 查找是否已存在相同ID的行
int existingRow = findExistingRowById(data.id);
int row;
if (existingRow >= 0) {
// 如果存在相同ID更新该行
row = existingRow;
} else {
// 如果不存在,插入新行
row = m_tableWidget->rowCount();
m_tableWidget->insertRow(row);
}
// 使用结构体数据填充表格,状态和类型显示中文,并设置居中对齐
NumericTableWidgetItem *idItem = new NumericTableWidgetItem(data.id);
idItem->setTextAlignment(Qt::AlignCenter); // ID列文字居中显示
m_tableWidget->setItem(row, 0, idItem);
QTableWidgetItem *statusItem = new QTableWidgetItem(getTearStatusText(data.tearStatus));
statusItem->setTextAlignment(Qt::AlignCenter); // 状态列文字居中显示
m_tableWidget->setItem(row, 1, statusItem);
QTableWidgetItem *typeItem = new QTableWidgetItem(getTearTypeText(data.tearType));
typeItem->setTextAlignment(Qt::AlignCenter); // 类型列文字居中显示
m_tableWidget->setItem(row, 2, typeItem);
m_tableWidget->setItem(row, 3, new QTableWidgetItem(data.tearDepth));
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearWidth));
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearLength));
// m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.statLineIdx));
// 设置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));
}
}
// 重新启用排序
m_tableWidget->setSortingEnabled(true);
// 检查是否需要限制行数
limitRowsIfNeeded();
}
void TearingDataTableWidget::addData(const std::vector<TearingData> &dataList)
{
if (dataList.empty()) {
return;
}
// 对于批量数据,禁用排序和更新以提高性能
m_tableWidget->setSortingEnabled(false);
m_tableWidget->setUpdatesEnabled(false);
// 遍历vector中的所有数据并添加到表格
for (const auto &data : dataList) {
addData(data);
}
// 重新启用更新和排序
m_tableWidget->setUpdatesEnabled(true);
m_tableWidget->setSortingEnabled(true);
// 手动触发一次排序
m_tableWidget->sortItems(0, Qt::AscendingOrder);
// 检查是否需要限制行数
limitRowsIfNeeded();
}
void TearingDataTableWidget::addDataBatch(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) {
if (findExistingRowById(data.id) < 0) {
rowsToAdd++;
}
}
// 批量插入新行
if (rowsToAdd > 0) {
m_tableWidget->setRowCount(currentRowCount + rowsToAdd);
}
// 填充数据
for (const auto &data : dataList) {
// 查找是否已存在相同ID的行
int existingRow = findExistingRowById(data.id);
int row;
if (existingRow >= 0) {
// 如果存在相同ID更新该行
row = existingRow;
} else {
// 如果不存在,使用新行
row = m_tableWidget->rowCount() - rowsToAdd;
rowsToAdd--; // 减少剩余需要分配的行数
}
// 使用结构体数据填充表格,状态和类型显示中文,并设置居中对齐
NumericTableWidgetItem *idItem = new NumericTableWidgetItem(data.id);
idItem->setTextAlignment(Qt::AlignCenter); // ID列文字居中显示
m_tableWidget->setItem(row, 0, idItem);
QTableWidgetItem *statusItem = new QTableWidgetItem(getTearStatusText(data.tearStatus));
statusItem->setTextAlignment(Qt::AlignCenter); // 状态列文字居中显示
m_tableWidget->setItem(row, 1, statusItem);
QTableWidgetItem *typeItem = new QTableWidgetItem(getTearTypeText(data.tearType));
typeItem->setTextAlignment(Qt::AlignCenter); // 类型列文字居中显示
m_tableWidget->setItem(row, 2, typeItem);
m_tableWidget->setItem(row, 3, new QTableWidgetItem(data.tearDepth));
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearWidth));
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearLength));
// 设置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));
}
}
}
// 重新启用更新和排序
m_tableWidget->setUpdatesEnabled(true);
m_tableWidget->setSortingEnabled(true);
// 手动触发一次排序
m_tableWidget->sortItems(0, Qt::AscendingOrder);
}
void TearingDataTableWidget::addData(const QJsonObject &json)
{
// 添加空指针检查防止在m_tableWidget为nullptr时崩溃
if (!m_tableWidget) {
return;
}
TearingData data = TearingData::fromJsonObject(json);
addData(data);
}
void TearingDataTableWidget::clearData()
{
// 添加空指针检查防止在m_tableWidget为nullptr时崩溃
if (m_tableWidget) {
// 清除所有选择
m_tableWidget->clearSelection();
// 清除所有行数据
m_tableWidget->setRowCount(0);
// 重置排序状态
m_tableWidget->setSortingEnabled(false);
m_tableWidget->setSortingEnabled(true);
}
}
void TearingDataTableWidget::setMaximumRows(int maxRows)
{
// 设置表格最大行数,防止内存占用过大
// m_maxRows = maxRows;
}
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++) {
m_tableWidget->removeRow(0);
}
// 重新启用更新
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 &id)
{
// 在表格中查找具有相同ID的行
// 使用二分查找优化性能假设表格按ID排序
int rowCount = m_tableWidget->rowCount();
if (rowCount == 0) {
return -1;
}
// 简单的线性查找(在实际应用中,如果数据量很大,可以考虑使用哈希表或其他数据结构来优化)
for (int row = 0; row < rowCount; ++row) {
QTableWidgetItem *item = m_tableWidget->item(row, 0); // ID在第0列
if (item && item->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;
}