四、Qt之保证本地只有一个应用程序启动,禁止多开(另QLocalServer、QLocalSocket使用案例)

SingleApplication.h

#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H

#include <QObject>
#include <QApplication>
class QMainWindow;
class QLocalServer;

class SingleApplication : public QApplication
{
    Q_OBJECT
public:
    SingleApplication(int &args, char **argv);
    bool getInstanceRunning() const; // 是否已经有实例在运行
    QMainWindow *getMainWindow() const;

    void setMainWindow(QMainWindow *value);

private slots:
    void newLocalConnection();

private:
    void initLocalConnection();  // 初始化本地连接
    void newLocalServer();       // 创建服务端
    bool instanceRunning;        // 是否已经有实例在运行
    QLocalServer *localServer;   // 本地socket Server(用于本地进程间通信)
    QString serverName;          // 服务名称
    QMainWindow *mainWindow;  // MainWindow指针
};

#endif // SINGLEAPPLICATION_H

SingleApplication.cpp

#include "singleapplication.h"

#include <QMainWindow>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#include <QFileInfo>
#include <QMessageBox>

SingleApplication::SingleApplication(int &args, char **argv) :
    QApplication(args, argv),
    instanceRunning(false),
    localServer(NULL),
    mainWindow(NULL)
{
    /**
     * 一般来说是取引用程序名作为 localServer 的进程服务名
     * 目前程序的进程名是根据文件名来的,但是一旦用于更改了文件名,那么进程名就不准确了,
     * 所以通过文件名来判断是进程服务是不可靠的,应该写死在代码里
     */
//    serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
    serverName = "TestServerName";
    initLocalConnection();
}

void SingleApplication::initLocalConnection()
{
    instanceRunning = false;
    QLocalSocket socket;
    //将套接字连接至进程服务,参数即为进程服务名
    socket.connectToServer(serverName);
    //若在500ms内连接至进程服务,说明进程服务已运行
    if (socket.waitForConnected(500)) {
        instanceRunning = 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); //再次监听
        }
    }
}

void SingleApplication::newLocalConnection()
{
    //监听进程服务,当有数据进来时,可以通过 nextPendingConnection() 获取套接字
    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();
        QMessageBox::warning(NULL, "警告", "程序已经启动!");
    }
}


// 说明:
// 检查是否已有一个实例在运行, true - 有实例运行, false - 没有实例运行

bool SingleApplication::getInstanceRunning() const
{
    return instanceRunning;
}

QMainWindow *SingleApplication::getMainWindow() const
{
    return mainWindow;
}

void SingleApplication::setMainWindow(QMainWindow *value)
{
    mainWindow = value;
}

main.cpp

#include "mainwindow.h"
#include <QApplication>

#include "singleapplication.h"

int main(int argc, char *argv[])
{
    SingleApplication a(argc, argv);
    if (!a.getInstanceRunning()) {
        MainWindow w;
        a.setMainWindow(&w);
        w.show();
        return a.exec();
    }

    return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值