多进程界面开发-Qt试玩儿
一、概述
做客户端开发已经有好几个年头了,今天看到同事发了一篇关于富途牛牛的文章,核心思想就是想说,新版本的富途支持多进程架构了,效率大大提升啦,可以更好的适应多核cpu,提高软件运行效率。
听到这个消息,我不仅感叹,我靠,真的好牛逼。
但是心里又在默默的想,这个东西到底有什么好处,多进程写界面!!!从来没这么搞过呀,会不会有坑,到底比多线程好在了哪里?带着这个问题,从百度上看了几篇相关文章,其中一些是线程和进程的区别文章,而更多的还是关注多进程界面怎么去开发。
资料真是少的可怜,而且都不是特别全面。所以自己打算深入的写写这方面的东西
其实很早以前就接触过多进程,只是自己好像也没有想那么多,一直对多进程架构的概念不是那么清晰。今天和同事聊了一些相关话题,感觉自己的知识面豁然开朗,要学习的东西好像还挺多。
看下面这张图,是任务管理器的应用截图,以前还真是没发现,居然我自己用的这么多应用都是多进程架构的。
我们平时最常用的chrome浏览器,客户端版本微信,还有有道云笔记等等
有了这么多的多进程架构开发的客户端软件,难道说多进程开发已经是势在必行了?
说这么多,还不如来点儿实际的干货,这篇文章是我初步开始使用多进程开发端产品的尝试,有不对的地方欢迎大家指出,可以给出更好建议
二、效果展示
下面是我做的一个demo程序截图,测试程序中一共包含了4个使用场景,分别是:
- qt嵌入系统自带计算机
- qt嵌入系统自带记事本
- qt调用系统ping命令,并收集结果
- qt嵌入其他qt可执行程序
大家可以先看看效果图,如果觉着有价值的可以继续往下看,下面我会分章节把四个事例进行讲解。
三、使用方法
首先需要清楚,我们是多进程界面开发,那么我们的exe启动后,势必是需要启动其他可执行程序的,并且把其他进程的界面嵌入到我们的窗口中来,代码执行流程可能像这样。
1、启动外部进程
启动外部进程有多种方式,qt使用比较习惯的同学可以直接使用qprocess类,这个类是qt封装的一个跨平台的类。
启动方式可能像下面这样
qprocess * myprocess = new qprocess(this); qstringlist arguments; myprocess->start("c:/windows/system32/notepad.exe"); myprocess->waitforfinished(2000);
除过qprocess之外,windows系统上我们还可以使用createprocess方法来创建进程。
qstring cmd = "c:/windows/system32/calc.exe"; startupinfo si = { sizeof(si) }; process_information pi; si.dwflags = startf_useshowwindow; si.wshowwindow = true; bool bret = createprocess( null, (lpwstr)cmd.tostdwstring().c_str(), null, null, false, create_new_console, null, null, &si, &pi);
2、创建qt窗口
外部进程启动后,我们可以在任务管理器中找到启动的进程
接着我们需要使用spy++工具进行查看外部进程的类名称和窗口名称,并使用findwindow接口进行查找,找到这个进程的主窗口句柄后,嵌入到我们的程序中来。
类名和窗口名称查找过程可以参考外部进程嵌入到qt进程界面这篇文章中的内容。
wid wid = (wid)findwindow(qstringliteral("notepad").tostdwstring().c_str() , qstringliteral("无标题 - 记事本").tostdwstring().c_str()); qwindow * window = qwindow::fromwinid(wid); if (window) { window->setflags(window->flags() | qt::customizewindowhint | qt::windowtitlehint); //这边可以设置一下属性 qwidget * widget = qwidget::createwindowcontainer(window, this, qt::widget); }
如上代码所示,我们如果找到外部进程的主窗口句柄后,就可以使用qt提供的createwindowcontainer这个接口进行创建qwidget,并加入到我们的程序中来。
3、加入到主进程布局
外部进程被封装成为一个qwidget后,我们只需要加入到自己的布局中即可。
ui.verticallayout_2->addwidget(widget);
接下来我们分别讲解不同场景下的多进程界面开发的简单使用
四、嵌入notepad
第三小节已经把嵌入其他程序的流程大致说了一遍,这里我就不在详细说明了,直接给出具体代码。
代码中比较关键的有2个地方
- qprocess不能使用临时变量,要不然函数执行完毕notepad.exe进程也就退出了。
- findwindow的两个参数,一个是类名,一个窗口标题栏名称,这两个信息都可以用个spy++进行查找。
void embedcalculate::on_pushbutton_2_clicked() { //创建进程 qstring cmd = "c:/windows/system32/notepad.exe"; qprocess * myprocess = new qprocess(this); qstringlist arguments; myprocess->start(cmd); myprocess->waitforfinished(2000); wid wid = (wid)findwindow(qstringliteral("notepad").tostdwstring().c_str() , qstringliteral("无标题 - 记事本").tostdwstring().c_str()); qwindow * window = qwindow::fromwinid(wid); if (window) { window->setflags(window->flags() | qt::customizewindowhint | qt::windowtitlehint); //这边可以设置一下属性 qwidget * widget = qwidget::createwindowcontainer(window, this, qt::widget); ui.verticallayout_2->addwidget(widget); } }
五、调用ping命令
ping命令使用场景主要是想展示主进程和外部进程是怎样通信的,虽然这个事例比较简单,但也算是两者之间发生了信息交换
子进程在执行完ping一个地址之后,会把得到的结果传递给主进程,主进程使用readall函数全部读入到主进程中。
void embedcalculate::on_pushbutton_3_clicked() { //创建进程 qprocess * myprocess = new qprocess(this); connect(myprocess, static_cast<void (qprocess::*)(int)>(&qprocess::finished), this, [this, myprocess](int exitcode){ if (exitcode == 0) { qtextcodec * gbkcodec = qtextcodec::codecforname("gbk"); qstring result = gbkcodec->tounicode(myprocess->readall()); ui.textedit->settext(result); } }); //myprocess->start("cmd.exe", qstringlist() << "/c" << "ping www.baidu.com"); myprocess->start("cmd.exe", qstringlist() << "/c" << "ping " + ui.lineedit->text().trimmed()); myprocess->waitforfinished(2000); ··· }
六、嵌入其他qwidget窗体
虽然这个东西是最后讲的,但是这个才是重头戏,有了这个实验之后,我们以后的qt多进程界面开发也可以进行投入正式环境了。
如下所示,childwidget外部程序的主窗体被我们嵌入到了embedcalculate这个进程的主界面上,突然觉着好神奇,给自己点赞,哈哈哈哈。
由于我这里的childwidget外部程序和embedcalculate主程序在一个目录中,因此cmd变量直接就指向了childwidget这个外部程序的名称。
其他部分的代码基本上就和前边几种使用场景差不多。
void embedcalculate::on_pushbutton_4_clicked() { //创建进程 qstring cmd = "childwidget.exe"; qprocess * myprocess = new qprocess(this); qstringlist arguments; myprocess->start(cmd); myprocess->waitforfinished(2000); wid wid = (wid)findwindow(qstringliteral("qt5qwindowicon").tostdwstring().c_str() , qstringliteral("childwidget").tostdwstring().c_str()); qwindow * window = qwindow::fromwinid(wid); if (window) { window->setflags(window->flags() | qt::customizewindowhint | qt::windowtitlehint); //这边可以设置一下属性 qwidget * widget = qwidget::createwindowcontainer(window, this, qt::widget); ui.verticallayout_3->addwidget(widget); } }
七、相关文章
以上的内容,基本上就是本篇文章的内容所有内容啦!初步完成了qt内嵌其他进程界面的功能,希望可以帮到大家。
很重要--转载声明
本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者: or twowords
如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。