type
Page
slug
Qt
status
Published
date
summary
tags
知识
category
技术分享
icon
password

写UI的两种方法

Qt Designer

  • 可视化编辑.ui文件
  • 本质上是XML
  • 便于分开前后端的编写
    • ui与业务逻辑解耦
  • 编译时需要先用uic工具转换为c++文件,多一个步骤
  • 静态页面,不适用于动态操作

C++动态创建

  • 手动实例化对象,设置布局
  • 灵活性强
  • 代码量大
  • 所敲非所得,不能随时监控布局,需要脑补

折中方案

  • 用Designer写静态框架,即程序运行中基本不变的内容
  • 动态处理的内容用C++处理

窗口类型

模态窗口

  • 有上下文关联的
  • 有层级限制的,操作一个窗口前必须完成上一个窗口的交互

非模态窗口

  • 相互独立

设计范式

万物皆对象

元对象系统

  • Qt的面向对象与一般的C++ OOP不同,它定义了一套元对象系统 (Meta-Object System)。
  • 所有对象均继承QObject 类。
  • 通过moc(元对象编译器)这个工具,在编译前给代码里塞进去了很多本来没有的功能,比如:
    • 信号与槽(Signals & Slots)
    • 运行时类型信息:比C++自带的RTTI(运行时类型识别,Runtime Type Information)信息更丰富。
      • RTTI
        • typeid操作符typeid主要是让你在运行时知道一个对象的“类型名”,比如 std::cout << typeid(*myObject).name();。它只能告诉你:“这个是个QPushButton“。
        • dynamic_cast:在做多态转换时用。比如有个QWidget指针,想安全地把它向下转型QPushButton指针,如果转型不成功,它就返回nullptr
        • 只能获取表面信息,无法获取内部方法和参数。
        元对象系统
        • 可以获取类名
        • 可以获取所有父类,查询继承链
        • qobject_cast<Type*>():Qt版本的dynamic_cast,效率更高,对QObject体系更安全
        • 动态方法调用:QMetaObject::invokeMethod()
          • 可以让你在运行时根据函数名,去调用任何信号、槽、或者Qt Property系统的读写方法
        • 更强大的属性系统
          • 可以通过一个字符串来获取或设置一个对象的属性值。
        • 支持翻译
          • QObject::tr() 方法能根据当前的语言环境,在运行时查找正确的翻译字符串
        • 与Qt Designer这样的工具联动
          • 加载带Q_OBJECT宏的类
          • 把它的属性显示在属性编辑器里
          • 把它的信号和槽列出来放在信号槽编辑器里让你连接
 

信号和槽

核心就是“事件驱动”和“组件解耦”
  • 信号:触发的事件
  • 槽:调用的方法
  • 组件只管喊:一个按钮,被点击了,它只管用“喊话筒”(Signal)向全世界广播:“我被点了!”。根本不关心谁在听,谁会理它。
  • 听众自己连:你写的其他代码,如果对这个“被点了”事件感兴趣,就自己长个“顺风耳”(Slot),然后用connect函数把这个耳朵和那个喊话筒连起来。
通过connect函数链接

特点

  • 解耦
  • 类型安全
    • 编译阶段就能帮你检查信号的参数类型和槽的参数类型是否匹配
  • 调用效率高,在底层直接调用函数指针

“模型-视图”架构(Model/View)

当要处理大量数据展示的时候,比如列表、表格、树状图,Qt强烈推荐你用这个范式。
  • 模型(Model):就是纯粹的数据。它就是个数据仓库,负责存储、管理数据,提供访问接口。
  • 视图(View):负责怎么把数据显示出来,画给用户看。
    • 如表格的视图QTableView,列表的视图QListView,树状的视图QTreeView,甚至你自己画的图QGraphicsView
    • 根本不关心数据从哪儿来,数据怎么存的,它只知道按照自己的风格,问模型要数据来画。
    • 用户在视图上点点画画的事件(比如选中一行,拖动列),它也只管发出信号,让别人去处理。
  • 代理(Delegate):负责怎么把模型里的“原始数据”转换成视图能够理解并显示出来的数据。同时,它还负责视图上的用户交互如何改动模型里的数据。(兼容Controller的工作)
    • 比如一个数字5,代理可以把它转成前面带个“¥”符号的字符串“¥5.00”。
    • 比如用户直接双击表格改了一个单元格的文本,代理负责把这个文本塞回到模型里。

QML+C++:MVVM架构

  • View:QML
    • 声明式UI:QML 是个声明式语言,描述你想要什么而不是一步步将它画出来。只关心结果不关心过程。
    • 只管UI实现。
    • 支持数据绑定。
    • 动画效果和图形能力强。
    • 内嵌JavaScript引擎,可以直接运行JS语句
  • ViewModel:C++ QObject
    • Q_PROPERTY:这个就是给 QML 准备的“数据绑定插头”,是 ViewModel 向 View 提供状态数据的基础
      • 当你用Q_PROPERTY在 C++ 类里声明一个属性时,QML 就能直接访问(读写)这个属性,还能通过 NOTIFY 信号监听这个属性的变化。
      • 这就是 QML 里面text: myViewModel.userName能自动更新的根本原因。
    • Q_INVOKABLE方法:这个就是行为指令的传送门,是 ViewModel 向 View 提供行为(命令)的基础。
      • 任何用 Q_INVOKABLE 标记的 C++ 函数,都能被 QML 像调用脚本函数一样直接调用。
  • 高性能、高颜值、易维护,跨平台。

布局管理器

自动排布各种控件。
  • QHBoxLayout (水平布局)
  • QVBoxLayout (垂直布局)
  • QGridLayout (网格布局)
  • QFormLayout (表单布局)
  • QStackedLayout (堆叠布局)
 
Loading...