796 lines
28 KiB
C++
Executable File
796 lines
28 KiB
C++
Executable File
/**
|
||
* @file SystemStatusWidget.cpp
|
||
* @author jinchao
|
||
* @brief 系统运行状态窗口类实现
|
||
* @version 1.0
|
||
* @date 2025-03-10
|
||
*
|
||
* @copyright Copyright (c) 2025 COMAC
|
||
*
|
||
*/
|
||
#include "SystemStatusWidget.h"
|
||
#include <QHBoxLayout>
|
||
#include <QSplitter>
|
||
#include <QList>
|
||
#include <QPushButton>
|
||
#include <QScrollArea>
|
||
#include <QGridLayout>
|
||
#include <QLabel>
|
||
#include <QVBoxLayout>
|
||
#include <QHeaderView>
|
||
#include <QTableWidget>
|
||
#include <QAbstractItemView>
|
||
#include <QFont>
|
||
#include <QMutexLocker>
|
||
|
||
SystemStatusWidget::SystemStatusWidget(QWidget *parent)
|
||
: QWidget(parent), engineInfoPage(nullptr), coreInfoPage(nullptr),
|
||
threadStatusTableWidget(nullptr), systemStatusChartWidget(nullptr), customPlot(nullptr),
|
||
currentTabIndex(0), freqOrPeriodIndex(0), labelXNEngine(nullptr),
|
||
labelProcessIDValue(nullptr), labelStatusValue(nullptr), labelAffinityValue(nullptr),
|
||
labelThreadCountValue(nullptr), threadInfoThread(nullptr)
|
||
{
|
||
// 初始化系统状态窗口
|
||
setupTabSystemStatus();
|
||
// 初始化线程信息更新线程
|
||
InitializeThreadInfoThread();
|
||
}
|
||
|
||
SystemStatusWidget::~SystemStatusWidget()
|
||
{
|
||
if (threadInfoThread != nullptr) {
|
||
// 断开所有信号槽连接
|
||
disconnect(threadInfoThread, nullptr, this, nullptr);
|
||
disconnect(this, nullptr, threadInfoThread, nullptr);
|
||
|
||
// 发送退出信号并等待线程结束
|
||
threadInfoThread->onThreadQuit();
|
||
threadInfoThread->quit();
|
||
threadInfoThread->wait();
|
||
}
|
||
}
|
||
|
||
void SystemStatusWidget::onSetCurrentTabIndex(int index)
|
||
{
|
||
// 设置当前选中的标签页索引
|
||
this->currentTabIndex = index;
|
||
if (currentTabIndex == 0) {
|
||
// 如果当前选中的标签页索引为0,则显示系统运行状态窗口,并控制线程信息更新线程
|
||
this->show();
|
||
emit controlThreadInfoThread(true);
|
||
} else if (currentTabIndex == 1) {
|
||
// 如果当前选中的标签页索引为1,则隐藏系统运行状态窗口,并控制线程信息更新线程
|
||
this->hide();
|
||
emit controlThreadInfoThread(true);
|
||
} else {
|
||
// 如果当前选中的标签页索引为其他,则隐藏系统运行状态窗口,并控制线程信息更新线程
|
||
this->hide();
|
||
emit controlThreadInfoThread(false);
|
||
}
|
||
}
|
||
|
||
void SystemStatusWidget::InitializeThreadInfoThread()
|
||
{
|
||
// 初始化线程信息更新线程
|
||
threadInfoThread = new SystemInfoUpdateThread(this);
|
||
// 连接线程信息更新线程的信号和槽函数
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateThreadInfo, this,
|
||
&SystemStatusWidget::updateThreadData);
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateEngineName, this,
|
||
&SystemStatusWidget::updateProcessName);
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateEngineID, this,
|
||
&SystemStatusWidget::updateProcessID);
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateEngineStatus, this,
|
||
&SystemStatusWidget::updateEngineStatus);
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateCoreStatus, this,
|
||
&SystemStatusWidget::updateCoreStatus);
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateThreadCount, this,
|
||
&SystemStatusWidget::updateThreadCount);
|
||
connect(threadInfoThread, &SystemInfoUpdateThread::updateAffinity, this,
|
||
&SystemStatusWidget::updateAffinity);
|
||
connect(this, &SystemStatusWidget::controlThreadInfoThread, threadInfoThread,
|
||
&SystemInfoUpdateThread::onThreadController);
|
||
// 初始化线程信息更新线程
|
||
threadInfoThread->Initialize();
|
||
// 启动线程信息更新线程
|
||
threadInfoThread->start();
|
||
}
|
||
|
||
// 设置 tabSystemStatus 的布局和组件
|
||
void SystemStatusWidget::setupTabSystemStatus()
|
||
{
|
||
QHBoxLayout *mainLayout = new QHBoxLayout(this); // 创建水平布局
|
||
// 使用QSplitter进行左右栏的动态分割
|
||
QSplitter *horizontalSplitter =
|
||
new QSplitter(Qt::Horizontal, this); // 创建一个水平方向的QSplitter
|
||
|
||
// 左栏布局
|
||
setupTabSystemStatusLeftPanel(horizontalSplitter);
|
||
|
||
// 右栏布局
|
||
setupTabSystemStatusRightPanel(horizontalSplitter);
|
||
|
||
// 设置QSplitter的初始分割比例为1:4,即左栏占五分之一,右栏占五分之四
|
||
QList<int> sizes;
|
||
sizes << 1 << 4;
|
||
horizontalSplitter->setSizes(sizes);
|
||
|
||
// 将QSplitter添加到主布局中
|
||
mainLayout->addWidget(horizontalSplitter);
|
||
}
|
||
|
||
//设置 tabSystemStatus 左栏的布局和组件
|
||
void SystemStatusWidget::setupTabSystemStatusLeftPanel(QSplitter *splitter)
|
||
{
|
||
// 左栏布局
|
||
QVBoxLayout *leftLayout = new QVBoxLayout();
|
||
|
||
// 创建引擎信息的 QStackedWidget 和按钮
|
||
// 创建引擎信息的按钮
|
||
QPushButton *engineInfoButton = new QPushButton("引擎信息", this);
|
||
leftLayout->addWidget(engineInfoButton);
|
||
// 创建或获取 "引擎信息" 页面的 widget
|
||
engineInfoPage = createEngineInfoPage();
|
||
leftLayout->addWidget(engineInfoPage);
|
||
|
||
// 创建内核信息的 QStackedWidget 和按钮
|
||
// 创建内核信息的按钮
|
||
QPushButton *coreInfoButton = new QPushButton("内核信息", this);
|
||
leftLayout->addWidget(coreInfoButton);
|
||
// 创建或获取 "内核信息" 页面的 widget
|
||
coreInfoPage = createCoreInfoPage();
|
||
leftLayout->addWidget(coreInfoPage);
|
||
|
||
// 连接按钮的 clicked 信号到槽函数
|
||
connect(engineInfoButton, &QPushButton::clicked, this, &SystemStatusWidget::toggleEngineInfo);
|
||
connect(coreInfoButton, &QPushButton::clicked, this, &SystemStatusWidget::toggleCoreInfo);
|
||
|
||
leftLayout->addStretch(); // 添加一个伸展项,使得布局可以自动调整大小
|
||
|
||
// 创建一个QWidget作为左栏的容器,并设置其布局为leftLayout
|
||
QWidget *leftPanel = new QWidget(this);
|
||
leftPanel->setLayout(leftLayout);
|
||
|
||
// 创建一个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);
|
||
}
|
||
|
||
// 创建包含 QLabel 的引擎信息页面
|
||
QWidget *SystemStatusWidget::createEngineInfoPage()
|
||
{
|
||
QWidget *page = new QWidget(this);
|
||
QGridLayout *gridLayout = new QGridLayout(page);
|
||
|
||
// 创建 QLabel 并设置文本和对齐方式
|
||
QLabel *labelProcessName = new QLabel("进程名称", page); // 进程名称标签
|
||
labelXNEngine = new QLabel("XNEngine", page); // XNEngine标签
|
||
QLabel *labelProcessID = new QLabel("进程ID", page); // 进程ID标签
|
||
labelProcessIDValue = new QLabel("0000", page); // 进程ID值标签
|
||
QLabel *labelStatus = new QLabel("运行状态", page); // 运行状态标签
|
||
labelStatusValue = new QLabel("未运行", page); // 运行状态值标签
|
||
QLabel *labelAffinity = new QLabel("CPU亲和性", page); // CPU亲和性标签
|
||
labelAffinityValue = new QLabel("0", page); // CPU亲和性值标签
|
||
QLabel *labelThreadCount = new QLabel("线程数", page); // 线程数标签
|
||
labelThreadCountValue = new QLabel("0", page); // 线程数值标签
|
||
// 设置第一列 QLabel 左对齐
|
||
labelProcessName->setAlignment(Qt::AlignLeft); // 进程名称标签左对齐
|
||
labelProcessID->setAlignment(Qt::AlignLeft); // 进程ID标签左对齐
|
||
labelStatus->setAlignment(Qt::AlignLeft); // 运行状态标签左对齐
|
||
labelAffinity->setAlignment(Qt::AlignLeft); // CPU亲和性标签左对齐
|
||
labelThreadCount->setAlignment(Qt::AlignLeft); // 线程数标签左对齐
|
||
|
||
// 设置第二列 QLabel 右对齐
|
||
labelXNEngine->setAlignment(Qt::AlignRight); // XNEngine标签右对齐
|
||
labelProcessIDValue->setAlignment(Qt::AlignRight); // 进程ID值标签右对齐
|
||
labelStatusValue->setAlignment(Qt::AlignRight); // 运行状态值标签右对齐
|
||
labelAffinityValue->setAlignment(Qt::AlignRight); // CPU亲和性值标签右对齐
|
||
labelThreadCountValue->setAlignment(Qt::AlignRight); // 线程数值标签右对齐
|
||
|
||
// 如果状态为 "未运行",则设置灰色文本
|
||
if (labelStatusValue->text() == "未运行") {
|
||
labelStatusValue->setStyleSheet("color: gray;"); // 设置灰色文本
|
||
}
|
||
|
||
// 将 QLabel 添加到网格布局中
|
||
gridLayout->addWidget(labelProcessName, 0, 0); // 将进程名称标签添加到网格布局中,位于第0行第0列
|
||
gridLayout->addWidget(labelXNEngine, 0, 1); // 将XNEngine标签添加到网格布局中,位于第0行第1列
|
||
gridLayout->addWidget(labelProcessID, 1, 0); // 将进程ID标签添加到网格布局中,位于第1行第0列
|
||
gridLayout->addWidget(labelProcessIDValue, 1,
|
||
1); // 将进程ID值标签添加到网格布局中,位于第1行第1列
|
||
gridLayout->addWidget(labelStatus, 2, 0); // 将运行状态标签添加到网格布局中,位于第2行第0列
|
||
gridLayout->addWidget(labelStatusValue, 2,
|
||
1); // 将运行状态值标签添加到网格布局中,位于第2行第1列
|
||
gridLayout->addWidget(labelAffinity, 3, 0); // 将CPU亲和性标签添加到网格布局中,位于第3行第0列
|
||
gridLayout->addWidget(labelAffinityValue, 3,
|
||
1); // 将CPU亲和性值标签添加到网格布局中,位于第3行第1列
|
||
gridLayout->addWidget(labelThreadCount, 4, 0); // 将线程数标签添加到网格布局中,位于第4行第0列
|
||
gridLayout->addWidget(labelThreadCountValue, 4,
|
||
1); // 将线程数值标签添加到网格布局中,位于第4行第1列
|
||
|
||
return page;
|
||
}
|
||
|
||
// 创建包含 QLabel 的内核信息页面
|
||
QWidget *SystemStatusWidget::createCoreInfoPage()
|
||
{
|
||
QWidget *page = new QWidget(this);
|
||
QGridLayout *gridLayout = new QGridLayout(page);
|
||
|
||
// 定义管理器名称和状态
|
||
// 定义管理器名称列表
|
||
const QStringList managerNames = {"主框架", "时间管理器", "事件管理器", "场景描述管理器",
|
||
"线程管理器", "模型管理器", "服务管理器", "DDS管理器"};
|
||
const QString initialStatus = "未加载";
|
||
|
||
// 遍历管理器名称列表,为每个管理器创建两个QLabel
|
||
for (int i = 0; i < managerNames.size(); ++i) {
|
||
QLabel *managerLabel = new QLabel(managerNames[i], page);
|
||
QLabel *statusLabel = new QLabel(initialStatus, page);
|
||
|
||
// 设置QLabel的对齐方式
|
||
// 设置管理器名称标签左对齐
|
||
managerLabel->setAlignment(Qt::AlignLeft);
|
||
// 设置状态标签右对齐
|
||
statusLabel->setAlignment(Qt::AlignRight);
|
||
|
||
// 设置状态标签的初始文本颜色为灰色
|
||
statusLabel->setStyleSheet("color: gray;");
|
||
|
||
// 设置状态标签的objectName,以便后续可以通过findChild找到它们
|
||
statusLabel->setObjectName(QString("coreStatusLabel%1").arg(i));
|
||
|
||
// 将QLabel添加到网格布局中
|
||
// 第一列放置管理器名称
|
||
gridLayout->addWidget(managerLabel, i, 0);
|
||
// 第二列放置状态
|
||
gridLayout->addWidget(statusLabel, i, 1);
|
||
}
|
||
|
||
return page;
|
||
}
|
||
|
||
// 切换引擎信息的显示状态
|
||
void SystemStatusWidget::toggleEngineInfo()
|
||
{
|
||
if (engineInfoPage == nullptr)
|
||
return;
|
||
engineInfoPage->setVisible(!engineInfoPage->isVisible());
|
||
}
|
||
|
||
// 切换内核信息的显示状态
|
||
void SystemStatusWidget::toggleCoreInfo()
|
||
{
|
||
if (coreInfoPage == nullptr)
|
||
return;
|
||
coreInfoPage->setVisible(!coreInfoPage->isVisible());
|
||
}
|
||
|
||
//设置 tabSystemStatus 右栏的布局和组件
|
||
void SystemStatusWidget::setupTabSystemStatusRightPanel(QSplitter *splitter)
|
||
{
|
||
// 右栏布局
|
||
QVBoxLayout *rightLayout = new QVBoxLayout();
|
||
|
||
// 创建一个新的QSplitter用于垂直分割右栏的上下两部分
|
||
QSplitter *verticalSplitter = new QSplitter(Qt::Vertical, this); // 垂直方向的QSplitter
|
||
|
||
// 表格布局
|
||
setupSystemStatusTableWidget();
|
||
|
||
// 图表绘制区域
|
||
setupSystemStatusChartWidget();
|
||
|
||
// 将表格和图表添加到垂直分割器中
|
||
if (threadStatusTableWidget != nullptr) {
|
||
verticalSplitter->addWidget(threadStatusTableWidget);
|
||
}
|
||
if (systemStatusChartWidget != nullptr) {
|
||
verticalSplitter->addWidget(systemStatusChartWidget);
|
||
}
|
||
|
||
QList<int> sizes;
|
||
sizes << 3 << 2;
|
||
verticalSplitter->setSizes(sizes);
|
||
|
||
// 将垂直分割器添加到右栏布局中
|
||
rightLayout->addWidget(verticalSplitter);
|
||
|
||
// 创建一个QWidget作为右栏的容器,并设置其布局为rightLayout
|
||
QWidget *rightPanel = new QWidget(this);
|
||
rightPanel->setLayout(rightLayout);
|
||
|
||
// 将右栏容器添加到QSplitter中
|
||
splitter->addWidget(rightPanel);
|
||
}
|
||
|
||
// 设置线程运行状态表格
|
||
void SystemStatusWidget::setupSystemStatusTableWidget()
|
||
{
|
||
threadStatusTableWidget = new QTableWidget(this);
|
||
|
||
threadStatusTableWidget->setRowCount(10); // 设置表格的行数
|
||
threadStatusTableWidget->setColumnCount(14); // 设置表格的列数
|
||
|
||
QFont headerFont("Arial", 16, QFont::Bold);
|
||
threadStatusTableWidget->horizontalHeader()->setFont(headerFont);
|
||
|
||
// 设置表格的列标题
|
||
threadStatusTableWidget->setHorizontalHeaderLabels(
|
||
{"线程名称", "线程ID", "运行状态", "CPU亲和性", "优先级", "设定频率", "最小频率",
|
||
"最大频率", "平均频率", "周期数", "设定周期", "最小周期", "最大周期", "平均周期"});
|
||
|
||
// 设置表格列宽自适应
|
||
threadStatusTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
||
|
||
// 设置表格的选择行为为按行选择
|
||
threadStatusTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||
|
||
// 设置表格的选择模式为单选
|
||
threadStatusTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||
|
||
// 设置表格不可编辑
|
||
threadStatusTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
|
||
// 连接 threadStatusTableWidget 的 itemSelectionChanged 信号到槽函数
|
||
connect(threadStatusTableWidget, &QTableWidget::itemSelectionChanged, this,
|
||
&SystemStatusWidget::onThreadStatusTableSelectionChanged);
|
||
}
|
||
|
||
// 处理线程状态表格的选择变化
|
||
void SystemStatusWidget::onThreadStatusTableSelectionChanged()
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (threadStatusTableWidget == nullptr) {
|
||
return;
|
||
}
|
||
QVector<double> xData, yData;
|
||
{
|
||
// 加锁,保护线程数据,用花括号包裹限制锁的作用域
|
||
QMutexLocker locker(&mutex);
|
||
// 获取当前选中的行索引
|
||
int rowIndex = threadStatusTableWidget->currentRow();
|
||
// 如果行索引小于0或大于线程数据向量的大小,则返回
|
||
if (rowIndex < 0 || rowIndex >= threadDataVec.size()) {
|
||
return;
|
||
}
|
||
// 如果图表绘图对象为空,则返回
|
||
if (customPlot == nullptr)
|
||
return; // 确保找到了XNCustomPlot对象
|
||
// 获取当前选中的行索引对应的线程数据
|
||
const XNRuntimeData &data = threadDataVec[rowIndex];
|
||
if (freqOrPeriodIndex == 0 && data.m_CurrentPeriod.size() > 0) {
|
||
// 如果显示周期,则设置图表的x轴和y轴范围
|
||
customPlot->xAxis->setRange(0, data.m_CurrentPeriod.size());
|
||
customPlot->yAxis->setRange(data.m_MinPeriod - 1, data.m_MaxPeriod + 1);
|
||
// 遍历当前周期的数据,并将其添加到x轴和y轴的数据向量中
|
||
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) {
|
||
// 如果显示频率,则设置图表的x轴和y轴范围
|
||
customPlot->xAxis->setRange(0, data.m_CurrentFrequency.size());
|
||
customPlot->yAxis->setRange(data.m_MinFrequency - 1, data.m_MaxFrequency + 1);
|
||
// 遍历当前频率的数据,并将其添加到x轴和y轴的数据向量中
|
||
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 SystemStatusWidget::setupSystemStatusChartWidget()
|
||
{
|
||
// 创建一个QWidget作为图表的容器
|
||
systemStatusChartWidget = new QWidget(this);
|
||
// 创建一个XNCustomPlot对象,并将其添加到图表容器中
|
||
customPlot = new XNCustomPlot(systemStatusChartWidget);
|
||
|
||
// 设置图表布局
|
||
systemStatusChartWidget->setLayout(new QVBoxLayout());
|
||
// 将XNCustomPlot对象添加到图表容器中
|
||
systemStatusChartWidget->layout()->addWidget(customPlot);
|
||
|
||
// 配置图表
|
||
customPlot->setBackground(QBrush(QColor("#19232D"))); // 设置图表的背景颜色
|
||
customPlot->xAxis->setLabelColor(Qt::white); // 设置x轴标签的颜色
|
||
customPlot->yAxis->setLabelColor(Qt::white); // 设置y轴标签的颜色
|
||
customPlot->xAxis->setLabel("时间(s)"); // 设置x轴标签
|
||
customPlot->yAxis->setLabel("周期(ms)"); // 设置y轴标签
|
||
customPlot->xAxis->setTickLabelRotation(60); // 设置x轴标签的旋转角度
|
||
customPlot->xAxis->setTickLabelColor(Qt::white); // 设置x轴标签的颜色
|
||
customPlot->yAxis->setTickLabelColor(Qt::white); // 设置y轴标签的颜色
|
||
customPlot->xAxis->grid()->setVisible(true); // 设置x轴网格线
|
||
customPlot->yAxis->grid()->setVisible(true); // 设置y轴网格线
|
||
|
||
// 添加图表并设置绿色
|
||
customPlot->addGraph();
|
||
QPen greenPen(Qt::green); // 设置绿色笔
|
||
greenPen.setWidth(2); // 设置笔宽
|
||
customPlot->graph(0)->setPen(greenPen); // 设置图表的笔
|
||
|
||
// 为chartWidget设置上下文菜单
|
||
connect(customPlot, &XNCustomPlot::customContextMenuRequested, this,
|
||
&SystemStatusWidget::showChartContextMenu);
|
||
|
||
// 连接信号
|
||
connect(this, &SystemStatusWidget::updateThreadCutomPlotData, this,
|
||
&SystemStatusWidget::onThreadStatusTableSelectionChanged, Qt::QueuedConnection);
|
||
|
||
customPlot->replot();
|
||
}
|
||
|
||
// 处理图表中的右键点击事件
|
||
void SystemStatusWidget::showChartContextMenu(const QPoint &pos)
|
||
{
|
||
if (customPlot == nullptr)
|
||
return; // 确保找到了XNCustomPlot对象
|
||
QMenu contextMenu(this);
|
||
QAction *actionFrequency = contextMenu.addAction("显示频率");
|
||
QAction *actionPeriod = contextMenu.addAction("显示周期");
|
||
|
||
// 连接QAction的triggered信号到相应的槽函数
|
||
connect(actionFrequency, &QAction::triggered, this, &SystemStatusWidget::onShowFrequency);
|
||
connect(actionPeriod, &QAction::triggered, this, &SystemStatusWidget::onShowPeriod);
|
||
|
||
// 在chartWidget上显示上下文菜单
|
||
QAction *selectedAction = contextMenu.exec(customPlot->mapToGlobal(pos));
|
||
}
|
||
|
||
// 处理右键菜单中的"显示频率"选项
|
||
void SystemStatusWidget::onShowFrequency()
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (customPlot == nullptr)
|
||
return; // 确保找到了XNCustomPlot对象
|
||
// 实现显示频率的逻辑
|
||
customPlot->yAxis->setLabel("频率(Hz)");
|
||
freqOrPeriodIndex = 1;
|
||
customPlot->replot(); // 重新绘制图表以显示新数据
|
||
emit updateThreadCutomPlotData();
|
||
}
|
||
|
||
// 处理右键菜单中的"显示周期"选项
|
||
void SystemStatusWidget::onShowPeriod()
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (customPlot == nullptr)
|
||
return; // 确保找到了XNCustomPlot对象
|
||
// 实现显示周期的逻辑
|
||
customPlot->yAxis->setLabel("周期(ms)");
|
||
freqOrPeriodIndex = 0;
|
||
customPlot->replot(); // 重新绘制图表以显示新数据
|
||
emit updateThreadCutomPlotData();
|
||
}
|
||
|
||
// 更新进程名称
|
||
void SystemStatusWidget::updateProcessName(const QString &name)
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (labelXNEngine != nullptr) {
|
||
labelXNEngine->setText(name);
|
||
}
|
||
}
|
||
|
||
// 更新进程ID
|
||
void SystemStatusWidget::updateProcessID(const unsigned int &id)
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (labelProcessIDValue != nullptr) {
|
||
labelProcessIDValue->setText(QString::number(id));
|
||
}
|
||
}
|
||
|
||
// 更新引擎状态
|
||
void SystemStatusWidget::updateEngineStatus(const unsigned int &status)
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (labelStatusValue != nullptr) {
|
||
switch (status) {
|
||
case 0:
|
||
labelStatusValue->setText("未运行");
|
||
labelStatusValue->setStyleSheet("color: gray;");
|
||
break;
|
||
case 1:
|
||
labelStatusValue->setText("运行中");
|
||
labelStatusValue->setStyleSheet("color: green;");
|
||
break;
|
||
case 2:
|
||
labelStatusValue->setText("暂停中");
|
||
labelStatusValue->setStyleSheet("color: orange;");
|
||
break;
|
||
case 3:
|
||
labelStatusValue->setText("错误");
|
||
labelStatusValue->setStyleSheet("color: red;");
|
||
break;
|
||
default:
|
||
labelStatusValue->setText("未知状态");
|
||
labelStatusValue->setStyleSheet("color: red;");
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新内核状态
|
||
void SystemStatusWidget::updateCoreStatus(int index, const unsigned int &status)
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
QLabel *statusLabel = findChild<QLabel *>(QString("coreStatusLabel%1").arg(index));
|
||
if (statusLabel) {
|
||
switch (status) {
|
||
case 0:
|
||
statusLabel->setText("未加载");
|
||
statusLabel->setStyleSheet("color: gray;");
|
||
break;
|
||
case 1:
|
||
statusLabel->setText("初始化完成");
|
||
statusLabel->setStyleSheet("color: orange;");
|
||
break;
|
||
case 2:
|
||
statusLabel->setText("正常");
|
||
statusLabel->setStyleSheet("color: green;");
|
||
break;
|
||
case 3:
|
||
statusLabel->setText("异常");
|
||
statusLabel->setStyleSheet("color: red;");
|
||
break;
|
||
default:
|
||
statusLabel->setText("未知状态");
|
||
statusLabel->setStyleSheet("color: yellow;"); // 默认颜色或其他状态的颜色设置
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新线程数据
|
||
void SystemStatusWidget::updateThreadData(const XNRuntimeData &data)
|
||
{
|
||
// 如果当前标签页不是第一个或第二个,则直接返回
|
||
if (currentTabIndex != 0 && currentTabIndex != 1)
|
||
return;
|
||
QMutexLocker locker(&mutex);
|
||
// 遍历 threadDataVec 向量
|
||
for (size_t i = 0; i < threadDataVec.size(); i++) {
|
||
// 如果当前遍历到的元素 ID 与传入数据的 ID 相同
|
||
if (data.m_id == threadDataVec[i].m_id) {
|
||
double currectFrequency = data.m_CurrentFrequency[0]; // 当前频率
|
||
double currentPeriod = data.m_CurrentPeriod[0]; // 当前周期
|
||
// 更新线程运行状态
|
||
threadDataVec[i].m_RunningState = data.m_RunningState;
|
||
// 如果线程不是运行状态,则不更新频率和周期数据
|
||
if (data.m_RunningState == 1) {
|
||
// 更新当前频率
|
||
threadDataVec[i].m_CurrentFrequency.push_back(currectFrequency);
|
||
// 更新当前周期
|
||
threadDataVec[i].m_CurrentPeriod.push_back(currentPeriod);
|
||
// 更新周期计数
|
||
threadDataVec[i].m_CycleCount = data.m_CycleCount;
|
||
// 更新最小频率
|
||
threadDataVec[i].m_MinFrequency =
|
||
std::min(currectFrequency, threadDataVec[i].m_MinFrequency);
|
||
// 更新最大频率
|
||
threadDataVec[i].m_MaxFrequency =
|
||
std::max(currectFrequency, threadDataVec[i].m_MaxFrequency);
|
||
// 更新平均频率
|
||
threadDataVec[i].m_AvgFrequency =
|
||
((data.m_CycleCount - 1) * threadDataVec[i].m_AvgFrequency + currectFrequency)
|
||
/ data.m_CycleCount;
|
||
// 更新最小周期
|
||
threadDataVec[i].m_MinPeriod =
|
||
std::min(currentPeriod, threadDataVec[i].m_MinPeriod);
|
||
// 更新最大周期
|
||
threadDataVec[i].m_MaxPeriod =
|
||
std::max(currentPeriod, threadDataVec[i].m_MaxPeriod);
|
||
// 更新平均周期
|
||
threadDataVec[i].m_AvgPeriod =
|
||
((data.m_CycleCount - 1) * threadDataVec[i].m_AvgPeriod + currentPeriod)
|
||
/ data.m_CycleCount;
|
||
|
||
// 如果当前频率或周期向量的长度超过100,移除最前面的元素
|
||
if (threadDataVec[i].m_CurrentFrequency.size() > 100) {
|
||
threadDataVec[i].m_CurrentFrequency.pop_front();
|
||
threadDataVec[i].m_CurrentPeriod.pop_front();
|
||
}
|
||
}
|
||
|
||
// 检查当前选中的行是否是被更新的行
|
||
if (currentTabIndex == 0) {
|
||
if (threadStatusTableWidget != nullptr) {
|
||
int currentRow = threadStatusTableWidget->currentRow();
|
||
if (currentRow == static_cast<int>(i)) {
|
||
emit updateThreadCutomPlotData();
|
||
}
|
||
}
|
||
|
||
// 更新表格数据
|
||
updateThreadTableData(threadDataVec[i], i);
|
||
} else if (currentTabIndex == 1) {
|
||
emit updateThreadInfo(i, threadDataVec[i]);
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 如果未找到匹配的 ID,将传入的数据添加到 threadDataVec 向量末尾
|
||
threadDataVec.push_back(data);
|
||
// 更新表格数据
|
||
if (currentTabIndex == 0) {
|
||
updateThreadTableData(data, threadDataVec.size() - 1);
|
||
} else if (currentTabIndex == 1) {
|
||
emit updateThreadInfo(threadDataVec.size() - 1, data);
|
||
}
|
||
}
|
||
|
||
// 更新线程数
|
||
void SystemStatusWidget::updateThreadCount(const unsigned int &count)
|
||
{
|
||
// 如果当前标签页索引不为0,则直接返回
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (labelThreadCountValue != nullptr) {
|
||
labelThreadCountValue->setText(QString::number(count));
|
||
}
|
||
}
|
||
|
||
// 更新CPU亲和性
|
||
void SystemStatusWidget::updateAffinity(const QString &affinity)
|
||
{
|
||
// 如果当前标签页索引不为0,则直接返回
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (labelAffinityValue != nullptr) {
|
||
labelAffinityValue->setText(affinity);
|
||
}
|
||
}
|
||
|
||
// 更新线程表格数据
|
||
void SystemStatusWidget::updateThreadTableData(const XNRuntimeData &data, int rowIndex)
|
||
{
|
||
// 如果当前标签页索引不为0,则直接返回
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
|
||
// 查找threadStatusTableWidget
|
||
if (threadStatusTableWidget == nullptr) {
|
||
// 如果没有找到,则直接返回
|
||
return;
|
||
}
|
||
|
||
// 设置表格的行数
|
||
threadStatusTableWidget->setRowCount(std::max(rowIndex + 1, (int)threadDataVec.size()));
|
||
|
||
// 设置线程名称
|
||
threadStatusTableWidget->setItem(rowIndex, 0, new QTableWidgetItem(data.m_name));
|
||
|
||
// 设置线程ID
|
||
threadStatusTableWidget->setItem(rowIndex, 1, new QTableWidgetItem(QString::number(data.m_id)));
|
||
|
||
// 根据线程的运行状态设置不同的状态显示
|
||
switch (data.m_RunningState) {
|
||
case 0:
|
||
// 未运行状态
|
||
threadStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("未运行"));
|
||
threadStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::gray));
|
||
break;
|
||
case 1:
|
||
// 运行中状态
|
||
threadStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("运行中"));
|
||
threadStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::green));
|
||
break;
|
||
case 2:
|
||
// 暂停中状态
|
||
threadStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("暂停中"));
|
||
threadStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::yellow));
|
||
break;
|
||
default:
|
||
// 未知状态
|
||
threadStatusTableWidget->setItem(rowIndex, 2, new QTableWidgetItem("未知状态"));
|
||
threadStatusTableWidget->item(rowIndex, 2)->setForeground(QBrush(Qt::red));
|
||
break;
|
||
}
|
||
|
||
// 初始化affinity字符串
|
||
QString affinity = "";
|
||
for (int i = 0; i < 32; i++) {
|
||
// 如果线程亲和性掩码对应位为1,则添加该位的索引到affinity字符串中
|
||
if (data.m_AffinityMask & (1 << i)) {
|
||
affinity += QString::number(i) + " ";
|
||
}
|
||
}
|
||
|
||
// 设置affinity
|
||
threadStatusTableWidget->setItem(rowIndex, 3, new QTableWidgetItem(affinity));
|
||
|
||
// 设置线程优先级
|
||
threadStatusTableWidget->setItem(rowIndex, 4,
|
||
new QTableWidgetItem(QString::number(data.m_Priority)));
|
||
|
||
// 设置线程设置频率
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 5, new QTableWidgetItem(QString::number(data.m_SetFrequency, 'f', 2) + " Hz"));
|
||
|
||
// 设置线程最小频率
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 6, new QTableWidgetItem(QString::number(data.m_MinFrequency, 'f', 2) + " Hz"));
|
||
|
||
// 设置线程最大频率
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 7, new QTableWidgetItem(QString::number(data.m_MaxFrequency, 'f', 2) + " Hz"));
|
||
|
||
// 设置线程平均频率
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 8, new QTableWidgetItem(QString::number(data.m_AvgFrequency, 'f', 2) + " Hz"));
|
||
|
||
// 设置线程周期计数
|
||
threadStatusTableWidget->setItem(rowIndex, 9,
|
||
new QTableWidgetItem(QString::number(data.m_CycleCount)));
|
||
|
||
// 设置线程设置周期
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 10, new QTableWidgetItem(QString::number(data.m_SetPeriod, 'f', 2) + " ms"));
|
||
|
||
// 设置线程最小周期
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 11, new QTableWidgetItem(QString::number(data.m_MinPeriod, 'f', 2) + " ms"));
|
||
|
||
// 设置线程最大周期
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 12, new QTableWidgetItem(QString::number(data.m_MaxPeriod, 'f', 2) + " ms"));
|
||
|
||
// 设置线程平均周期
|
||
threadStatusTableWidget->setItem(
|
||
rowIndex, 13, new QTableWidgetItem(QString::number(data.m_AvgPeriod, 'f', 2) + " ms"));
|
||
}
|
||
|
||
// 更新图表数据
|
||
void SystemStatusWidget::updatePlotData(const QVector<double> &newXData,
|
||
const QVector<double> &newYData)
|
||
{
|
||
if (currentTabIndex != 0)
|
||
return;
|
||
if (customPlot == nullptr)
|
||
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(); // 重新绘制图表以显示新数据
|
||
}
|
||
}
|
||
|
||
QString SystemStatusWidget::getThreadName(const quint32 threadID)
|
||
{
|
||
QMutexLocker locker(&mutex);
|
||
// 遍历threadDataVec向量
|
||
for (int i = 0; i < threadDataVec.size(); i++) {
|
||
// 如果当前遍历到的元素的ID与传入的ID相同
|
||
if (threadID == threadDataVec[i].m_id) {
|
||
// 返回当前遍历到的元素的名称
|
||
return threadDataVec[i].m_name;
|
||
}
|
||
}
|
||
// 如果未找到匹配的ID,则返回未知线程
|
||
return QString("未知线程");
|
||
} |