在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;
}

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

相关推荐
yuan199972 分钟前
H264视频压缩matlab帧内预测帧间预测熵编码
开发语言·matlab
aini_lovee4 分钟前
基于MATLAB GUI的信号处理系统设计与实现
开发语言·matlab·信号处理
kylezhao201915 分钟前
C#上位机实现权限管理
开发语言·c#
古城小栈18 分钟前
rust 借用,三巨头之一
开发语言·rust
小北方城市网19 分钟前
第 9 课:Python 全栈项目性能优化实战|从「能用」到「好用」(企业级优化方案|零基础落地)
开发语言·数据库·人工智能·python·性能优化·数据库架构
superman超哥25 分钟前
Rust 内存泄漏检测与防范:超越所有权的内存管理挑战
开发语言·后端·rust·内存管理·rust内存泄漏
悟能不能悟37 分钟前
java HttpServletRequest 设置header
java·开发语言
云栖梦泽42 分钟前
易语言运维自动化:中小微企业的「数字化运维瑞士军刀」
开发语言
刘97531 小时前
【第23天】23c#今日小结
开发语言·c#
郝学胜-神的一滴1 小时前
线程同步:并行世界的秩序守护者
java·linux·开发语言·c++·程序人生