笔者:xiaobai_Ry(CSDN)
笔记时间:2022年某个未知时间点😂
原创文章,未经同意请勿转载
之前说过要share QT的八股文(原创),maybe有小伙伴之前看过我的这篇笔记博客?
先来看看之前的笔记概况吧,最近打算清理一下之前的知识存货啦啦啦(PS:给自己的年度目标还没有达标,所以最近疯狂码字系列了😂)
终于我来更新了!!!这里我同样不喜欢在一篇博文中放太长的内容所以这里我同样分成章节来share啦。今天(2023/12/21)先来更新第一篇章吧。
【第一篇章主要内容】
作为第一篇章主要是基础定义及QT中重要的事件机制啦
原创文章,未经同意请勿转载
开发时,笔者也会发现开发环境,实验环境及生产环境下程序的运行效率真的还有比较多的差别,尤其是在打包没有设置好的情况下。而且随着系统的规模及复杂程度这种现象也越明显。
主要有三大核心机制(围绕信号与槽的展开):元对象系统,属性系统,信号与槽(最核心)
元对象系统(提供信号与槽机制,属性系统…)
Qt的元对象系统(meta-object)提供了用于内部对象通讯的信号与槽(signals & slots)机制
,运行时类型信息,以及动态属性系统(dynamic property system)。
元对象编译器MOC
属性系统
属性系统特性可以用于任何Qt支持的编译器与架构。它基于元对象系统(Meta-Object System),这套系统同时也提供信号与槽机制用于对象间通讯
。
信号与槽
信号与槽用于对象之间的通讯。信号与槽机制是Qt的核心特性。
在Qt中,使用了信号与槽机制代替了回调机制。信号将会在特定的事件出现时被发出。Qt的控件预定义了很多信号,当然我们也可以继承这些控件以定义自己的子类,然后添加自己的信号。槽是在响应特定信号时会被调用的方法。Qt的控件存在很多预定义的槽,但通常的做法是继承控件以生成自己的子类,然后添加自己的槽,这样我们就可以自行处理感兴趣的信号。
其他核心机制:GUI界面管理机制(窗口管理器和布局管理器),事件处理机制,数据库支持….
Qt中的主窗口(MainWindow)类是一种特殊的窗口类,它通常用于构建程序的主窗口。主窗口类继承自QWidget类
,因此可以使用QWidget类中的函数和成员变量,同时还具有一些特殊的函数和成员变量。其中:
常用的成员变量包括:
QtWidgets.QMenuBar()
QtWidgets.QSidebar
QtWidgets.QBottomBar
QtWidgets.QToolBar(window)
QVector:基于数组实现的动态数组容器类
,支持快速的随机访问和尾部插入操作。适合于需要频繁随机访问的情况。QList:基于双向链表实现的容器类
,支持高效的插入和删除操作。适合于需要频繁插入和删除元素的情况。QLinkedList:基于双向链表实现的容器类
,支持高效的插入和删除操作,但不支持随机访问。适合于需要频繁插入和删除元素,但不需要随机访问的情况。QSet:基于哈希表实现的集合容器类
,支持高效的查找和插入操作,不允许重复元素。适合于需要快速查找元素,且不需要重复元素的情况。QMap:基于红黑树实现的映射容器类
,支持高效的查找和插入操作,键值对按照键的大小有序排列。适合于需要按键进行排序和快速查找的情况。QHash:基于哈希表实现的映射容器类
,支持高效的查找和插入操作,键值对无序存储。适合于需要快速查找键值对,且不需要按键排序的情况。QStringList:基于QString实现的字符串列表容器类
,支持高效的字符串操作,如拼接、查找、替换等。适合于处理字符串列表的情况。QByteArray:基于char数组实现的字节数组容器类
,支持高效的二进制数据读写操作。适合于处理二进制数据的情况。在 PyQt5 中,有许多常用的容器类可以用来组织和管理 GUI 应用程序中的数据和情感。以下是一些常用的 PyQt5 容器类,并说明它们的特点及使用场景:
QtWidgets.QStackedWidget
: QStackedWidget
是一个弹出式窗口容器,用于在一组窗口之间切换。它支持标签、标题、最小化和最大化按钮,以及内容滚动。它的特点是可以弹出新窗口,并在窗口之间切换,常用于布局多个子窗口,以及在主窗口中显示多个子窗口。QtWidgets.QVBoxLayout
: QVBoxLayout
是垂直布局容器,用于在子组件之间布局。它支持垂直布局、水平和垂直布局,特点是可以嵌套子组件,并控制子组件的大小和位置。它常用于布局文本框、按钮、标签等组件,以及在主窗口中添加子窗口。QtWidgets.QHBoxLayout
: QHBoxLayout
是水平布局容器,用于在子组件之间布局。它支持水平布局、垂直布局和水平垂直布局,特点是可以嵌套子组件,并控制子组件的大小和位置。它常用于布局下拉框、列表框等组件,以及在主窗口中添加子窗口。QtWidgets.QFormLayout
: QFormLayout
是表单布局容器,用于布局表单组件,例如文本框、下拉框和按钮。它支持垂直布局、水平布局和表单布局,特点是可以添加表单控件,并控制它们的大小和位置。它常用于布局表单数据,例如用户注册或登录窗口。QtWidgets.QGridLayout
: QGridLayout
是网格布局容器,用于在水平或垂直方向上布局多个组件。它支持组件对齐、组件大小调整和组件重叠,特点是可以控制组件的位置和大小,适用于布局多个组件的大型 GUI 应用程序。QtWidgets.QGroupBox
: QGroupBox
是一个群组框容器,用于创建群组框,可以在其中添加子窗口和组件。它的特点是可以添加子窗口,并控制子窗口的大小和位置。它常用于布局多个组件,例如菜单栏或状态栏。QtWidgets.QFrame
: QFrame
是边界框容器,用于创建边界框,可以包含文本、按钮和其他组件。它的特点是可以添加其他容器组件,并控制组件的大小和位置。它常用于布局文本、按钮和其他小型组件,例如按钮组或标签组。QtWidgets.Q Banner
: QBanner
是一个广告条容器,用于在应用程序中显示广告或信息。它的特点是可以显示文本、图像或其他媒体,并支持动画效果。它常用于在应用程序中添加广告或重要信息。QtWidgets.QListWidget
: QListWidget
是一个列表容器,用于显示列表中的项。它支持选中、拖动和删除操作,特点是可以添加、删除和修改项。它常用于显示数据列表,例如文件列表或用户列表。QtWidgets.QTreeView
: QTreeView
是树形结构容器,用于显示树形结构中的项。它支持拖动和删除操作,特点是可以添加、删除和修改项。它常用于显示数据树形结构,例如文件系统或数据库。综上所述,这些容器类都有各自特点和使用场景,可以根据实际需要选择合适的容器类来组织和管理 GUI 应用程序中的数据和情感。
定义
Qt 事件是一个 QEvent 对象,用于描述程序内部或外部发生的动作,任意的 QObject 对象都具有事件处理的能力
意义
来源
Qt中事件的来源有两个:程序外部和内部。
接收者
事件由QObject类来接收,是Qt对象模型的核心,所有需要处理的事件类都必须继承QObject。
GUI 应用程序的事件处理方式
事件的传递过程
首先,我们需要了解一下相关的定义。
signal
由具体对象发出,然后会马上交给由connect
函数连接的 slot
进行处理。信号与事件的区别主要可以概述为:
举个例子,当使用 QPushButton 时,我们对于它的 clicked()信号往往更为关注,而很少关心促成发射该信号的底层的鼠标或者键盘事件。但是,如果要实现一个类似于 QPushButton 的类,我们就需要编写一定的处理鼠标和键盘事件的代码,而且在必要的时候,仍然需要发射和接收 clicked()信号。
💡 当发生事件,比如点击鼠标或键盘,就会产生一个QEvent对象,这里注意QT中所有的事件类都继承于QEvent,这个QEvent对象会传给当前组件的event函数,如果没有事件过滤器,则该函数会按照事件对象的类型发送到特定的xxxEvent事件处理函数中进行处理。
定义
除了使用事件分发器来过滤 Qt 窗口中产生的事件,还可以通过事件过滤器过滤相关的事件。当 Qt 的事件通过应用程序对象发送给相关窗口之后,窗口接收到数据之前这个期间可对事件进行过滤,过滤掉的事件就不能被继续处理了。事件过滤器可以对其它组件接收到的事件进行监控。QObject 有一个 eventFilter () 函数,用于建立事件过滤器。
作用
实际上,事件过滤器并不只是过滤事件,也可以对事件进行捕捉、并做出相应的处理操作。对象A只有安装了对象B的事件过滤器,才会在对象B的eventFilter方法中进行监控对象A的所有事件。
过滤传递中的事件,主要分为两步:
installEventFilter()
函数安装事件过滤器💡 注意:事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。
事件循环:事件是一个类对象,具有特定的类型,多数情况下是被分发到一个队列中(事件队列),当队列中有事件时就不停地将队列中的事件发送给QObject对象,当队列为空时,就阻塞地等待事件。
事件循环首先是一个无限“循环”,程序在exec()里面无限循环,能让跟在exec()后面的代码得不到运行机会,直至程序从exec()跳出。从exec()跳出时,事件循环即被终止。QEventLoop::quit()能够终止事件循环。
首先QCoreApplication::exec()开启了事件循环,一直到QCoreApplication::exit()被调用才终止,所以说事件循环是伴随着Qt程序的整个运行周期,事件被分发到事件队列中,当队列中有事件时会不停的将事件发送给QObject对象,队列为空时就阻塞
Qt将系统产生的信号(软件中断)转换成Qt事件,并且将事件封装成类,所有的事件类都是由QEvent派生的,事件的产生和处理就是Qt程序的主轴,且伴随整个程序的运行周期
。因此说Qt是事件驱动的。
Key Press Event, Key Release Event
Mouse Motion Event, Mouse Click Event,Mouse Right Click Event,Mouse Position Event
Dragging Event
Focus Change Event
根据对Qt事件机制的分析, 我们可以得到5种级别的事件过滤,处理办法. 以功能从弱到强, 排列如下:
1)重写特定事件处理函数.
最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent() 这样的特定事件处理函数.
2)重写event()函数.
通过重载event()函数,我们可以在事件被特定的事件处理函数处理之前(象keyPressEvent())处理它. 比如, 当我们想改变tab键的默认动作时,一般要重载这个函数. 在处理一些不常见的事件(比如:LayoutDirectionChange)时,evnet()也很有用,因为这些函数没有相应的特定事件处理函数. 当我们重载event()函数时, 需要调用父类的event()函数来处理我们不需要处理或是不清楚如何处理的事件.
3) 在Qt对象上安装事件过滤器
安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)
首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数. 这样所有发往B的事件都将先由A的eventFilter()处理.
然后, A要重载QObject::eventFilter()函数, 在eventFilter() 中书写对事件进行处理的代码.
4) 给QAppliction对象安装事件过滤器.
一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个 eventFilter(). 在debug的时候,这个办法就非常有用, 也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. ( 在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃)
5) 继承QApplication类,并重写notify()函数.
Qt 是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法. 通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类. 而且可以给QApplication对象安装任意个数的事件。
QT中的模型/视图(Model/View)架构是一种用于管理和显示数据的模型。在很多书中,QT的视图模型经常被叫做MVC,其实QT中的MVC并不叫MVC,而是叫“MVD”,Qt中没有Controller的说法,而是使用了另外一种抽象: Delegate (委托) ,其行为和传统的MVC是相同的。
模型视图委托(MVD)是PyQt中特有的设计模式,类似MVC设计模式,将MVC设计模式中的Controller当做MVD中的Delegate,两者的概念基本相同。不同的是委托不是独立存在,而是包含在视图里面。
模型视图委托设计模式中,模型负责存储和管理数据;视图负责显示数据,其中界面的框架和基础信息是视图负责,具体数据的显示是委托负责;委托不仅仅负责数据的显示,还有一个重要的功能是负责数据的编辑,如在视图中双击就可以编辑数据。
其中:
模型
数据的存储一般是列表,表格和树,不同的存储方式有不同的操作和管理方法,为了适应这种差异性,PyQt中提供了一种统一的操作方法,如下图所示:
委托
委托被封装在视图里面,主要是负责数据的显示和编辑功能。
下篇笔记链接:【待更新】
下篇笔记主要内容:【待更新】
原创文章,未经同意请勿转载
作者:xiaobai_Ry
码字不易,可能当中存在某些字体错误(笔者我没有发现),如果有错误,欢迎大家指正。🤗