赞助

Qt 实现程序只运行一个实例,并激活已运行的程序

转载:https://zhuanlan.zhihu.com/p/639359628(参考此例子)

转载:https://blog.csdn.net/houxian1103/article/details/130736832

转载:https://blog.51cto.com/u_15692960/5405761?

转载:https://www.cnblogs.com/cnxkey/articles/15589182.html(QT 让任务栏图标闪烁)

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

1.QSharedMemory

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

2.文件锁

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

3.利用QLocalServer

要用到Qt的QLocalSocket,QLocalServer类,这两个类从接口上看和网络通信socket没有区别,但是它并不是真正的网络API,只是模仿了而已。这两个类在Unix/Linux系统上采用Unix域socket实现,而在Windows上则采用有名管道(named pipe)来实现

4.QtSingleApplication

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

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

image

 singleapplication.h

#ifndef SINGLEAPPLICATION_H_
#define SINGLEAPPLICATION_H_

#include <QObject>

class QWidget;
class QLocalServer;

class SingleApplication : public QObject {
    Q_OBJECT

public:
    explicit SingleApplication(const QString& key, QObject* parent = nullptr);

    bool isRunning();                // 是否已经有实例在运行
    QWidget* widget_;                       // 窗口指针

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 <QLocalServer>
#include <QLocalSocket>
#include <QApplication>
#include <QWidget>

SingleApplication::SingleApplication(const QString& key, QObject* parent)
    : QObject(parent)
    , widget_(NULL)
    , isRunning_(false)
    , localServer_(NULL) {
    serverName_ = key;

    initLocalConnection();
}
bool SingleApplication::isRunning() {
    return isRunning_;
}


// 说明:
// 通过socket通讯实现程序单实例运行,监听到新的连接时触发该函数

void SingleApplication::newLocalConnection() {
    QLocalSocket* socket = localServer_->nextPendingConnection();
    if (socket) {
        socket->waitForReadyRead(2 * 500);
        delete socket;

        // 其他处理,如:读取启动参数

        activateWindow();
    }
}


// 说明:
// 通过socket通讯实现程序单实例运行,
// 初始化本地连接,如果连接不上server,则创建,否则退出

void SingleApplication::initLocalConnection() {
    isRunning_ = false;

    QLocalSocket socket;
    socket.connectToServer(serverName_);
    if (socket.waitForConnected(500)) {
        fprintf(stderr, "%s already running.\n",
            serverName_.toLocal8Bit().constData());
        isRunning_ = true;
        // 其他处理,如:将启动参数发送到服务端
        return;
    }

    //连接不上服务器,就创建一个
    newLocalServer();
}

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 (widget_) {

        if (widget_->isMinimized()) {
            widget_->showNormal();
        }

        widget_->show();
        widget_->raise();
        widget_->activateWindow(); // 激活窗口
        QApplication::alert(widget_, 0);//任务栏闪烁提醒
    }
}

 

posted @ 2026-09-03 15:53  车臣  阅读(3)  评论(0)    收藏  举报