这也是新年前的最后一篇记录了,今天说下关于进程多开的问题。
首先我先回答下上篇关于快捷键文章中最后的问题。可忽略。
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的使用简单总结。
别的就不说了,准备明天回家过年。 在这里祝福所有技术人员能够在新的一年里,有所学,有所得,事事开心快乐。