在Qt中激活已运行的应用程序实例

Qt生成的exe,如果已经运行,直接打开

示例1

main.cpp

复制代码
#include <QLocalSocket> //用于本地进程间通信
#include <QLocalServer>
​
​
bool isApplicationRunning(QLocalSocket &socket)
{
    //尝试连接到名为"AIGAME"的本地服务器
    socket.connectToServer("AIGAME"); // 使用唯一的应用名称  
    if (socket.waitForConnected(500)) {
        // QMessageBox::warning(nullptr, "警告", "应用程序已在运行中");
​
        //发送激活命令给已运行的实例
        socket.write("active");
        //等待数据写入完成
        socket.waitForBytesWritten();
​
        return true;
    }
​
    // 没有连接成功,说明没有实例在运行
    QLocalServer::removeServer("AIGAME"); // 清理可能的残留
    return false;
​
}
​
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
​
​
​
​
    //-------------
    //检查是否已有实例运行
    
    //创建本地socket对象
    QLocalSocket socket;
    if(isApplicationRunning(socket))
    {
        // return 0; //已有一个实例在运行,直接退出
        //如果已有实例,当前程序退出
        return 0; //已发送激活命令,当前实例退出
    }
}

index.cpp

复制代码
//创建本地服务器
​
    m_server = new QLocalServer(this);
    
    //连接服务器的newConnection信号到lambda表达式
    connect(m_server,&QLocalServer::newConnection,this,[this](){
        //获取待处理的连接
        QLocalSocket * socket = m_server->nextPendingConnection();
        //连接socket的readyRead信号到另一个lambda
        connect(socket,&QLocalSocket::readyRead,[this,socket](){
            //读取所有数据,检查是否是"activate"命令
            if(socket->readAll() =="active"){
                //显示窗口
                this->show();
                //设置窗口状态:取消最小化状态,设置为活动状态
                this->setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
                //将窗口提升到最前面
                this->raise();
                //激活窗口
                this->activateWindow();
​
            }
            //稍后删除socket对象
            socket->deleteLater();
        });
    });
    
    //尝试监听"AIGAME"服务器
    if(!m_server->listen("AIGAME"))
    {
        //如果监听失败,输出警告信息
        qDebug() <<"无法创建本地服务器"<<m_server->errorString();
    }

参考

要将单例检测改为激活已运行的应用程序而不是显示警告,你需要让两个实例之间能够通信。以下是完整的解决方案:

1. 修改单例检测和激活机制

复制代码
// 在main.cpp中添加
#include <QLocalSocket>
#include <QMessageBox>
​
bool isApplicationRunning(QLocalSocket& socket) {
    socket.connectToServer("AIGAME");
    if (socket.waitForConnected(500)) {
        // 发送激活命令给已运行的实例
        socket.write("activate");
        socket.waitForBytesWritten();
        return true;
    }
    QLocalServer::removeServer("AIGAME");
    return false;
}
​
// 在Index类中添加激活处理
class Index : public QMainWindow {
    Q_OBJECT
public:
    Index(QWidget *parent = nullptr);
    
private slots:
    void handleActivateRequest();
    
private:
    QLocalServer *m_server;
};
​
// 实现
Index::Index(QWidget *parent) : QMainWindow(parent) {
    // 创建本地服务器
    m_server = new QLocalServer(this);
    connect(m_server, &QLocalServer::newConnection, this, [this]() {
        QLocalSocket *socket = m_server->nextPendingConnection();
        connect(socket, &QLocalSocket::readyRead, [this, socket]() {
            if (socket->readAll() == "activate") {
                this->show();
                this->setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
                this->raise();
                this->activateWindow();
            }
            socket->deleteLater();
        });
    });
    
    if (!m_server->listen("AIGAME")) {
        qWarning() << "无法创建本地服务器:" << m_server->errorString();
    }
    
    // ... 其他初始化代码 ...
}
​
void Index::handleActivateRequest() {
    this->show();
    this->setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
    this->raise();
    this->activateWindow();
}

2. 修改main.cpp

复制代码
int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    
    // 检查是否已有实例运行
    QLocalSocket socket;
    if (isApplicationRunning(socket)) {
        return 0; // 已发送激活命令,当前实例退出
    }
    
    // 创建主窗口
    Index w;
    w.show();
    
    return a.exec();
}

3. 完整的工作流程

  1. 新实例启动:尝试连接"AIGAME"本地服务器

  2. 连接成功

    • 发送"activate"命令

    • 当前实例退出

  3. 已运行实例

    • 收到"activate"命令

    • 将窗口前置显示

  4. 首次运行

    • 创建本地服务器

    • 正常显示窗口

4. 跨平台注意事项

Windows平台优化

复制代码
// 在activate时添加Windows特有的前置方法
#ifdef Q_OS_WIN
#include <windows.h>
​
void bringToFront(HWND hwnd) {
    if (IsIconic(hwnd)) {
        ShowWindow(hwnd, SW_RESTORE);
    }
    SetForegroundWindow(hwnd);
}
#endif
​
// 在Index类中添加
void Index::bringToFront() {
    this->show();
    this->raise();
    this->activateWindow();
#ifdef Q_OS_WIN
    bringToFront((HWND)this->winId());
#endif
}

macOS平台优化

复制代码
#ifdef Q_OS_MAC
#include <objc/message.h>
#include <objc/runtime.h>
​
void bringToFrontMac(WId winId) {
    id nsApp = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
    ((void (*)(id, SEL, id))objc_msgSend)(nsApp, sel_getUid("activateIgnoringOtherApps:"), (id)YES);
}
#endif
​
// 在bringToFront方法中添加
#ifdef Q_OS_MAC
    bringToFrontMac(this->winId());
#endif

5. 增强的激活命令处理

复制代码
// 扩展命令处理
connect(socket, &QLocalSocket::readyRead, [this, socket]() {
    QByteArray command = socket->readAll();
    if (command == "activate") {
        this->bringToFront();
    } 
    else if (command.startsWith("open:")) {
        // 处理其他命令,如打开特定文件
        QString filePath = QString::fromUtf8(command.mid(5));
        this->openFile(filePath);
        this->bringToFront();
    }
    socket->deleteLater();
});

6. 错误处理和日志

复制代码
// 在服务器设置中添加错误处理
connect(m_server, &QLocalServer::acceptError, [](QLocalServer::LocalSocketError error) {
    qWarning() << "本地服务器错误:" << error;
});
​
// 在客户端连接中添加错误处理
if (!socket.waitForConnected(500)) {
    qDebug() << "连接已运行实例失败:" << socket.errorString();
    return false;
}

这样实现后,当用户尝试启动第二个实例时,第一个实例会被激活并前置显示,而不是简单地显示警告消息。

相关推荐
喜欢喝果茶.13 小时前
QOverload<参数列表>::of(&函数名)信号槽
开发语言·qt
亓才孓13 小时前
[Class类的应用]反射的理解
开发语言·python
努力学编程呀(๑•ี_เ•ี๑)13 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
island131413 小时前
CANN GE(图引擎)深度解析:计算图优化管线、内存静态规划与异构任务的 Stream 调度机制
开发语言·人工智能·深度学习·神经网络
坚持就完事了13 小时前
Java中的集合
java·开发语言
魔芋红茶13 小时前
Python 项目版本控制
开发语言·python
wjhx14 小时前
QT中对蓝牙权限的申请,整理一下
java·数据库·qt
踏过山河,踏过海14 小时前
【qt-查看对应的依赖的一种方法】
qt·visual studio
云小逸14 小时前
【nmap源码解析】Nmap OS识别核心模块深度解析:osscan2.cc源码剖析(1)
开发语言·网络·学习·nmap
冰暮流星14 小时前
javascript之二重循环练习
开发语言·javascript·数据库