XNSim/XNMonitor/ModelStatusWidget/ModelStatusWidget.cpp

681 lines
24 KiB
C++
Raw Normal View History

2025-04-28 12:25:20 +08:00
/**
* @file ModelStatusWidget.cpp
* @author jinchao
* @brief
* @version 1.0
* @date 2025-03-10
*
* @copyright Copyright (c) 2025 COMAC
*
*/
#include "ModelStatusWidget.h"
#include <QHBoxLayout>
#include <QScrollArea>
#include <QLabel>
#include <QGridLayout>
#include <QPushButton>
#include <QTableWidget>
#include <QHeaderView>
#include "../XNCustomPlot.h"
ModelStatusWidget::ModelStatusWidget(QWidget *parent, SystemStatusWidget *systemStatusWidget)
: QWidget(parent)
{
//初始化系统运行状态窗口指针
this->systemStatusWidget = systemStatusWidget;
//初始化模型状态标签页
setupTabModelStatus();
//初始化模型信息线程
InitialModelInfoThread();
}
ModelStatusWidget::~ModelStatusWidget()
{
//释放模型信息线程
if (modelThread != nullptr) {
modelThread->onThreadQuit();
modelThread->quit();
modelThread->wait();
delete modelThread;
modelThread = nullptr;
}
}
void ModelStatusWidget::onSetCurrentTabIndex(int index)
{
this->currentTabIndex = index;
if (currentTabIndex == 1) {
//如果当前选中的标签页为1则显示模型状态窗口
this->show();
//控制模型信息线程
emit controlModelInfoThread(true);
} else {
//如果当前选中的标签页为0则隐藏模型状态窗口
this->hide();
//控制模型信息线程
emit controlModelInfoThread(false);
}
}
void ModelStatusWidget::InitialModelInfoThread()
{
//初始化模型信息线程
modelThread = new ModelInfoUpdateThread(this);
//连接模型信息线程的更新模型信息信号到槽函数
connect(modelThread, &ModelInfoUpdateThread::updateModelInfo, this,
&ModelStatusWidget::updateModelData);
//连接模型信息线程的控制信号到槽函数
connect(this, &ModelStatusWidget::controlModelInfoThread, modelThread,
&ModelInfoUpdateThread::onThreadController);
//初始化模型信息线程
modelThread->Initialize();
//启动模型信息线程
modelThread->start();
}
// 设置模型状态标签页
void ModelStatusWidget::setupTabModelStatus()
{
QHBoxLayout *mainLayout = new QHBoxLayout(this); // 创建水平布局
// 使用QSplitter进行左右栏的动态分割
QSplitter *horizontalSplitter = new QSplitter(Qt::Horizontal); // 创建一个水平方向的QSplitter
// 左栏布局
setupTabModelStatusLeftPanel(horizontalSplitter);
// 右栏布局
setupTabModelStatusRightPanel(horizontalSplitter);
// 设置QSplitter的初始分割比例为1:4即左栏占五分之一右栏占五分之四
QList<int> sizes;
sizes << 1 << 4;
horizontalSplitter->setSizes(sizes);
// 将QSplitter添加到主布局中
mainLayout->addWidget(horizontalSplitter);
}
// 设置模型状态左栏的布局和组件
void ModelStatusWidget::setupTabModelStatusLeftPanel(QSplitter *splitter)
{
// 左栏布局
QVBoxLayout *leftMainLayout = new QVBoxLayout();
QWidget *leftMainWidget = new QWidget();
leftMainLayout->addWidget(leftMainWidget);
QVBoxLayout *leftLayout = new QVBoxLayout();
leftLayout->setObjectName("ModelStatusLeftLayout");
leftMainWidget->setLayout(leftLayout);
leftMainLayout->addStretch(); // 添加一个伸展项,使得布局可以自动调整大小
// 创建一个QWidget作为左栏的容器并设置其布局为leftLayout
QWidget *leftPanel = new QWidget();
leftPanel->setLayout(leftMainLayout);
// 创建一个QScrollArea来包含左栏的布局
QScrollArea *leftScrollArea = new QScrollArea(this);
leftScrollArea->setWidget(leftPanel);
leftScrollArea->setWidgetResizable(true);
leftScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
leftScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
// 将QScrollArea添加到QSplitter中
splitter->addWidget(leftScrollArea);
}
// 创建线程信息页面
QWidget *ModelStatusWidget::createThreadInfoPage(unsigned int threadIndex)
{
QWidget *page = new QWidget();
QGridLayout *gridLayout = new QGridLayout(page);
// 定义运行信息的标签和初始值
// 定义标签列表
const QStringList labels = {"线程ID", "运行状态", "运行周期数", "实时频率", "设定频率",
"最小频率", "最大频率", "平均频率", "实时周期", "设定周期",
"最小周期", "最大周期", "平均周期"};
// 定义值列表
const QStringList values = {"0", "未运行", "0", "0Hz", "0Hz", "0Hz", "0Hz",
"0Hz", "0ms", "0ms", "0ms", "0ms", "0ms"};
// 遍历标签和值列表为每个条目创建两个QLabel
for (int i = 0; i < labels.size(); ++i) {
QLabel *label = new QLabel(labels[i], page);
QLabel *valueLabel = new QLabel(values[i], page);
// 设置QLabel的对齐方式
// 设置标签对齐方式为左对齐
label->setAlignment(Qt::AlignLeft);
// 设置值标签对齐方式为右对齐
valueLabel->setAlignment(Qt::AlignRight);
// 设置valueLabel的objectName以便后续可以通过findChild找到并更新它
valueLabel->setObjectName(QString("threadRunValueLabel%1_%2").arg(threadIndex).arg(i));
// 将QLabel添加到网格布局中
// 在第i行第0列放置标签
gridLayout->addWidget(label, i, 0);
// 在第i行第1列放置值
gridLayout->addWidget(valueLabel, i, 1);
}
return page;
}
// 切换线程信息页面的显示状态
void ModelStatusWidget::toggleThreadInfo()
{
QPushButton *button = qobject_cast<QPushButton *>(sender());
if (button) {
QString buttonText = button->objectName();
int threadIndex = extractTrailingNumbers(buttonText, 3); // 提取数字部分作为线程索引
if (threadIndex < 0)
return;
QWidget *coreInfoPage = findChild<QWidget *>(QString("threadInfoPage%1").arg(threadIndex));
if (!coreInfoPage)
return;
coreInfoPage->setVisible(!coreInfoPage->isVisible());
}
}
// 设置模型状态右栏的布局和组件
void ModelStatusWidget::setupTabModelStatusRightPanel(QSplitter *splitter)
{
// 右栏布局
QVBoxLayout *rightLayout = new QVBoxLayout();
// 创建一个新的QSplitter用于垂直分割右栏的上下两部分
QSplitter *verticalSplitter = new QSplitter(Qt::Vertical); // 垂直方向的QSplitter
// 表格布局
QTableWidget *modelStatusTableWidget = new QTableWidget();
setupModelStatusTableWidget(modelStatusTableWidget);
// 图表绘制区域
QWidget *modelChartWidget = new QWidget(); // 图表区域可以使用XNCustomPlot等库进行绘制
setupModelStatusChartWidget(modelChartWidget); // 配置图表区域
// 将表格和图表添加到垂直分割器中
verticalSplitter->addWidget(modelStatusTableWidget);
verticalSplitter->addWidget(modelChartWidget);
QList<int> sizes;
sizes << 3 << 2;
verticalSplitter->setSizes(sizes);
// 将垂直分割器添加到右栏布局中
rightLayout->addWidget(verticalSplitter);
// 创建一个QWidget作为右栏的容器并设置其布局为rightLayout
QWidget *rightPanel = new QWidget();
rightPanel->setLayout(rightLayout);
// 将右栏容器添加到QSplitter中
splitter->addWidget(rightPanel);
}
// 设置模型状态表格
void ModelStatusWidget::setupModelStatusTableWidget(QTableWidget *tableWidget)
{
tableWidget->setRowCount(10); // 设置表格的行数
tableWidget->setColumnCount(15); // 设置表格的列数
QFont headerFont("Arial", 16, QFont::Bold);
tableWidget->horizontalHeader()->setFont(headerFont);
// 设置表格的列标题
tableWidget->setHorizontalHeaderLabels(
{"模型名称", "模型ID", "运行状态", "所属线程", "运行节点", "优先级", "设定频率", "最小频率",
"最大频率", "平均频率", "周期数", "设定周期", "最小周期", "最大周期", "平均周期"});
// 设置表格列宽自适应
tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
// 设置表格的选择行为为按行选择
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
// 设置表格的选择模式为单选
tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
// 设置表格不可编辑
tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 设置表格的objectName以便后续可以通过findChild找到并更新它
tableWidget->setObjectName("modelStatusTableWidget");
// 连接 threadStatusTableWidget 的 itemSelectionChanged 信号到槽函数
connect(tableWidget, &QTableWidget::itemSelectionChanged, this,
&ModelStatusWidget::onModelStatusTableSelectionChanged);
}
// 处理模型状态表格的选择变化
void ModelStatusWidget::onModelStatusTableSelectionChanged()
{
if (currentTabIndex != 1)
return;
QTableWidget *modelStatusTableWidget = findChild<QTableWidget *>("modelStatusTableWidget");
if (!modelStatusTableWidget) {
return;
}
int rowIndex = modelStatusTableWidget->currentRow();
if (rowIndex < 0 || rowIndex >= modelDataVec.size()) {
return;
}
XNCustomPlot *customPlot = findChild<XNCustomPlot *>("modelStatusCustomPlot");
if (!customPlot)
return; // 确保找到了XNCustomPlot对象
const XNRuntimeData &data = modelDataVec[rowIndex];
QVector<double> xData, yData;
if (freqOrPeriodIndex == 0 && data.m_CurrentPeriod.size() > 0) {
customPlot->xAxis->setRange(0, data.m_CurrentPeriod.size());
customPlot->yAxis->setRange(data.m_MinPeriod - 1, data.m_MaxPeriod + 1);
for (int i = 0; i < data.m_CurrentPeriod.size(); ++i) {
xData.push_back(i);
yData.push_back(data.m_CurrentPeriod[i]);
}
} else if (freqOrPeriodIndex == 1 && data.m_CurrentFrequency.size() > 0) {
customPlot->xAxis->setRange(0, data.m_CurrentFrequency.size());
customPlot->yAxis->setRange(data.m_MinFrequency - 1, data.m_MaxFrequency + 1);
for (int i = 0; i < data.m_CurrentFrequency.size(); ++i) {
xData.push_back(i);
yData.push_back(data.m_CurrentFrequency[i]);
}
} else {
return;
}
updatePlotData(xData, yData);
}
// 设置模型状态图表
void ModelStatusWidget::setupModelStatusChartWidget(QWidget *modelStatusChartWidget)
{
modelStatusChartWidget->setObjectName("modelStatusChartWidget");
XNCustomPlot *customPlot = new XNCustomPlot(modelStatusChartWidget);
customPlot->setObjectName("modelStatusCustomPlot");
// 设置图表布局
modelStatusChartWidget->setLayout(new QVBoxLayout());
modelStatusChartWidget->layout()->addWidget(customPlot);
// 配置图表
customPlot->setBackground(QBrush(QColor("#19232D")));
customPlot->xAxis->setLabelColor(Qt::white);
customPlot->yAxis->setLabelColor(Qt::white);
customPlot->xAxis->setLabel("时间(s)");
customPlot->yAxis->setLabel("周期(ms)");
customPlot->xAxis->setTickLabelRotation(60);
customPlot->xAxis->setTickLabelColor(Qt::white);
customPlot->yAxis->setTickLabelColor(Qt::white);
customPlot->xAxis->grid()->setVisible(true);
customPlot->yAxis->grid()->setVisible(true);
// 添加图表并设置绿色
customPlot->addGraph();
QPen greenPen(Qt::green);
greenPen.setWidth(2);
customPlot->graph(0)->setPen(greenPen);
// 为chartWidget设置上下文菜单
connect(customPlot, &XNCustomPlot::customContextMenuRequested, this,
&ModelStatusWidget::showChartContextMenu);
// 连接信号
connect(this, &ModelStatusWidget::updateModelCutomPlotData, this,
&ModelStatusWidget::onModelStatusTableSelectionChanged);
customPlot->replot();
}
// 处理图表中的右键点击事件
void ModelStatusWidget::showChartContextMenu(const QPoint &pos)
{
XNCustomPlot *customPlot = findChild<XNCustomPlot *>("modelStatusCustomPlot");
if (!customPlot)
return; // 确保找到了XNCustomPlot对象
QMenu contextMenu(this);
QAction *actionFrequency = contextMenu.addAction("显示频率");
QAction *actionPeriod = contextMenu.addAction("显示周期");
// 连接QAction的triggered信号到相应的槽函数
connect(actionFrequency, &QAction::triggered, this, &ModelStatusWidget::onShowFrequency);
connect(actionPeriod, &QAction::triggered, this, &ModelStatusWidget::onShowPeriod);
// 在chartWidget上显示上下文菜单
QAction *selectedAction = contextMenu.exec(customPlot->mapToGlobal(pos));
}
// 处理右键菜单中的"显示频率"选项
void ModelStatusWidget::onShowFrequency()
{
XNCustomPlot *customPlot = nullptr;
if (currentTabIndex == 1) {
customPlot = findChild<XNCustomPlot *>("modelStatusCustomPlot");
} else
return;
if (!customPlot)
return; // 确保找到了XNCustomPlot对象
// 实现显示频率的逻辑
customPlot->yAxis->setLabel("频率(Hz)");
freqOrPeriodIndex = 1;
customPlot->replot(); // 重新绘制图表以显示新数据
emit updateModelCutomPlotData();
}
// 处理右键菜单中的"显示周期"选项
void ModelStatusWidget::onShowPeriod()
{
XNCustomPlot *customPlot = nullptr;
if (currentTabIndex == 1) {
customPlot = findChild<XNCustomPlot *>("modelStatusCustomPlot");
} else
return;
if (!customPlot)
return; // 确保找到了XNCustomPlot对象
// 实现显示周期的逻辑
customPlot->yAxis->setLabel("周期(ms)");
freqOrPeriodIndex = 0;
customPlot->replot(); // 重新绘制图表以显示新数据
emit updateModelCutomPlotData();
}
// 更新线程信息页面
void ModelStatusWidget::updateThreadInfoPage(unsigned int threadIndex, const XNRuntimeData &data)
{
if (currentTabIndex != 1)
return;
QPushButton *threadInfoButton =
findChild<QPushButton *>(QString("threadInfoButton%1").arg(threadIndex));
if (NULL == threadInfoButton) {
QVBoxLayout *leftLayout = findChild<QVBoxLayout *>("ModelStatusLeftLayout");
if (NULL == leftLayout)
return;
threadInfoButton = new QPushButton(data.m_name);
threadInfoButton->setObjectName(QString("threadInfoButton%1").arg(threadIndex));
connect(threadInfoButton, &QPushButton::clicked, this,
&ModelStatusWidget::toggleThreadInfo);
leftLayout->addWidget(threadInfoButton);
QWidget *threadInfoPage = createThreadInfoPage(threadIndex);
threadInfoPage->setObjectName(QString("threadInfoPage%1").arg(threadIndex));
leftLayout->addWidget(threadInfoPage);
}
threadInfoButton->setText(data.m_name);
QWidget *threadInfoPage = findChild<QWidget *>(QString("threadInfoPage%1").arg(threadIndex));
if (threadInfoPage) {
updateThreadInfoValue(threadIndex, 0, QString::number(data.m_id));
switch (data.m_RunningState) {
case 0:
updateThreadInfoValue(threadIndex, 1, "未运行");
break;
case 1:
updateThreadInfoValue(threadIndex, 1, "运行中");
break;
case 2:
updateThreadInfoValue(threadIndex, 1, "暂停中");
break;
case 3:
updateThreadInfoValue(threadIndex, 1, "错误");
break;
default:
updateThreadInfoValue(threadIndex, 1, "未知状态");
break;
}
updateThreadInfoValue(threadIndex, 2, QString::number(data.m_CycleCount));
updateThreadInfoValue(
threadIndex, 3,
QString("%1 Hz").arg(data.m_CurrentFrequency[data.m_CurrentFrequency.size() - 1], 0,
'f', 2));
updateThreadInfoValue(threadIndex, 4, QString("%1 Hz").arg(data.m_SetFrequency, 0, 'f', 2));
updateThreadInfoValue(threadIndex, 5, QString("%1 Hz").arg(data.m_MinFrequency, 0, 'f', 2));
updateThreadInfoValue(threadIndex, 6, QString("%1 Hz").arg(data.m_MaxFrequency, 0, 'f', 2));
updateThreadInfoValue(threadIndex, 7, QString("%1 Hz").arg(data.m_AvgFrequency, 0, 'f', 2));
updateThreadInfoValue(
threadIndex, 8,
QString("%1 ms").arg(data.m_CurrentPeriod[data.m_CurrentPeriod.size() - 1], 0, 'f', 2));
updateThreadInfoValue(threadIndex, 9, QString("%1 ms").arg(data.m_SetPeriod, 0, 'f', 2));
updateThreadInfoValue(threadIndex, 10, QString("%1 ms").arg(data.m_SetPeriod, 0, 'f', 2));
updateThreadInfoValue(threadIndex, 11, QString("%1 ms").arg(data.m_MaxPeriod, 0, 'f', 2));
updateThreadInfoValue(threadIndex, 12, QString("%1 ms").arg(data.m_AvgPeriod, 0, 'f', 2));
}
}
// 更新线程信息值
void ModelStatusWidget::updateThreadInfoValue(unsigned int threadIndex, int index,
const QString &newValue)
{
if (currentTabIndex != 1)
return;
QLabel *valueLabel =
findChild<QLabel *>(QString("threadRunValueLabel%1_%2").arg(threadIndex).arg(index));
if (valueLabel) {
valueLabel->setText(newValue);
if (1 == index) {
if (newValue == "未运行") {
valueLabel->setStyleSheet("color: gray;");
} else if (newValue == "运行中") {
valueLabel->setStyleSheet("color: green;");
} else if (newValue == "暂停中") {
valueLabel->setStyleSheet("color: orange;");
} else if (newValue == "错误") {
valueLabel->setStyleSheet("color: red;");
} else {
valueLabel->setText("未知状态");
valueLabel->setStyleSheet("color: red;");
}
}
}
}
// 更新图表数据
void ModelStatusWidget::updatePlotData(const QVector<double> &newXData,
const QVector<double> &newYData)
{
XNCustomPlot *customPlot = nullptr;
if (currentTabIndex == 1)
customPlot = findChild<XNCustomPlot *>("modelStatusCustomPlot");
else if (currentTabIndex == 2)
customPlot = findChild<XNCustomPlot *>("dataMonitoringCustomPlot");
else
return;
if (!customPlot)
return; // 确保找到了XNCustomPlot对象
if (customPlot->graphCount() == 1) {
// 假设我们只有一个图形
customPlot->graph(0)->setData(newXData, newYData);
customPlot->replot(); // 重新绘制图表以显示新数据
} else {
customPlot->addGraph(); // 添加一个新的图形
customPlot->graph(0)->setData(newXData, newYData);
customPlot->replot(); // 重新绘制图表以显示新数据
}
}
// 更新模型数据
void ModelStatusWidget::updateModelData(const XNRuntimeData &data)
{
// 如果当前标签页不是第二个,则直接返回
if (currentTabIndex != 1)
return;
// 遍历 modelDataVec 向量
for (size_t i = 0; i < modelDataVec.size(); i++) {
// 如果当前遍历到的元素 ID 与传入数据的 ID 相同
if (data.m_id == modelDataVec[i].m_id) {
double currectFrequency = data.m_CurrentFrequency[0]; // 当前频率
double currentPeriod = data.m_CurrentPeriod[0]; // 当前周期
// 更新模型运行状态
modelDataVec[i].m_RunningState = data.m_RunningState;
// 如果模型不是运行状态,则不更新频率和周期数据
if (data.m_RunningState != 1)
return;
// 更新当前频率
modelDataVec[i].m_CurrentFrequency.push_back(currectFrequency);
// 更新当前周期
modelDataVec[i].m_CurrentPeriod.push_back(currentPeriod);
// 更新周期计数
modelDataVec[i].m_CycleCount = data.m_CycleCount;
// 更新最小频率
modelDataVec[i].m_MinFrequency =
std::min(currectFrequency, modelDataVec[i].m_MinFrequency);
// 更新最大频率
modelDataVec[i].m_MaxFrequency =
std::max(currectFrequency, modelDataVec[i].m_MaxFrequency);
// 更新平均频率
modelDataVec[i].m_AvgFrequency =
((data.m_CycleCount - 1) * modelDataVec[i].m_AvgFrequency + currectFrequency)
/ data.m_CycleCount;
// 更新最小周期
modelDataVec[i].m_MinPeriod = std::min(currentPeriod, modelDataVec[i].m_MinPeriod);
// 更新最大周期
modelDataVec[i].m_MaxPeriod = std::max(currentPeriod, modelDataVec[i].m_MaxPeriod);
// 更新平均周期
modelDataVec[i].m_AvgPeriod =
((data.m_CycleCount - 1) * modelDataVec[i].m_AvgPeriod + currentPeriod)
/ data.m_CycleCount;
// 如果当前频率或周期向量的长度超过100移除最前面的元素
if (modelDataVec[i].m_CurrentFrequency.size() > 100) {
modelDataVec[i].m_CurrentFrequency.pop_front();
modelDataVec[i].m_CurrentPeriod.pop_front();
}
// 检查当前选中的行是否是被更新的行
// 找到名为 "modelStatusTableWidget" 的子控件
QTableWidget *modelStatusTableWidget =
findChild<QTableWidget *>("modelStatusTableWidget");
if (modelStatusTableWidget) {
int currentRow = modelStatusTableWidget->currentRow();
if (currentRow == static_cast<int>(i)) {
emit updateModelCutomPlotData();
}
}
// 更新表格数据
updateModelTableData(modelDataVec[i], i);
return;
}
}
// 如果未找到匹配的 ID将传入的数据添加到 modelDataVec 向量末尾
modelDataVec.push_back(data);
// 更新表格数据
updateModelTableData(data, modelDataVec.size() - 1);
}
// 更新模型表格数据
void ModelStatusWidget::updateModelTableData(const XNRuntimeData &data, int rowIndex)
{
// 如果当前标签页索引不为1则直接返回
if (currentTabIndex != 1)
return;
// 查找名为"threadStatusTableWidget"的QTableWidget
QTableWidget *modelStatusTableWidget = findChild<QTableWidget *>("modelStatusTableWidget");
if (!modelStatusTableWidget) {
// 如果没有找到,则直接返回
return;
}
// 设置表格的行数
modelStatusTableWidget->setRowCount(std::max(rowIndex + 1, (int)modelDataVec.size()));
// 设置模型名称
modelStatusTableWidget->setItem(rowIndex, 0, new QTableWidgetItem(data.m_name));
// 设置模型ID
modelStatusTableWidget->setItem(rowIndex, 1, new QTableWidgetItem(QString::number(data.m_id)));
// 根据模型的运行状态设置不同的状态显示
switch (data.m_RunningState) {
case 0:
// 未运行状态
modelStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("未运行"));
modelStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::gray));
break;
case 1:
// 运行中状态
modelStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("运行中"));
modelStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::green));
break;
case 2:
// 暂停中状态
modelStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("暂停中"));
modelStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::yellow));
break;
default:
// 未知状态
modelStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("未知状态"));
modelStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::red));
break;
}
// 设置所属线程
if (systemStatusWidget != nullptr) {
modelStatusTableWidget->setItem(
rowIndex, 3,
new QTableWidgetItem(systemStatusWidget->getThreadName(data.m_AffinityMask)));
} else {
modelStatusTableWidget->setItem(rowIndex, 3, new QTableWidgetItem("未知线程"));
}
// 设置节点号
modelStatusTableWidget->setItem(rowIndex, 4,
new QTableWidgetItem(QString::number(data.m_NodeID)));
// 设置模型优先级
modelStatusTableWidget->setItem(rowIndex, 5,
new QTableWidgetItem(QString::number(data.m_Priority)));
// 设置模型设置频率
modelStatusTableWidget->setItem(
rowIndex, 6, new QTableWidgetItem(QString::number(data.m_SetFrequency, 'f', 2) + " Hz"));
// 设置模型最小频率
modelStatusTableWidget->setItem(
rowIndex, 7, new QTableWidgetItem(QString::number(data.m_MinFrequency, 'f', 2) + " Hz"));
// 设置模型最大频率
modelStatusTableWidget->setItem(
rowIndex, 8, new QTableWidgetItem(QString::number(data.m_MaxFrequency, 'f', 2) + " Hz"));
// 设置模型平均频率
modelStatusTableWidget->setItem(
rowIndex, 9, new QTableWidgetItem(QString::number(data.m_AvgFrequency, 'f', 2) + " Hz"));
// 设置模型周期计数
modelStatusTableWidget->setItem(rowIndex, 10,
new QTableWidgetItem(QString::number(data.m_CycleCount)));
// 设置模型设置周期
modelStatusTableWidget->setItem(
rowIndex, 11, new QTableWidgetItem(QString::number(data.m_SetPeriod, 'f', 2) + " ms"));
// 设置模型最小周期
modelStatusTableWidget->setItem(
rowIndex, 12, new QTableWidgetItem(QString::number(data.m_MinPeriod, 'f', 2) + " ms"));
// 设置模型最大周期
modelStatusTableWidget->setItem(
rowIndex, 13, new QTableWidgetItem(QString::number(data.m_MaxPeriod, 'f', 2) + " ms"));
// 设置模型平均周期
modelStatusTableWidget->setItem(
rowIndex, 14, new QTableWidgetItem(QString::number(data.m_AvgPeriod, 'f', 2) + " ms"));
}
// 提取字符串末尾的数字
int ModelStatusWidget::extractTrailingNumbers(const QString &str, int count)
{
QRegularExpression re("\\d{1," + QString::number(count) + "}$");
QRegularExpressionMatch match = re.match(str);
if (match.hasMatch()) {
return match.captured().toInt();
} else {
return -1; // 如果没有找到匹配项,则返回一个-1
}
}