logo头像

技术引领生活!

Qt单实例运行

本文于2010天之前发表,文中内容可能已经过时。

在用Qt写程序时候可能遇到避免程序重复启动的问题,我们知道用MFC时有个FindWindow函数可以进行窗口查找于是想Qt能否实现呢,经过一番摸索和折腾终于搞定(测试环境为Win7和Ubuntu)

系列目录

本文是系列教程<跟随Designer源码学Qt>中的一篇详见跟随Designer源码学Qt

参考

一去二三里
具体见链接Qt学习一二三

根据大神的说明大致有三种:

  • QSharedMemory
  • QLocalServer
  • QtSingleApplication
    本文着重介绍QLocalServer,在大神的代码基础上修改了下使程序启动时判断如果已经启动则进行窗口显示

代码

废话不多说直接上硬货

头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H

#include <QApplication>
#include <QWidget>

class QLocalServer;
class QWidget;

class SingleApplication : public QApplication
{
Q_OBJECT

public:
SingleApplication(int &argc, char **argv);
~SingleApplication();

public:
bool isRunning();

//保存主窗口指针
void setSingleMainWindow(QWidget* w);

private slots:
void newLocalConnection();

private:
bool m_bRunning;
QLocalServer *m_pServer;
QWidget *m_widget;
};

#endif // SINGLEAPPLICATION_H

cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "singleapplication.h"
#include <QLocalSocket>
#include <QLocalServer>
#include <QFile>
#include <QTextStream>
#include <QWidget>
#include <QDebug>

static const char *ApplicationName = "myApp";

SingleApplication::SingleApplication(int &argc, char **argv):
QApplication(argc, argv),
m_mousePoint(0, 0),
m_mousePressed(false),
m_bRunning(false),
m_pServer(Q_NULLPTR),
m_widget(Q_NULLPTR)
{
setOrganizationName(QStringLiteral("MyProject"));
setApplicationName(QLatin1String(ApplicationName));

#if !defined(Q_OS_OSX)
setWindowIcon(QIcon(QStringLiteral(":/image/calcapp.webp")));
#endif

QString strServerName = QString("%1%2")
.arg(QCoreApplication::organizationName())
.arg(QCoreApplication::applicationName());

QLocalSocket socket;
socket.connectToServer(strServerName);

if (socket.waitForConnected(500)){
QTextStream stream(&socket);
QStringList args = QCoreApplication::arguments();
QString strArg = (args.count() > 1) ? args.last() : "";
stream << strArg;
stream.flush();

qDebug() << "Have already connected to server.";
socket.waitForBytesWritten();
m_bRunning = true;
}
else{
// 如果不能连接到服务器,则创建
m_pServer = new QLocalServer(this);

connect(m_pServer, SIGNAL(newConnection()), this, SLOT(newLocalConnection()));

if (m_pServer->listen(strServerName)){
// 防止程序崩溃,残留进程服务,直接移除
if ((m_pServer->serverError() == QAbstractSocket::AddressInUseError)
&& QFile::exists(m_pServer->serverName())){
QFile::remove(m_pServer->serverName());
m_pServer->listen(strServerName);
}
}
}

}

SingleApplication::~SingleApplication()
{

}

bool SingleApplication::isRunning()
{
return m_bRunning;
}


void SingleApplication::setSingleMainWindow(QWidget *w)
{
m_widget = w;
}


void SingleApplication::newLocalConnection()
{
QLocalSocket *pSocket = m_pServer->nextPendingConnection();
if (pSocket != Q_NULLPTR){
pSocket->waitForReadyRead(1000);

QTextStream in(pSocket);
QString strValue;
in >> strValue;
delete pSocket;
pSocket = Q_NULLPTR;

//如果窗口不为空,则前端显示
//核心代码
if(m_widget){
m_widget->showMaximized();
m_widget->activateWindow();
m_widget->raise();
}
}
}

用法

别忘了在pro文件中加上网络依赖
QT += network

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "singleapplication.h"
#include <QDialog>

int main(int argc, char *argv[])
{
SingleApplication a(argc, argv);

if (a.isRunning()){
return 0;
}

QDialog w;
w.show();

//保存指针用于显示
a.setSingleMainWindow(&w);
return a.exec();
}

遇到的坑

在Win7上可以随心所欲的运行,不料放到Ubuntu上之后崩的噼里啪啦,经过一番折腾终于找到个大坑

  1. 连接服务器的代码要放到构造函数中
  2. setApplicationName(QLatin1String(ApplicationName));中的参数要提前定义为static const char *

PS

在使用刘典武大神的代码时AppInit 也要放到SingleApplication的构造函数中,顺便说一句 QTimer::singleShot真香

PPS

你没有看错,我确实把大神的CSDN博客给撸下来,做成了高清无码的PDF….
嗯,爬虫在手,天下我有…..

支付宝打赏 微信打赏

您的支持是我前行的动力!