Qt单实例程序(防止程序多开)

版权声明:本文为博主原创文章,转载请注明原帖地址。 https://blog.csdn.net/sunflover454/article/details/50426639

使用QLocalServer,QLocalSocket实现单实例进程,当已经存在相同进程时且窗口未激活(遮挡,最小化,托盘)时,激活进程主窗口。

参考文章:http://blog.csdn.net/playstudy/article/details/7796691

#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H

#include <QObject>
#include <QApplication>

class QWidget;
class QLocalServer;

class SingleApplication : public QApplication
{
    Q_OBJECT
public:
    SingleApplication(int &argc, char **argv);
    bool isRunning();               // 是否已经有实例在运行
    QWidget *mainWindow;            // MainWindow指针

private slots:
    // 有新连接时触发
    void newLocalConnection();

private:
    // 初始化本地连接
    void initLocalConnection();
    // 创建服务端
    void newLocalServer();
    bool bRunning;                  // 是否已经有实例在运行
    QLocalServer *localServer;      // 本地socket Server
    QString serverName;             // 服务名称
};

#endif // SINGLEAPPLICATION_H


#include "SingleApplication.h"
#include <QWidget>
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QFileInfo>
#include <QLibrary>


SingleApplication::SingleApplication(int &argc, char **argv)
    : QApplication(argc, argv)
    , bRunning(false)
    , localServer(NULL)
    , mainWindow(NULL)
{
    // 取应用程序名作为LocalServer的名字
    serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
    //qDebug()<<serverName;
    initLocalConnection();
}


////////////////////////////////////////////////////////////////////////////////
// 说明:
// 检查是否已經有一个实例在运行, true - 有实例运行, false - 没有实例运行
////////////////////////////////////////////////////////////////////////////////
bool SingleApplication::isRunning()
{
    return bRunning;
}

////////////////////////////////////////////////////////////////////////////////
// 说明:
// 通过socket通讯实现程序单实例运行,监听到新的连接时触发该函数
////////////////////////////////////////////////////////////////////////////////
void SingleApplication::newLocalConnection()
{
    QLocalSocket *socket = localServer->nextPendingConnection();
    if (!socket)
        return;
    socket->waitForReadyRead(1000);
    QTextStream stream(socket);
    //其他处理
    delete socket;
    if (mainWindow != NULL)
    {
        //激活窗口
        mainWindow->raise();
        mainWindow->activateWindow();
        mainWindow->setWindowState((mainWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
        mainWindow->show();
    }
}

////////////////////////////////////////////////////////////////////////////////
// 说明:
// 通过socket通讯实现程序单实例运行,
// 初始化本地连接,如果连接不上server,则创建,否则退出
////////////////////////////////////////////////////////////////////////////////
void SingleApplication::initLocalConnection()
{
    bRunning = false;
    QLocalSocket socket;
    socket.connectToServer(serverName);
    if(socket.waitForConnected(500))
    {
        bRunning = true;
        // 其他处理,如:将启动参数发送到服务端
        QTextStream stream(&socket);
        QStringList args = QCoreApplication::arguments();
        if (args.count() > 1)
            stream << args.last();
        else
            stream << QString();
        stream.flush();
        socket.waitForBytesWritten();

        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); // 再次监听
        }
    }
}


如何使用:

1:在.pro文件中添加 QT += network

2:main.cpp如下

#include "mainwindow.h"
#include "SingleApplication.h"


int main(int argc, char *argv[])
{
    //单实例进程,或者说防止程序多开
    SingleApplication a(argc, argv);

    if (!a.isRunning())
    {        
        MainWindow w;
        //传入一个要激活程序的窗口,当多开时会激活已有进程的窗口,且多开失败
        a.mainWindow = &w;
        w.show();

        return a.exec();
    }
    return 0;
}

如果有发现无法激活窗口的童鞋,请更换系统环境测试。


猜你喜欢

转载自blog.csdn.net/sunflover454/article/details/50426639