[Qt學習筆記]Qt實現(xiàn)程序單例運行,再次點擊后彈出界面

一、介紹

在實際工程項目中,軟件在打開情況下,再次打開軟件會出現(xiàn)打開多個軟件界面的情況,進而找出與下位機交互的錯誤,對于工程項目是不允許此類情況出現(xiàn),所以在軟件運行時必須保證該軟件是單例運行,在運行狀況下再次打開時進行提示或彈出之前的軟件界面。

二、實現(xiàn)方法

2.1 重寫QApplation類本地localserver監(jiān)控單例程序

2.1.1 實現(xiàn)原理

通過socket通訊實現(xiàn)程序單實例運行,已程序名稱創(chuàng)建一個localServer,通過socket一直監(jiān)聽程序是否在運行。當程序在運行時,再次打軟件,將激活顯示已運行的程序顯示界面。

2.1.2 效果展示

20.SingleApplationTest.gif

2.1.3 實現(xiàn)代碼

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通訊實現(xiàn)程序單實例運行,監(jiān)聽到新的連接時觸發(fā)該函數(shù).
******************************************************************/
void SingleApplication::NewLocalConnection()
{
    QLocalSocket *localSocket = localserver->nextPendingConnection();
    if(localSocket)
    {
        localSocket->waitForReadyRead(TIME_OUT * 2);
        delete localSocket;

        //其他處理,如:讀取啟動參數(shù)
        ActivateWindow();
    }
}


/*****************************************************************
* 通過socket通訊實現(xiàn)程序單實例運行,
* 初始化本地連接,如果連接不上server,則創(chuàng)建,否則退出
******************************************************************/
void SingleApplication::InitLocalConnection()
{
    isRunnings = false;
    QLocalSocket socket;
    socket.connectToServer(serverName);
    if(socket.waitForConnected(TIME_OUT))
    {
        isRunnings = true;

        //其他處理,如:將啟動參數(shù)發(fā)送到服務端
        return;
    }

    //連接不上服務器,就創(chuàng)建一個
    NewLocalServer();
}

/*****************************************************************
* 創(chuàng)建localserver
******************************************************************/
void SingleApplication::NewLocalServer()
{
    localserver = new QLocalServer(this);
    connect(localserver, &QLocalServer::newConnection, this, &SingleApplication::NewLocalConnection);
    if(!localserver->listen(serverName))
    {
        // 此時監(jiān)聽失敗,可能是程序崩潰時,殘留進程服務導致的,移除
        if(localserver->serverError() == QAbstractSocket::AddressInUseError)
        {
            localserver->removeServer(serverName);
            localserver->listen(serverName); //重新監(jiān)聽
        }
    }
}

/*****************************************************************
* 激活主窗口
******************************************************************/
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:
    //有新連接時觸發(fā)
    void NewLocalConnection();

private:
    //初始化本地連接
    void InitLocalConnection();
    //創(chuàng)建服務端
    void NewLocalServer();
    //激活窗口
    void ActivateWindow();

    // 本地socket Server
    QLocalServer *localserver;
    // 服務名稱
    QString       serverName;
    // 運行狀態(tài)
    bool          isRunnings;
};

#endif // SINGLEAPPLICATION_H

main函數(shù)調(diào)用,將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 實現(xiàn)原理

文件鎖試下程序單例運行,就是在程序啟動的時候創(chuàng)建一個唯一標識的文件鎖文件,再次啟動程序時先檢測是都有文件鎖存在,且文件鎖是否有效來達到鎖定程序的效果。

2.2.2 效果展示

單實例測試.gif

2.2.3 實現(xiàn)代碼

#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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容