效果图
第一步 设计器
拖拽一个QTableWidget和三个QPushButton,布局一下
第二步 上码
1.mainwindow.h
代码如下(示例):
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QPushButton>
#include <QLabel>
#include <QFileInfo>
#include <QEvent>
#include <QCloseEvent>
#include "keeplivemanager.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initView();
void showView();
private slots:
void onTableBtnClicked();
void recvStatSignal(const QString &str1, const QString &str2);
void on_pushButton_update_clicked();
void on_pushButton_start_clicked();
void on_pushButton_stop_clicked();
protected:
// 重写关闭事件
void closeEvent(QCloseEvent *event) override ;
// 重写变形事件
void resizeEvent(QResizeEvent *event) override;
private:
Ui::MainWindow *ui;
QMap<QString,QString> m_mapApps;
KeepliveManager* m_pKeeplive = nullptr;
};
#endif // MAINWINDOW_H
2.mainwindow.cpp
代码如下(示例):
#include "mainwindow.h"
#include "ui_mainwindow.h"
enum WatchColumn{
_NAME =0,
_PATH =1,
_PID =2,
_STAT =3,
_EXEC =4
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(tr("MyWatchDog"));
initView();
m_pKeeplive = new KeepliveManager();
m_pKeeplive->Start();
showView();
QObject::connect(m_pKeeplive, &KeepliveManager::sendStatSignal, this, &MainWindow::recvStatSignal);
m_pKeeplive->Watchasyn();
}
MainWindow::~MainWindow()
{
delete m_pKeeplive;
m_pKeeplive = nullptr;
delete ui;
}
void MainWindow::closeEvent(QCloseEvent *event)
{
// 不执行默认关闭行为
//event->ignore();
// 最小化窗口 点击托盘"主界面"显示
//this->hide();
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
int nWidth = this->width() - 20;
ui->tableWidget->setColumnCount(5);
ui->tableWidget->setColumnWidth(WatchColumn::_NAME, nWidth * 0.2);
ui->tableWidget->setColumnWidth(WatchColumn::_PATH, nWidth * 0.4);
ui->tableWidget->setColumnWidth(WatchColumn::_PID, nWidth * 0.1);
ui->tableWidget->setColumnWidth(WatchColumn::_STAT, nWidth * 0.1);
ui->tableWidget->setColumnWidth(WatchColumn::_EXEC, nWidth * 0.2);
}
void MainWindow::initView()
{
int nWidth = this->width() - 20;
ui->tableWidget->setColumnCount(5);
ui->tableWidget->setColumnWidth(WatchColumn::_NAME, nWidth * 0.2);
ui->tableWidget->setColumnWidth(WatchColumn::_PATH, nWidth * 0.4);
ui->tableWidget->setColumnWidth(WatchColumn::_PID, nWidth * 0.1);
ui->tableWidget->setColumnWidth(WatchColumn::_STAT, nWidth * 0.1);
ui->tableWidget->setColumnWidth(WatchColumn::_EXEC, nWidth * 0.2);
// 设置列标题
ui->tableWidget->setHorizontalHeaderItem(WatchColumn::_NAME, new QTableWidgetItem(tr("应用")));
ui->tableWidget->setHorizontalHeaderItem(WatchColumn::_PATH, new QTableWidgetItem(tr("路径")));
ui->tableWidget->setHorizontalHeaderItem(WatchColumn::_PID, new QTableWidgetItem(tr("PID")));
ui->tableWidget->setHorizontalHeaderItem(WatchColumn::_STAT, new QTableWidgetItem(tr("状态")));
ui->tableWidget->setHorizontalHeaderItem(WatchColumn::_EXEC, new QTableWidgetItem(tr("操作")));
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
//ui->tableWidget->setSelectionMode(QAbstractItemView::MultiSelection);
ui->tableWidget->verticalHeader()->setVisible(false);
ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
connect(ui->tableWidget, &QTableWidget::itemPressed, this, [&](QTableWidgetItem *item){
});
}
void MainWindow::showView()
{
ui->tableWidget->clearContents();
m_mapApps = m_pKeeplive->GetMap();
int nIndex = 0;
for (auto it = m_mapApps.begin(); it != m_mapApps.end(); ++it) {
ui->tableWidget->setRowCount(nIndex + 1);
QString strPath = it.key();
QFileInfo fileInfo(strPath);
QString strName = fileInfo.fileName();
qDebug() << strName << strPath;
ui->tableWidget->setItem(nIndex, WatchColumn::_NAME, new QTableWidgetItem(strName));
QTableWidgetItem *itemPath = new QTableWidgetItem(strPath);
itemPath->setToolTip(strPath);
ui->tableWidget->setItem(nIndex, WatchColumn::_PATH, itemPath);
ui->tableWidget->setItem(nIndex, WatchColumn::_PID, new QTableWidgetItem("0"));
//状态
QLabel *label3 = new QLabel("");
QWidget *widget3 = new QWidget();
QHBoxLayout *layout3 = new QHBoxLayout(widget3);
layout3->addWidget(label3);
layout3->setContentsMargins(8, 2, 8, 2);
widget3->setLayout(layout3);
ui->tableWidget->setCellWidget(nIndex, WatchColumn::_STAT, widget3);
//操作
QPushButton *button4 = new QPushButton(tr("停止"));
button4->setStyleSheet("background-color: rgb(247, 211, 60);"
"color:rgb(255, 255, 255) ;"
"font-family: PingFang SC;"
"font-weight: bold;"
"font-size: 18px;");
//设置按钮的自定义属性
button4->setProperty("S_Name",strName);
button4->setProperty("S_Path",strPath);
connect(button4, SIGNAL(clicked(bool)), this, SLOT(onTableBtnClicked()));
QWidget *widget4 = new QWidget();
QHBoxLayout *layout4 = new QHBoxLayout(widget4);
layout4->addWidget(button4);
layout4->setContentsMargins(2, 2, 2, 2);
widget4->setLayout(layout4);
ui->tableWidget->setCellWidget(nIndex, WatchColumn::_EXEC, widget4);
nIndex++;
}
}
void MainWindow::onTableBtnClicked()
{
QPushButton *button = (QPushButton*)sender();
//提取按钮的自定义属性 数据类型须统一
QString S_Name = button->property("S_Name").toString();
QString S_Path = button->property("S_Path").toString();
if(m_pKeeplive)
{
QString strText = button->text();
if(strText == "开启")
{
m_pKeeplive->StartProcess(S_Path);
}
else
{
m_pKeeplive->StopProcess(S_Path);
}
}
}
void MainWindow::recvStatSignal(const QString &str1, const QString &str2)
{
QString strPath = str1;
QString strPid = str2;
for (int row = 0; row < ui->tableWidget->rowCount(); ++row) {
QTableWidgetItem *item = ui->tableWidget->item(row, WatchColumn::_PATH);
if (item && item->text() == strPath) {
// 更新
QTableWidgetItem *item = new QTableWidgetItem(strPid);
ui->tableWidget->setItem(row, WatchColumn::_PID, item);
// 获取所在的 QWidget
QWidget *widget3 = ui->tableWidget->cellWidget(row, WatchColumn::_STAT);
QWidget *widget4 = ui->tableWidget->cellWidget(row, WatchColumn::_EXEC);
if (widget3 && widget4) {
//获取button
QPushButton *button = widget4->findChild<QPushButton *>();
//获取label
QLabel *label = widget3->findChild<QLabel *>();
if (button && label) {
if(strPid.isEmpty() || strPid == "0")
{
button->setText(tr("开启"));
QString strStyleSheet = QString("background-color: rgb(255, 0, 0); border-radius: %1px;").arg(label->height()/2);
label->setStyleSheet(strStyleSheet);
}
else
{
button->setText(tr("停止"));
QString strStyleSheet = QString("background-color: rgb(0, 170, 127); border-radius: %1px;").arg(label->height()/2);
label->setStyleSheet(strStyleSheet);
}
}
}
}
}
}
void MainWindow::on_pushButton_update_clicked()
{
ui->tableWidget->clearSelection();
if(m_pKeeplive)
{
m_pKeeplive->UpdateProcess();
}
}
void MainWindow::on_pushButton_start_clicked()
{
ui->tableWidget->clearSelection();
if(m_pKeeplive)
{
m_pKeeplive->StartProcess("");
}
}
void MainWindow::on_pushButton_stop_clicked()
{
ui->tableWidget->clearSelection();
if(m_pKeeplive)
{
m_pKeeplive->StopProcess("");
}
}
3.keeplivemanager.h
代码如下(示例):
#ifndef KEEPLIVEMANAGER_H
#define KEEPLIVEMANAGER_H
#include <QObject>
#include <QProcess>
#include <QThread>
#include <QMap>
#include <QDebug>
#include <thread>
#include <QMutex>
struct stAppStat
{
QString strPath;
QString strType;
int nKeeping; //是否需要保活 1是 0否
stAppStat( const QString &path = "", const QString &type = "", int keeping = 0)
: strPath(path), strType(type), nKeeping(keeping) {}
};
class KeepliveManager : public QObject
{
Q_OBJECT
public:
explicit KeepliveManager(QObject *parent = nullptr);
virtual ~KeepliveManager();
//开始+读取配置
void Start();
//停止循环
void Stop();
//检测+启动
void Watch();
//异步执行
void Watchasyn();
void SetMap(const QMap<QString,QString>& map);
QMap<QString,QString> GetMap();
void StartProcess(const QString &path);
void StopProcess(const QString &path);
//刷新
void UpdateProcess();
signals:
void sendStatSignal(const QString &str1, const QString &str2);
private:
//判断进程是否存在
bool isProcessRunning(const QString &processName,QString &processPid);
private:
bool bkeeping_ = true;
bool bruning_ = true;
int nYesCount_ = 0;
int nNoCount_ = 0;
QMutex m_mutex; //定义一个互斥锁变量
QMap<QString,stAppStat*> m_mapApps;
};
#endif // KEEPLIVEMANAGER_H
4.keeplivemanager.cpp
代码如下(示例):
#include "keeplivemanager.h"
KeepliveManager::KeepliveManager(QObject *parent)
: QObject(parent), bkeeping_(true), bruning_(true)
{
}
KeepliveManager::~KeepliveManager()
{
for (auto it = m_mapApps.begin(); it != m_mapApps.end(); ++it) {
QString strPath = it.key();
stAppStat* stStat = it.value();
delete stStat;
stStat = nullptr;
}
m_mapApps.clear();
}
bool KeepliveManager::isProcessRunning(const QString &processName,QString &processPid)
{
QProcess process;
// 设置环境变量,确保可以在PATH中找到pidof命令
process.setEnvironment(QProcess::systemEnvironment());
// 执行pidof命令,并获取输出
process.start("pidof", QStringList() << processName);
process.waitForFinished();
QByteArray output = process.readAllStandardOutput();
processPid = output.trimmed();
// 如果输出为空,则表示没有找到对应的进程
return !output.trimmed().isEmpty();
}
void KeepliveManager::Stop()
{
qDebug()<< " stop" ;
bkeeping_ = false;
bruning_ = false;
}
void KeepliveManager::UpdateProcess()
{
QMutexLocker locker(&m_mutex);
for (QMap<QString, stAppStat*>::const_iterator it = m_mapApps.begin(); it != m_mapApps.end(); ++it)
{
QString strPath = it.key();
stAppStat* stStat = it.value();
if(stStat->nKeeping == 0)
{
nNoCount_++;
if(nNoCount_ > 5)
{
qDebug() << strPath << " is not keeping";
nNoCount_ = 0;
}
continue;
}
QString strPid ;
bool _bRet = isProcessRunning(strPath,strPid);
emit sendStatSignal(strPath,strPid);
if(_bRet)
{
nYesCount_++;
if(nYesCount_ > 10)
{
qDebug() << strPath << " is not running";
nYesCount_ = 0;
}
}
else
{
QProcess::startDetached(strPath + stStat->strType);
}
}
}
void KeepliveManager::SetMap(const QMap<QString,QString>& map)
{
for (auto it = map.begin(); it != map.end(); ++it) {
stAppStat* stStat = new stAppStat();
stStat->strPath = it.key();
stStat->strType = it.value();
stStat->nKeeping = 1;
m_mapApps.insert(it.key(),stStat);
}
}
QMap<QString,QString> KeepliveManager::GetMap()
{
QMap<QString,QString> _map;
for (auto it = m_mapApps.begin(); it != m_mapApps.end(); ++it) {
QString strPath = it.key();
stAppStat* stStat = it.value();
_map.insert(strPath, stStat->strType);
}
return _map;
}
void KeepliveManager::Start()
{
qDebug()<< " start" ;
bkeeping_ = true;
bruning_ = true;
if(m_mapApps.size() == 0)
{
//拓展成从配置文件中读取
int sub_count = 1;
for(int n = 0 ; n < sub_count ;n++ )
{
QString strIndex = "/" + QString::number(n+1) + "/";
QString strPath = "/home/kylin/test";
QString strType = ".sh";
stAppStat* stStat = new stAppStat();
stStat->strPath = strPath;
stStat->strType = strType;
stStat->nKeeping = 1;
m_mapApps.insert(strPath,stStat);
}
}
}
void KeepliveManager::StartProcess(const QString &path)
{
QMutexLocker locker(&m_mutex);
for (QMap<QString, stAppStat*>::const_iterator it = m_mapApps.begin(); it != m_mapApps.end(); ++it)
{
QString strPath = it.key();
stAppStat* stStat = it.value();
if(path == strPath || path.isEmpty())
{
QString strPid ;
bool _bRet = isProcessRunning(strPath,strPid);
emit sendStatSignal(strPath,strPid);
if(!_bRet)
{
stStat->nKeeping = 1;
QProcess::startDetached(strPath + stStat->strType);
}
if(path == strPath)
{
return;
}
}
}
}
void KeepliveManager::StopProcess(const QString &path)
{
QMutexLocker locker(&m_mutex);
for (QMap<QString, stAppStat*>::const_iterator it = m_mapApps.begin(); it != m_mapApps.end(); ++it)
{
QString strPath = it.key();
stAppStat* stStat = it.value();
if(path == strPath || path.isEmpty())
{
QString strPid ;
bool _bRet = isProcessRunning(strPath,strPid);
if(_bRet)
{
QString command = QString("kill -9 %1").arg(strPid);
QProcess process;
process.start(command);
process.waitForFinished(-1); // Wait indefinitely for the process to finish
stStat->nKeeping = 0;
emit sendStatSignal(strPath,"");
}
if(path == strPath)
{
return;
}
}
}
}
void KeepliveManager::Watch()
{
qDebug()<< "Watch" ;
while(bruning_)
{
QThread::sleep(5);
if(!bkeeping_)
{
qDebug()<< "keeplive is stop" ;
continue;
}
UpdateProcess();
}
}
void KeepliveManager::Watchasyn()
{
std::thread _wth([&](){
this->Watch();
});
_wth.detach();
}
总结
上述示例适用于Linux系统,使用QProcess 命令行判断进程是否存在和杀进程,跨平台则修改这两个功能函数即可。
标签:WatchColumn,Qt,void,QTableWidget,保活,tableWidget,ui,QString,strPath From: https://blog.csdn.net/qq_17319357/article/details/143206821