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

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

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript