添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

目前使 Qt 运行一个实例有如下几种方式:

1.QSharedMemory

使用共享内存,当第二个进程启动时,判断内存区数据是否建立,如有,则退出;这种方式有弊端,在程序发生崩溃时,未及时清除共享区数据,导致程序不能正常启动。

2.文件锁

在程序运行的时候就在目录下创建一个文件,当程序运行时就判断这个文件是否存在,如果存在说明程序已经在运行。其本质与 QSharedMemory 相同。

3.利用QLocalServer

Qt实现应用程序单实例运行–LocalServer方式
让QT只运行一个实例

4.QtSingleApplication

使用 Qt 扩展库 QtSingleApplication,能很好的解决这个问题。

QSingleApplication 是 Qt 提供的一个 solution ,它不包含在 Qt 的 library 中。遵循 LGPL 协议。Qt 欢迎里面有例子。

二、实现代码

下面给出了 LocalServer 方式的实现代码。

SingleApplication.h:

#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H
#include <QObject>
#include <QApplication>
#include <QtNetwork/QLocalServer>
#include <QWidget>
class SingleApplication : public QApplication {
        Q_OBJECT
    public:
        SingleApplication(int &argc, char **argv);
        bool isRunning();                // 是否已經有实例在运行
        QWidget *w;                        // MainWindow指针
    private slots:
        // 有新连接时触发
        void _newLocalConnection();
    private:
        // 初始化本地连接
        void _initLocalConnection();
        // 创建服务端
        void _newLocalServer();
        // 激活窗口
        void _activateWindow();
        bool _isRunning;                // 是否已經有实例在运行
        QLocalServer *_localServer;     // 本地socket Server
        QString _serverName;            // 服务名称
#endif // SINGLEAPPLICATION_H

SingleApplication.cpp:

#include "SingleApplication.h"
#include <QtNetwork/QLocalSocket>
#include <QFileInfo>
#define TIME_OUT                (500)    // 500ms
SingleApplication::SingleApplication(int &argc, char **argv)
    : QApplication(argc, argv)
    , w(NULL)
    , _isRunning(false)
    , _localServer(NULL) {
    // 取应用程序名作为LocalServer的名字
    _serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
    _initLocalConnection();
////////////////////////////////////////////////////////////////////////////////
// 说明:
// 检查是否已經有一个实例在运行, true - 有实例运行, false - 没有实例运行
////////////////////////////////////////////////////////////////////////////////
bool SingleApplication::isRunning() {
    return _isRunning;
////////////////////////////////////////////////////////////////////////////////
// 说明:
// 通过socket通讯实现程序单实例运行,监听到新的连接时触发该函数
////////////////////////////////////////////////////////////////////////////////
void SingleApplication::_newLocalConnection() {
    QLocalSocket *socket = _localServer->nextPendingConnection();
    if(socket) {
        socket->waitForReadyRead(2*TIME_OUT);
        delete socket;
        // 其他处理,如:读取启动参数
        _activateWindow();
////////////////////////////////////////////////////////////////////////////////
// 说明:
// 通过socket通讯实现程序单实例运行,
// 初始化本地连接,如果连接不上server,则创建,否则退出
////////////////////////////////////////////////////////////////////////////////
void SingleApplication::_initLocalConnection() {
    _isRunning = false;
    QLocalSocket socket;
    socket.connectToServer(_serverName);
    if(socket.waitForConnected(TIME_OUT)) {
        fprintf(stderr, "%s already running.\n",
                _serverName.toLocal8Bit().constData());
        _isRunning = true;
        // 其他处理,如:将启动参数发送到服务端
        return;
    //连接不上服务器,就创建一个
    _newLocalServer();
////////////////////////////////////////////////////////////////////////////////
// 说明:
// 创建LocalServer
////////////////////////////////////////////////////////////////////////////////
void SingleApplication::_newLocalServer() {
    _localServer = new QLocalServer(this);
    connect(_localServer, SIGNAL(newConnection()), this, SLOT(_newLocalConnection()));
    if(!_localServer->listen(_serverName)) {
        // 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之
        if(_localServer->serverError() == QAbstractSocket::AddressInUseError) {
            QLocalServer::removeServer(_serverName); // <-- 重点
            _localServer->listen(_serverName); // 再次监听
////////////////////////////////////////////////////////////////////////////////
// 说明:
// 激活主窗口
////////////////////////////////////////////////////////////////////////////////
void SingleApplication::_activateWindow() {
    if(w) {
        w->show();
        w->raise();
        w->activateWindow(); // 激活窗口

调用示例:

#include "MainWindow.h"
#include "SingleApplication.h"
int main(int argc, char *argv[]) {
    SingleApplication a(argc, argv);
    if(!a.isRunning()) {
        MainWindow w;
        a.w = &w;
        w.show();
        return a.exec();
    return 0;