目录
一、介绍
在实际工程项目中,软件在打开情况下,再次打开软件会出现打开多个软件界面的情况,进而找出与下位机交互的错误,对于工程项目是不允许此类情况出现,所以在软件运行时必须保证该软件是单例运行,在运行状况下再次打开时进行提示或弹出之前的软件界面。
二、实现方法
2.1 重写QApplation类本地localserver监控单例程序
2.1.1 实现原理
通过socket通讯实现程序单实例运行,已程序名称创建一个localServer,通过socket一直监听程序是否在运行。当程序在运行时,再次打软件,将激活显示已运行的程序显示界面。
2.1.2 效果展示
2.1.3 实现代码
singleapplation.cpp
#include "SingleApplication.h"
#include <QtNetwork/QLocalSocket>
#include <QFileInfo>
#define TIME_OUT 500
SingleApplication::SingleApplication(int &argc, char *argv[])
:QApplication(argc, argv),
isRunnings(false),
w(NULL),
localserver(NULL)
{
//取应用程序名作为localServer的名字
serverName = QFileInfo(QApplication::applicationFilePath()).fileName();
InitLocalConnection();
}
/*****************************************************************
* 检查是否已有一个实例在运行, true有实例运行, false没有实例运行.
******************************************************************/
bool SingleApplication::isRunning()
{
return isRunnings;
}
/*****************************************************************
* 通过socket通讯实现程序单实例运行,监听到新的连接时触发该函数.
******************************************************************/
void SingleApplication::NewLocalConnection()
{
QLocalSocket *localSocket = localserver->nextPendingConnection();
if(localSocket)
{
localSocket->waitForReadyRead(TIME_OUT * 2);
delete localSocket;
//其他处理,如:读取启动参数
ActivateWindow();
}
}
/*****************************************************************
* 通过socket通讯实现程序单实例运行,
* 初始化本地连接,如果连接不上server,则创建,否则退出
******************************************************************/
void SingleApplication::InitLocalConnection()
{
isRunnings = false;
QLocalSocket socket;
socket.connectToServer(serverName);
if(socket.waitForConnected(TIME_OUT))
{
isRunnings = true;
//其他处理,如:将启动参数发送到服务端
return;
}
//连接不上服务器,就创建一个
NewLocalServer();
}
/*****************************************************************
* 创建localserver
******************************************************************/
void SingleApplication::NewLocalServer()
{
localserver = new QLocalServer(this);
connect(localserver, &QLocalServer::newConnection, this, &SingleApplication::NewLocalConnection);
if(!localserver->listen(serverName))
{
// 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除
if(localserver->serverError() == QAbstractSocket::AddressInUseError)
{
localserver->removeServer(serverName);
localserver->listen(serverName); //重新监听
}
}
}
/*****************************************************************
* 激活主窗口
******************************************************************/
void SingleApplication::ActivateWindow()
{
if(w)
{
w->raise();
// w->activateWindow();
w->showNormal();
}
}
singleapplation.h
#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H
#include <QObject>
#include <QWidget>
#include <QApplication>
#include <QtNetwork/QLocalServer>
class SingleApplication : public QApplication
{
Q_OBJECT
public:
SingleApplication(int &argc, char *argv[]);
// 判断是否已有实例在运行
bool isRunning();
QWidget *w;
private slots:
//有新连接时触发
void NewLocalConnection();
private:
//初始化本地连接
void InitLocalConnection();
//创建服务端
void NewLocalServer();
//激活窗口
void ActivateWindow();
// 本地socket Server
QLocalServer *localserver;
// 服务名称
QString serverName;
// 运行状态
bool isRunnings;
};
#endif // SINGLEAPPLICATION_H
main函数调用,将QApplation改成SingleApplation类
#include "widget.h"
#include "singleapplication.h"
//#include <QApplication>
int main(int argc, char *argv[])
{
// 方法一 本地socket 使用SingleApplication 代替原来的QApplication类
SingleApplication a(argc, argv);
if(!a.isRunning()){
Widget w;
a.w = &w;
w.show();
return a.exec();
}
}
2.2 文件锁
2.2.1 实现原理
文件锁试下程序单例运行,就是在程序启动的时候创建一个唯一标识的文件锁文件,再次启动程序时先检测是都有文件锁存在,且文件锁是否有效来达到锁定程序的效果。
2.2.2 效果展示
2.2.3 实现代码
#include "widget.h"
//#include "singleapplication.h"
#include <QApplication>
#include <QLockFile>
#include <QMessageBox>
bool CheckSoftExist()
{
// 防止程序重复启动
QString lockFilePath;
lockFilePath = "./singleApp.lock";
QLockFile *lockFile = new QLockFile(lockFilePath);
if (!lockFile ->tryLock(2000)) {
QMessageBox::warning(NULL, QObject::tr("Warning"), QObject::tr("The software is running!"));
return false;
}
return true;
}
int main(int argc, char *argv[])
{
// 方法一 本地socket 使用SingleApplication 代替原来的QApplication类
// SingleApplication a(argc, argv);
// if(!a.isRunning()){
// Widget w;
// a.w = &w;
// w.show();
// return a.exec();
// }
// 方法二 文件锁方法
QApplication a(argc, argv);
if(CheckSoftExist() == true)
{
Widget w;
w.show();
return a.exec();
}
}
三、源码开源
源码放到gitee上,大家学习交流,有错误或bug还望不吝赐教,希望大脚给个星星支持一下。
https://gitee.com/Damion_Learning/QtHalcon_LearningRecord.git