qt

抱一只橘 461 0
温馨提示

本篇为windows(桌面)开发的第四篇,上一篇为《python自动化办公教程》,在本篇我将对qt为主的桌面客户端开发技术进行分析。

一、项目构成

 

  • 概况
    • 开源协议:lgpl和gplv2
    • qt
    • qt生态链:商业版需要付费,否则只能开源。qss自由度有,
      • 但是组件库收费:一个模仿WPF UI的国内库(GitHub - zhiyiYo/PyQt-Fluent-Widgets at Qt5
      • 跨平台:已经不是优势,音视频处理领域有一定优势。
      • 嵌入式:没优势,低端的用mingui、lgvl;高端的用Android。
    • mfc和.net的生态链:需要微软的Visual studio授权,如果是.net framework甚至要购买Window Server。
      • ui组件库:WPF UI、Win UI都是微软主推的,主要给的就是vs授权。
    • electron:开源,qt开发者都在转。
    • Linux平台:开源核心优势在那,但也细分领域。
      • Android内核:是最高级的,也是最流行的,上个好的arm芯片要不了多少钱。例子:收银机、车机
      • 自研:基本上还是二次开发,例如3d打印领域的klipper。纯自研可以用qt,最近出现了lgvl。

 

  • IDE:qt creator
    • 设计器 qt designer:非常类似于winform
    • 构建器:qmake、极度相似与Cmake(makefile)
    • 编译器:gcc 32位、msvc等都行
      • 设置msvc:本意是在命令行中设置编译环境,即独立于vs之外进行命令行编译开发。现在qt直接提供入口即可。
      • qt
    • 帮助文档:
      • qt core:核心库
      • qt gui:基于openGL的组件库
    • 快捷键:
    • qt

 

  • widgets app:
  • qt
    • sources源码窗口:QmainWindow类,体现为头文件
      • QApplication:是qt应用程序,执行exec()即阻塞生成桌面。底层就是基于消息循环的概念
      • MyWindow:主要窗口,生成ui界面,和qmainwindow的区别是有无菜单,执行show()方法
      • qt
    • Forms:.ui文件——运行时编译成cpp文件
      • 对应的cpp文件为:mywindow、mywidget等里面的UI子对象
      • 本质:designer来设计,自动生成代码放进容器类里,和winform逻辑一致。
    • Headers:专门放头文件
    • .pro文件:项目配置相当于qmake的Makefile文件
      • 编译:模块、源文件、ui文件
      • qt

 

  • 编译和构建:
    • 项目结构:只能ide里调试qt
    • 完整的dll项目:
    • qt

 

 

  • event filter:全局事件拦截器
    • 作用:让一些不常规的事件触发
    • qt

 

 

二、q widget页面

  • 界面:和安卓高度相似,有特色的cpp库
    • 对象树:Qlist记录子对象树,方便析构
    • gc:系统根据parent指针会调用父类的析构,自动析构所有对象。
      • qt
      • QObject 对象通过 setParent() 方法设置了其父对象后,就会被添加到父对象的对象树中。当父对象被销毁时,它会自动递归销毁其所有子对象,从而避免了内存泄漏问题。
    • Q_OBJECT宏:qobject的特点,信号槽函数都在此

 

 

  • 设计器:只能说和winform没区别
    • 查看继承结构:qt
    • 生成文件:ui_wight/ui_mainwindows
      • 在窗口类里被定义在Ui命名空间里引用qt
      • cpp里初始化指针:qt
      • 初始化成员列表:这里用到了ui(new Ui::Widget),一个快速赋值的技巧语法糖,相当于=赋值。这种写法也有助于避免潜在的资源泄漏问题,因为如果在构造函数初始化列表中出现了异常,构造函数会在对象被完全创建之前终止,从而避免资源泄漏。
      • 底层原理:
        • setupUI():创建组件和属性、
        • 关联槽函数:qt
        • 类定义:意思就是ui::Widget被包含了,之前已经声明,实现了可视化设计功能。
        • qt
        • 不用设计器:就没有ui指针,直接在窗口widget文件下定义和操作:qt

 

 

  • 窗口开发:
    • 1.先加layout(div):里面的组件自动垂直或水平划分
    • 2.菜单栏:设置tab顺序、快捷键获取焦点等
    • qt
    • 3.手动创建组件实例:一般用iniUI()函数,是手动创建ui。
      • 对比Android:是用xml设计居多,而非代码。qt
    • qtqt
    • Qdialog:
      • 与mainwindows区别:exec()以模态显示就会导致聚焦中心不会发生变化,show()才能同时多个对话框窗口。
    • QMessagebox:直接使用information()函数
    • 资源文件:Resource目录,十分类似于Android。

 

  • 菜单栏:
    • 菜单-工具-状态栏:得QmainWindow才具有
    • action:拖动到菜单分组下的按钮控件,触发信号triggered()
      • 组成:图标-文字qt
      • 事件:qt

 

  • 图标:
    • RC_ICONS =APPIcon.cio

 

  • 控件
    • qtextEdit:典型的对象绑定数据、
      • 与前端的区别:dom树双绑到js对象是不同的。

 

  • qss:类似于css

 

 

三、事件和模块

  • 信号槽:
    • 本质:回调函数,但从性能角度来看,信号槽机制相对于回调函数可能略微慢一些,因为信号槽机制涉及到一些附加的元数据和运行时信息。但是,这种差异通常不太明显,并且由于信号槽机制带来的灵活性和可维护性,一般情况下使用信号槽机制比使用回调函数更好。
    • 实际开发:还是用回调函数on_click(),这样便于维护。
    • 与mfc的消息区别:Qt的信号槽机制更加灵活、易于使用,而MFC的消息机制则更加底层,且不支持多对多。
    • 使用:
      • 由父类对象进行connect(对象,信号,对象,槽)函数,一般写在窗口的构造函数调用initSIGNALSlots()函数中。
      • 例如:connect(ui->rbtn,SIGNAL(clicked()),this,SLOT(on_xx_clicked()))
      • 可视化:qtqt
      • 关闭连接(少用):disconnect()
    • 自定义:1对多的灵活性体现,跨对象进行通信
      • signals:是一个宏,声明自定义信号例如:love(),在c#中类似于事件,最好加emit标志
      • slots:是实现,当信号发出时自动调用的回调函数。
    • 带参数:得声明函数指针来指向特定的函数,void (boy::*xprt)(Qstring)
    • 使用lambda:
      • js中:(参数)=>{}
      • qt中:[外面的参数](信号传的参数类型)muteble->返回值{}(实际传参),[]中的参数主要是传入this指针
      • 常见应用:ret=[&ret]()mutable->int{}相当于js中修改全局数据

 

  • qtcore:
    • 底层:qt的预编译机制完成了

 

 

四、mfc附录

1.谈泛前端界面的渲染框架

 

  • 谈客户端
    • 核心:HMI(人机交互)
    • 页面渲染引擎:引擎是webgl、还是xml解释器、还是其他。
    • 数据绑定:mvvm自动绑定、命令式手动绑定mvc。
    • MFC(Microsoft Foundation Classes)
      • 渲染引擎:MFC使用GDI(Graphics Device Interface)作为其底层渲染引擎,用于2D图形绘制和界面渲染。
      • 维护者:MFC由Microsoft维护和支持。
    • Qt
      • 渲染引擎:Qt使用自己的绘图引擎,称为Qt Graphics View Framework,它是基于OpenGL的。
      • 维护者:Qt是由Qt公司(前身是Nokia,现在是Digia的一部分)维护的,同时也是开源社区参与的项目。
    • WinForms(Windows Forms)
      • 渲染引擎:WinForms使用GDI+(Graphics Device Interface Plus)作为其底层渲染引擎,用于2D图形绘制和界面渲染。
      • 维护者:WinForms由Microsoft维护和支持。
    • WPF(Windows Presentation Foundation)
      • 渲染引擎:WPF使用DirectX作为其底层渲染引擎,具有强大的3D图形和高级图形特性。
      • 维护者:WPF由Microsoft维护和支持。
    • Electron
      • 渲染引擎:Electron使用Chromium作为其底层渲染引擎,Chromium是开源的Web浏览器引擎,它支持HTML、CSS、JavaScript等Web技术。
      • 维护者:Electron是一个开源项目,由社区维护,但也得到了一些大公司的支持,如GitHub、Microsoft等。

 

  • 四大端:
    • browser:基于浏览器的w3c标准,main.js的入口、vue提供了组件化、mvvm数据流。原生函数式编程支持(事件)。
    • Windows:
      • mfc:基于win32,有InitInstance虚函数入口
      • qt:有main.app加载QApplication应用程序入口,
      • 运行时c#:也有入口,结构化ui和控件组件对象化,委托支持事件,
    • Android:基于java虚拟机的,manifest文件入口读取,四大组件。
    • 跨平台应用:基于混合编译的,基于特定语言,还有调用特定平台api接口。
    • 驱动程序和硬件支持
      • 一般来讲是Android rom开发或者上位机控制需要的驱动程序。
      • 消费电子:液晶显示屏

 

 

 

 

2.工程化构成

 

  • 概念:微软维护的c++类库
    • 初版本:1992年,提出的 GDI渲染技术。
    • MFC 4.0:1995年发布,引入了Doc/View架构,这是一种用于管理文档和视图的模型-视图-控制器(MVC)设计模式。
    • MFC 16.0 / Visual Studio 2019:继续对Windows 10进行改进,并提供了更多的现代化界面控件和工具。

 

  • 基本库:三大声明:afx.h和afxwin.h、afxext窗口类声明
    • 全局对象:cwinapp,提供了消息循环的应用程序类
    • cobject:提供机制的支持——序列化、动态创建
    • 为什么mfc:微软提供了一个c++的应用程序框架,用于快速开发桌面应用。

 

  • 三大机制:
    • 程序启动机制:总结就是围绕cwinapp的构造和生命周期InitInstance - 程序的初始化函数和Run - 消息循环
    • 窗口创建机制:与消息紧密相关,
    • 消息映射机制:
      • 类内必须添加声明宏:DECLARE_MESSAGE_MAP()
      • 类外必须添加实现宏:就是在cpp中,
        BEGIN_MESSAGE_MAP(
        theClass, //想要实现消息映射的类名称
        baseClass //theClass中的基类名称
        )
        END_MESSAGE_MAP()
        上述两个实现宏需要配对使用,也就是两个一起

 

  • 对话框应用程序:
    • h文件:
      • winapp:应用程序类负责了
      • xxdlg:窗体,类似于form
    • cpp文件:
      • CDialog:

 

  • 单文档视图架构程序:
    • CFrameWnd:窗口类
    • CDocument:文档类,负责管理数据
    • Cview:视图窗口类,负责显示数据

 

  • 多文档视图框架程序:
    • CMDIFrameWnd:多文档的窗口类
    • CMDIChildWnd:子窗口类
    • CView:显示数据

 

  • 基本类:
    • 类的阶层:qt
    • Cviews:视图
    • CMenu:菜单
    • Ccontrols:控件类
    • Cfile:系统文件io
    • CDialogEx:简单的对话框
    • 概括:qt

 

  • 关于程序启动流程:
    • 入口函数:与Win32窗口程序相同,都是从WinMain函数开始,但是MFC库已经实现了WinMain函数,所以在程序中不需要实现由于MFC库实现了WinMain,也就意味着MFC负责安排程序的流程。且C++ 规定,全局对象的构造将比程序进入点(在 DOS 环境为main,在 Windows 环境为WinMain)更早。所以theApp 的构造函数将更早于main。换句话说你所看到的执行结果中的那些构造函数输出动作全都是在main函数之前完成的。main 函数调用全局函数 AfxGetApp 以取得theApp 的对象指针。这完全是仿真 MFC 程序的手法。
    • 每一个窗口的cpp必执行InitInstance():生命周期内的数据处理呗。

 

 

 

 

 

3.实际开发

 

  • 消息映射开发:一对一映射
    • 声明:在类中声明 afx_msg类型
    • 实现:在类外使用宏实现
      • qt

 

  • 视图(view+control):
    • 作用:覆盖在主框架窗口客户区上的另一个窗口,这个窗口没有标题栏也没有边框,背景是白色的,将主框架窗口客户区遮挡起来,它可以提供一个用于专门显示数据的窗口
    • 重写:void OnDraw(CDC* pDC)

 

 

  • 文档(model):覆盖在主框架窗口客户区上的另一个窗口,这个窗口没有标题栏也没有边框,背景是白色的,将主框架窗口客户区遮挡起来,它可以提供一个用于专门显示数据的窗口。

 

  • 窗口切分:
    • 使用类:CSplitterWnd - 不规则框架窗口类,封装了不规则框架窗口的操作
    • 生命周期:
      • 1.写在虚函数OnCreateClient()中
      • 2.调用CSplitterWnd::CreateStatic()

 

 

  • 实际开发:以一个数据列表展示应用为例。
    • 1.如果你想创建一个带有菜单、窗口内分成多个区域(CView)并展示一些数据列表的应用,我建议你选择多文档视图架构。这个框架允许你创建多个文档和视图,每个视图可以在主窗口中的不同区域显示不同的内容,同时还可以轻松地管理菜单和工具栏。
    • 2.然后走流程cwinapp-cframewnd-cdocument+cview-控件

 

4.基本的Window原理和api

  • Window api
    • 总结:mfc就是对Window api的高级封装。
    • 库文件GDI32.LIB 和 USER32.LIB 和 KERNEL32.LIB。
      • USER32.LIB:掌控外围设备监控和巡侦。
      • GDI32.LIB:至于窗口的产生与显示,十分简单,有专门的API函数负责。
    • 声明头文件:Window.h涵盖了所有api,windef、winusr等等。
    • 编译:
      • qt
    • 资源:resource.h:这个头文件通常包含了资源标识符的定义,例如图标、位图、对话框模板等。这些资源可以在你的应用程序中使用,例如作为窗口图标或对话框的布局。
    • targetver.h:这个头文件通常包含了一些宏定义,用于指定你的应用程序要针对的最低Windows版本,以便在编译时进行条件编译
    • main函数入口:当Windows的「外壳」(shell,例如 Windows 3.1的程序管理员或Windows 95的文件总管)侦测到使用者意欲执行一个 Windows 程序,于是调用加载器把该程序加载,然后调用C startup code,后者再调用WinMain,开始执进程序。WinMain 的四个参数由作业系统传递进来。

 

  • 消息驱动机制:程序不断等待(利用一个 while 循环),等待任何可能的输入,然后做判断,然后再做适当的处理。
    • qt
    • 消息循环需要先创建一个MSG结构,其中包含以下的信息
      1、窗口句柄
      2、消息ID
      3、消息的两个参数(两个附带消息)
      4、消息产生的时间
      5、消息产生时的鼠标位置
    • GetMessage()获取信息到结构体lpMsg,并指定句柄hWnd的抓,
    • DispatchMessage(const MSG* lpMsg)函数会调用窗口处理函数,首先调用窗口处理的
    • SendMessage()阻塞式函数,PostMessage()非阻塞式。
    • 系统消息:就是相当于事件e传参。
    • 用户消息:
      • #define WM_MYMESSAGE WM_USER + 1001 //消息的宏名称,可以随意定义
      • SendMessage - 直接将消息发送给窗口的处理函数,并等候处理结果,是非消息队列的
      • 常见消息:WM_CREATE、WM_SIZE等
    • 总结流程:消息发送后,首先放入系统队列,再转发到各程序队列,然后通过消息循环,从本进程队列中获取
      • GetMessage - 从消息队列中获取消息
      • PostMessage - 将消息投递到消息队列
      • 常见队列消息:WM_PAINT、键盘、鼠标、定时器
      • qt

 

  • 消息的应用:
    • WM_CREATE:常用于初始化窗口的参数、资源等等,包括创建子窗口等
    • WM_SIZE:常用于窗口大小变化后,调整窗口内各个部分的布局
    • WM_SYSCOMMAND:关闭确认

 

  • GDI绘图:可以说相当于opengl的绘图,晦涩难懂。而且只有2d,
    • 性能:强于java的swing库但弱于directx(WPF)

 

  • 编译问题:
    • 静态库是将代码嵌入到使用程序中,当多个程序使用时,会有多份代码,所以代码的体积会增大
      动态库的代码只需要存在一份,其他程序通过函数地址可以直接使用,所以代码体积小
    • 静态库发生变化后,新的代码需要重新链接并嵌入到执行程序中
      动态库发生变化后,如果库中函数的定义(或地址)没有变化,其他使用DLL的程序不需要重新链接

 

6.console程序

  • visual c++:其实就是Windows c++
    • 我在BBS论坛上看到很多程序设计初学者,还没有学习C/C++,就想直接学习Visual C++。并不是他们好高骛远,而是他们以为Visual C++是一种特殊的C++语言。吃过苦头的过来人以为初学所说的 Visual C++ programming 是指MFC programming,所以大吃一惊(没有一点C++ 基础就要学习MFC programming,当然是大吃一惊)。

 

  • console程序和gui程序:
    • 共同:Console 程序的格式则和所有的Win32 程序一样,是所谓的PE(Portable Executable)格式
    • 区别:能调用的api有限,仅限于与绘窗口无关的。例如多线程支持的、cstring。

 

qt

发表评论 取消回复
表情 图片 链接 代码

分享