如何避免进程多开

这也是新年前的最后一篇记录了,今天说下关于进程多开的问题。

首先我先回答下上篇关于快捷键文章中最后的问题。可忽略。

1.能不能通过主框架进程检测键盘的消息,然后通知给子进程?

2.被主框架嵌套的子进程在获取到焦点后,主框架进程会不会失去焦点?

3.在上面2的条件下,主进程还能不能够检测到键盘事件了呢?

 少啰嗦:1.不可以。2.会。3.不能。

分析,由于是多进程,虽然主界面进程窗口嵌套了子进程的窗口,但是进程之间是独立的。当一个窗口被激活时候,必定其余窗口会取消了激活状态,至于顶层的窗口也只能是一个。这时候被激活窗口是可以监听到键盘事件的,使用进程键盘钩子也是可以的。但是当这个窗口没有被激活时候,窗口也是不会监听到键盘事件的,所以多进程条件下想要通过父进程传递键盘信息数据给子进程,并不能完全解决问题。那么到底如何解决呢?

QT QWidget窗口是可以设置接受焦点事件的方式的,我们可以通过点击或者tab按键的方式等设置使得窗口被激活。然后从而监听对应的键盘事件,然后所有的快捷键统一处理。不多说了,说今天内容。

如何使得进程只打开一个?

我们在开发中会经常遇到,要求进程单开,那么有什么好的方法可以使得进程单开?

期初,自己听说这个需求时候,不知道如何去实现,自己换傻傻的在进程中设置全局变量,想通过对比是判断,想在想想都觉得那时候自己好笑。那么如何实现呢?方法很多,但其实就是进程间通信问题。下面简单说两种方法。

1.通过共享内存去实现,在进程启动时候,先判断特定的内存中有没有数据,有数据不启动进程,没数据,启动进程,同时在共享内存中写入数据。

2。使用本地通信,程序启动时候,连接一个服务,连接失败,自己启动服务,连接成功,客户端就退出,说明已经有启动了。

 

不多说,直接看代码,                                   

#ifndef __CLIENTFRAME_SINGLEAPPLICATION_H__
#define __CLIENTFRAME_SINGLEAPPLICATION_H__

#include <QObject>
#include <QApplication>
#include <QtNetwork/QLocalServer>
#include <QWidget>

class CSingleApplication : public QApplication
{
	Q_OBJECT

public:
	// 构造函数
	// int & argc: 
	// char * * argv: 
	// :
	CSingleApplication(int &argc, char **argv);

	// 是否已经有实例在运行
	// bool: true 有 false 无
	bool GetRunning() const;

	// 设置第二次运行时,提示重复运行后激活的窗口
	// const QWidget * ptrWidget: 
	// void:
	void SetActivateWindow(const QWidget* ptrWidget);

private slots:
	// 监听到新的连接时触发该函数
	void NewLocalConnection();

private:
	// 初始化本地连接,如果连接不上server,则创建,否则退出
	void InitLocalConnection();

	// 创建服务端
	void NewLocalServer();

	// 激活窗口
	void ActivateWindow();

private:
	// 是否已经有实例在运行
	bool brunning_;

	// 本地socket Server
	QLocalServer *ptr_local_server_;

	// 服务名称
	QString str_server_name_;

	// 激活的窗口
	QWidget *ptr_activate_window_;
};

 


#include "SingleApplication.h"
#include <QtNetwork/QLocalSocket>
#include <QFileInfo>

#define TIME_OUT                (500)    // 500ms

CSingleApplication::CSingleApplication(int &argc, char **argv)
	: QApplication(argc, argv),
	  brunning_(false),
	  ptr_local_server_(NULL),
	  ptr_activate_window_(NULL)
{
	// 取应用程序名作为LocalServer的名字
	str_server_name_ = QFileInfo(QCoreApplication::applicationFilePath()).fileName();

	InitLocalConnection();
}

// 是否已经有实例在运行
bool CSingleApplication::GetRunning() const
{
	return brunning_;
}

// 设置第二次运行时,提示重复运行后激活的窗口
void CSingleApplication::SetActivateWindow(const QWidget* ptrWidget)
{
	ptr_activate_window_ = const_cast<QWidget*>(ptrWidget);
}

// 监听到新的连接时触发该函数
void CSingleApplication::NewLocalConnection()
{
	if (NULL == ptr_local_server_)
	{
		fprintf(stderr, "ptr_local_server_ is null.\n");
		return;
	}

	QLocalSocket *ptr_socket = ptr_local_server_->nextPendingConnection();
	if (NULL != ptr_socket)
	{
		ptr_socket->waitForReadyRead(2 * TIME_OUT);
		delete ptr_socket;

		// 其他处理,如:读取启动参数
		ActivateWindow();
	}
}

// 初始化本地连接,如果连接不上server,则创建,否则退出
void CSingleApplication::InitLocalConnection()
{
	brunning_ = false;

	QLocalSocket socket;
	socket.connectToServer(str_server_name_);
	if (socket.waitForConnected(TIME_OUT))
	{
		fprintf(stderr, "%s already running.\n", str_server_name_.toLocal8Bit().constData());
		brunning_ = true;

		// 其他处理,如:将启动参数发送到服务端
		return;
	}

	//连接不上服务器,就创建一个
	NewLocalServer();
}

// 创建服务端
void CSingleApplication::NewLocalServer()
{
	if (NULL != ptr_local_server_)
	{
		fprintf(stderr, "ptr_local_server_ already new.\n");
		return;
	}

	ptr_local_server_ = new QLocalServer(this);
	connect(ptr_local_server_, SIGNAL(newConnection()), this, SLOT(NewLocalConnection()));
	if (!ptr_local_server_->listen(str_server_name_))
	{
		// 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之
		if (ptr_local_server_->serverError() == QAbstractSocket::AddressInUseError)
		{
			QLocalServer::removeServer(str_server_name_); // <-- 重点
			ptr_local_server_->listen(str_server_name_); // 再次监听
		}
	}
}

// 激活窗口
void CSingleApplication::ActivateWindow()
{
	if (NULL != ptr_activate_window_)
	{
		ptr_activate_window_->show();
		ptr_activate_window_->raise();
		ptr_activate_window_->activateWindow();
		ptr_activate_window_->setFocus();
	}
}

上面代码中有该功能,多余的代码请直接忽略,总在床上写,操作不方便,就不做整理了。

当然我们写QT客户端的人都清楚QApplication类,很多初始化,或者关于程序的设置以及消息分发都可以在重写这个类时候做处理。具体QApplication的一些方法我不多少,直接谷歌就行。

 

通过上面的代码,你应该已经实现了进程单利化了吧。千言万语都不如源码说明的清楚啊。还是用代码比较方便。

如果你看到这里了,那我会告诉你接下来的一篇文章会是什么内容。

最近开发中看到有些监控的画面,播放视频的窗口可以多窗口播放,并且多窗口的布局是自定义的,年后我会针对自定义窗口来分析下如何实现自己的布局。同事最近在调试信息会用到windebug,也会将如何使用windebug的使用简单总结。

别的就不说了,准备明天回家过年。   在这里祝福所有技术人员能够在新的一年里,有所学,有所得,事事开心快乐。                        

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

          

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值