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. 完整的工作流程
-
新实例启动:尝试连接"AIGAME"本地服务器
-
连接成功:
-
发送"activate"命令
-
当前实例退出
-
-
已运行实例:
-
收到"activate"命令
-
将窗口前置显示
-
-
首次运行:
-
创建本地服务器
-
正常显示窗口
-
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;
}
这样实现后,当用户尝试启动第二个实例时,第一个实例会被激活并前置显示,而不是简单地显示警告消息。