迁移通知
本站内容正在逐步向 https://www.weiran.ink 迁移,更新内容请到新站查找。
通过Qt优雅地调用命令行计算程序并抓取输出显示在窗口上
编写大型工程计算软件时,计算核心与图形操作界面混在一起不是一个好的实践。一则不容易实现跨平台,二则难以在非图形环境下部署和使用,三则这样写容易让二者的代码混在一起提高维护难度,四则图形库往往引入不必要的性能开销和难以预知的输入。所以,分别单独实现计算核心和图形操作界面,然后通过命令行调用、消息输出是一个很合适的方案。
这些天基于Qt
搞了一个这样一套方案,同时以此为契机搞清楚了Qt
的信号(signal)/槽(slot)
机制,这里做一个总结。
功能点
- 使用特定的命令行参数启动计算核心
- 实时抓取计算核心的输出,显示在图形界面上
- 计算过程中要保持GUI的正常响应
实现
调用计算核心
比较容易,Qt
已经提供了很好的封装:
computeProcess.setProgram(launchOption.executable); computeProcess.setArguments(launchOption.arguments); computeProcess.setWorkingDirectory(launchOption.runDirectory); computeProcess.start(); while (!computeProcess.waitForFinished()) { QThread::sleep(1); } emit computingFinished(computeProcess.exitStatus() == QProcess::NormalExit);
launchOption
就是个结构体,存放了一些字符串。start
是实际启动外部程序。computeProcess.waitForFinished()
看名字是等待到程序结束,但实际上默认最长只等三十秒,然后就返回一个false
回来。理论上可以传一个参数让他永久等待,不过想想还是用一个循环多次调用它比较好,需要的话,循环里面可以做一些别的事情,比如计数什么的。
最后一句emit ...
是发送一个信号,信号中包含了一个数据:程序是否正常退出。
抓取计算核心的输出
可以对Process
对象执行相关的抓取函数来获得。但是单开一个线程反复尝试抓取(我在Java
里面就是这样干的!)相当的不优雅。利用Qt
的消息机制,可以将他们封装为信号:
// 在一个继承了QObject的类中 // 已经声明了: // public slots: // void doCompute(); // 以及 // signals: // void newMessageIncoming(QString newMessage, bool isError); // void computingFinished(bool isExitedNormally); connect(&computeProcess, &QProcess::readyReadStandardOutput, [this]() { emit newMessageIncoming(computeProcess.readAllStandardOutput(), false); }); connect(&computeProcess, &QProcess::readyReadStandardError, [this]() { emit newMessageIncoming(computeProcess.readAllStandardError(), true); });
等于是,把Process
中Qt原生提供的的“有标准输出/错误输出”信号,连接到了两个lambda
表达式史上,这两个表达式所执行的内容则是读出所有的新来的信息,并且将他们封装到一个自定义的信号newMessageIncoming
中,发射出去。
对于信号的槽的几点认识:
- 最后更改: 2025/05/10 05:59