zoukankan      html  css  js  c++  java
  • Qt 实现应用程序单实例运行

    一、实现方案

    目前使 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.
    ",
                    _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;
    }
    

  • 相关阅读:
    DAL层中根据ID删除方法(常用)
    DAL层联合查询及条件查询方法(常用)
    WPF中DataGrid在没有数据的时候也可以显示水平滚动条
    C#使用SharpZipLib创建压缩文件,并指定压缩文件夹路径(解决SharpZipLib压缩长路径显示问题)
    WPF的DataGrid的某个列绑定数据的三种方法(Binding、Converter、DataTrigger)
    WPF实现背景透明磨砂,并通过HandyControl组件实现弹出等待框
    C#使用FileSystemWatcher来监控指定文件夹,并使用TCP/IP协议通过Socket发送到另外指定文件夹
    C#使用Parallel处理数据同步写入Datatable并使用BulkInsert批量导入数据库
    C#编写运行在Linux环境下的采用Mediainfo来获取多媒体文件信息的代码
    C#使用iTextSharp+ZXing.Net+FreeSpire.PDF生成和打印pdf文档
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/13353130.html
Copyright © 2011-2022 走看看