Qt界面程序嵌入另一个Qt界面程序[Linux]

  • Qt的界面程序出现的问题
  • Qt处理问题的传统方法
  • 传统方法的缺陷
  • 多进程界面开发
  • 示例代码
  • 结语

Qt的界面程序出现的问题

在Qt界面程序里,主线程是界面线程,并且有且只有主线程才能完成界面的渲染操作,这样就会带来问题。一旦主进程一直处于一个非常耗时的函数中(如构建一个庞大的界面、处理大量的数据),无法处理事件循环中积压的事件以及回调,那么整个界面都会处于未响应状态。

Qt处理问题的传统方法

  1. 方法1 常规的处理方式,也是Qt官方的处理方式是调用 processEvents() 函数,在长期占用主线程的函数的合适地方不断地调用该函数,这样就可以不断处理各种积压的界面刷新动作、用户操作响应等
  2. 方法2 另一种处理方式,可以将数据的处理放置于另一个线程中处理,这样就可以解放主线程,让主线程专心应对于界面相关的工作。

传统方法的缺陷

有一种情况,上述两种方式都无法处理。比如说,程序在收到某个消息时创建一个新的界面,而创建这个界面非常耗时,在这种情况下,首先方法2是无法使用的,因为这是界面控件的创建必须在主线程。

然后是方法1,方法1存在风险,设想这样一个情况,程序收到消息 M_A 将数据 dataA 存储在对象 * structA* 上,然后界面 WidgetA 根据 dataA 来创建控件,在创建 widgetA 的中途中调用 processEvents() ,这时又收到一次消息 M_B ,那么调用processEvents()就会处理该消息的对应的函数,那么就会把 dataB 存在对象 structA 上,就会将原本的 dataA 数据给覆盖,那么一旦 processEvents() 结束,回到WidgetA的创建函数,但此时的数据已经不是原来的数据了,这样就会带来未知的后果。所以说,需要确保事件队列的所有动作不影响本函数(调用 processEvents() 的函数),才能调用 processEvents() 函数。

那么至少,我们在加载又大又多的界面时,需要给用户一个等待条的提示,这样才能避免界面未响应的不良效果。那等待条在加载界面时是无法刷新的,界面的刷新需要不断处理事件队列里关于绘制的事件,处理事件队列需要调用 processEvents() 函数,但是该函数是一股脑的把所有积压的事件处理了(当然Qt的 processEvents() 可以过滤用户动作产生的事件),只要其中有一个事件对正在进行创建的界面产生了影响,那么就会出现问题,那么这种情况下有什么解决方案呢?当然有,多进程界面开发。

多进程界面开发

参考blog:
https://www.cnblogs.com/swarmbees/p/11100513.html
https://blog.csdn.net/u013394556/article/details/78534833
https://blog.csdn.net/r5014/article/details/79286444

既然主线程的随心的调用processEvents(),而我们又需要刷新等待界面,而刷新界面必须主线程,既然如此,那就再创建一个主线程不就好了么!但是一个进程只有一个主线程啊,所以说我们需要再创建一个界面进程,然后把这个子界面进程嵌入到主界面进程当中,在主界面进程忙于工作时,子界面进程仍可以不断刷新窗口,这样就可以避免给用户界面未响应的体验。

关键函数:
QWindow::fromWinId(winId),可以通过句柄返回一个window对象
QWidget::createWindowContainer(), 可以为QWindow创建一份widget对象

示例代码

子窗口进程:
main.cpp

#include <QApplication>
#include <QDebug>
#include <stdio.h>
#include <QLabel>
#include <QMovie>
#include <QWindow>int main(int argc, char *argv[])
{if(argc == 2){QApplication a(argc, argv);//这里是子窗口的顶层窗口QLabel w;QMovie movie(&w);movie.setFileName("XXX.gif");w.setMovie(&movie);movie.start();//endWId wid = WId(QString(argv[1]).toInt());//通过参数列表获取父进程窗口的WinIdQWindow *window = QWindow::fromWinId(wid);//获取父进程窗口w.setProperty("_q_embedded_native_parent_handle", QVariant(wid));//设置属性,这句是必须的w.winId();//必须调用一次,生成winIdw.windowHandle()->setParent(window);//设置父窗口w.show();//最后调用show,提前调用qt会为其生成窗口控件,这样就会和你原本想要嵌入进的父进程界面产生冲突fprintf(stderr, "%lld", w.winId());//写入标准错误输出,stderr能立即输出,stdout则不行return a.exec();}return 0;
}

主窗口进程
waitingbarwin.h

#ifndef WAITINGBARWIN_H
#define WAITINGBARWIN_H#include <QWidget>namespace Ui {
class WaitingBarWin;
}class QProcess;class WaitingBarWin : public QWidget
{Q_OBJECTpublic:explicit WaitingBarWin(QWidget *parent = 0);~WaitingBarWin();private:Ui::WaitingBarWin *ui;QProcess *m_process;private slots:void slot_createWaitingBar();
};#endif// WAITINGBARWIN_H

waitingbarwin.cpp

#include "waitingbarwin.h"
#include "ui_waitingbarwin.h"#include <QProcess>
#include <QDebug>
#include <QWindow>
#include <QPixmap>
#include <QBitmap>WaitingBarWin::WaitingBarWin(QWidget *parent) :QWidget(parent),ui(new Ui::WaitingBarWin),m_process(nullptr)
{ui->setupUi(this);QPixmap pixmap;pixmap.load("XXX.gif");setFixedSize(pixmap.size());setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);setMask(pixmap.mask());if(m_process == nullptr){QString cmd = "WaitingBar";//子程序执行文件地址QStringList argList;argList << QString::number(this->winId());//把父窗口的id给子进程传递过去m_process = new QProcess(this);//使用进程运行子进程窗口connect(m_process, &QProcess::readyReadStandardError, this, &WaitingBarWin::slot_createWaitingBar);//等待子进程窗口把自身的winId传递过来m_process->start(cmd, argList);}
}WaitingBarWin::~WaitingBarWin()
{delete ui;m_process->terminate();//在父窗口关闭时,主动终止子窗口进程m_process->waitForFinished(50);
}void WaitingBarWin::slot_createWaitingBar()
{quint64 winId = m_process->readAllStandardError().toLongLong();QWindow *childWin = QWindow::fromWinId(winId);if(childWin){QWidget *widget = QWidget::createWindowContainer(childWin);//获取一个子进程窗口的widgetui->verticalLayout->addWidget(widget);//这里是可以使用布局器管理子进程窗口的,不管理的话就在坐标0,0处}
}

main.cpp

#include "waitingbarwin.h"
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>int main(int argc, char *argv[])
{QApplication a(argc, argv);QPushButton win;win.show();WaitingBarWin w(&win);//测试,主进程陷入长时间工作时,子进程窗口仍然正常刷新QObject::connect(&win, &QPushButton::clicked, [&w](){w.show();while (1) {}});return a.exec();
}

结语

关于windows平台的使用我没有测试,网上也大多是windows平台的,感觉是获取winId的方式可以使用windows系统的函数实现,这样就可以去嵌入更多的应用。linux平台的获取WinId的方法我暂时没有实现,只是通过Qt自带的方式获取本进进程界面的WinId,如果想要嵌入其他程序,能找到WinId的话理论上是可行的。

Qt界面程序嵌入另一个Qt界面程序[Linux]相关推荐

  1. Linux下 Qt界面程序嵌入另一个Qt界面程序_Qt应用嵌入外部进程窗口

    项目工程的实现,想要使用多个程序进行实现,在里面存在一定的调用的过程:调查的情况如下 Qt界面程序嵌入另一个Qt界面程序[Linux] Qt界面程序嵌入另一个Qt界面程序[Linux]_ptc321的 ...

  2. 一、Qt初尝试,做一个QT计算器《QT 入门到实战》

    学习目标 了解 qt 的基本信息 了解 qt 的下载及安装 了解创建一个基本 qt 项目的流程 了解信号与槽 通过示例了解信号与槽的设置与编写 了解控件添加的方式 了解控件如何使用代码获取其文本 了解 ...

  3. 如何从当前窗口界面切换到另一个窗口界面

    如何从当前窗口界面切换到另一个窗口界面 在程序中,经常会在不同的窗口界面中互相切换.本文,将介绍如何进行窗口界面的切换. 下面采用的示例以文章<在程序代码中设定控件调用的方法 >代码为基础 ...

  4. 【PYTHON】tkinter如何设置界面消失 当制作一个登陆界面时,登陆成功之后,如何让登陆界面本身消失...

    tkinter如何设置界面消失 当制作一个登陆界面时,登陆成功之后,如何让登陆界面本身消失 tkinter如何设置界面消失 当制作一个登陆界面时,登陆成功之后,如何让登陆界面本身消失 1 if que ...

  5. 候选人选票程序:设计一个候选人选票程序。假设有3个候选人,在屏幕上输入要选择的候选人姓名,有10个人进行投票,最后输出每个人的得票结果。

    候选人选票程序:设计一个候选人选票程序.假设有3个候选人,在屏幕上输入要选择的候选人姓名,有10个人进行投票,最后输出每个人的得票结果. 声明结构体类型并定义结构体变量.代码如下: struct ca ...

  6. Qt入门01 创建第一个Qt程序

    一.安装Qt及Qt Creator 1.Qt下载地址 常用的工具也在这些地方可以找到,当然也可以直接官网下载,考入到网速因素,国内的镜像源网站还是要更快一些.Qt 5.15 之后已经不提供离线安装包了 ...

  7. Qt学习笔记(一) 第一个Qt应用程序

    使用Qt Creator向导创建一个QtGui应用程序,会生成一个.pro工程定义文件和几个.h/.cpp源代码文件. 首先看工程定义文件的内容: QT       += core gui TARGE ...

  8. QT学习——Qt工具介绍,Qt助手使用,第一个Qt程序,Qt字符串和字符编码

    一.Qt主要工具介绍 1)qt助手(assistant) 2)qt构建器(qmake) 3)qt设计师(designer) 4)qt转换器(uic) 5)qt资源编译器(rcc) 6)qt元对象编译器 ...

  9. python可视化界面编程 pycharm_pycharm开发一个简单界面和通用mvc模板(操作方法图解)...

    文章首先使用pycharm的 PyQt5 Designer 做一个简单的界面,然后引入所谓的"mvc框架". 一.设计登录界面 下面开始第一个话题,使用pycharm的 PyQt5 ...

  10. java ee 程序_第一个 JavaEE 应用程序 - JavaWeb 入门开发教程

    第一个 JavaEE 应用程序 JavaEE 是 Java Web 开发当中事实上的标准,诸多框架也都是建立在 JavaEE 的 API 基础之上的.为了从头理解 Java Web 开发,我们将从一个 ...

最新文章

  1. jquery 选择时间(小时)区间(四)
  2. Windows 7 几个小问题的解决方法(二)
  3. 鼠标事件onmouuse大全
  4. Android 解析AsyncTask(一)
  5. php支持cs吗,关于composer、phpmd和phpcs于windows中的安装与使用方法
  6. Java基础知识强化之集合框架笔记27:ArrayList集合练习之去除ArrayList集合中的重复字符串元素...
  7. python编译exe运行慢_Python运行速度慢你知道这是为什么吗?
  8. oracle_jdbc新建实例,JDBC的操作步骤和实例
  9. 【练习】删除表中的分区
  10. Protocol Buffers动态消息解析
  11. 启用iptables后,连接速度很慢
  12. 运输问题中产销不平衡问题(表上作业法和LINGO方法)
  13. python的交并补_Python 集合的交差并补操作及方法
  14. c++win32项目 如何显示后再删除一个绘图_Golden Software Surfer(三维绘图软件) 中文版分享...
  15. 句子反转:小米笔试编程题目——python
  16. Java与Android配合开发ICQ、2018-8-4
  17. Telegram 查看下载保存的文件
  18. 鼠标移动到的地方一直往右移动的解决办法
  19. PHP和apache的三种连接示例------转自骏马金龙博客
  20. centos6.9 yum安装中出现Loading mirror speeds from cached hostfile No package......

热门文章

  1. 【备忘】传智播客黑马程序员28期JavaEE基础及就业班视频教程
  2. idea部署启动ssm项目
  3. matlab画中国,用matlab绘制中国地图
  4. matlab有限元分析程序,matlab有限元分析与应用(书及源程序)
  5. 电路分析之《变压器》
  6. Java中获取时间戳
  7. plsql如何显示表结构图_如何用PLSQL导出数据库存表结构信息
  8. 用旧电脑安装黑群晖系统
  9. 基于LDA模型的知网Python论文主题挖掘
  10. 高效率OCR场景文字图片合成工具发布!