Notes
-
Qt Charts是二维图表模块,用于绘制柱状图、饼图、曲线图等常用二维图表。
-
Qt Data Visualization是三维数据图表模块,用于数据的三维显示,如散点的三维空间分布、三维曲面等。
-
pyuic5 是用于将Qt Designer(或Qt Creator内置的UI Designer)可视化设计的界面文件(.ui文件)编译转换为Python程序文件的工具软件。
-
pyrcc5 是用于将Qt Creator里设计的资源文件(.qrc文件)编译转换为Python程序文件的工具软件,资源文件一般存储了图标、图片等UI设计资源。
-
widget 是 label 的父容器。在创建时,将父容器作为参数传入。指定父容器,这样标签才能显示在窗体上。
widget = QtWidgets.QWidget()
label = QtWidgets.Qlabel(widget)
-
基于QMainWindow类的窗体,具有主窗口的特性,窗口上有主菜单栏、工具栏、状态栏等。
-
QWidget类是所有界面组件的基类,如QLabel、QPushButton等界面组件都是从QWidget类继承而来。
-
Qt Designer中的Property Editor界面,还显示了组件的继承关系。如QLabel的继承关系为:QObject→QWidget→QFrame→QLabel;QPushButton为QObject->QWidget->QAbstractButton。
-
objectName是组件的对象名称,界面上的每个组件都需要一个唯一的对象名称,以便被引用。
-
retranslateUi()函数集中设置了窗体上所有的字符串,利于实现软件的多语言界面。
-
函数setupUi()用于窗体的初始化,它创建了窗体上的所有组件并设置其属性。窗体是外部传入的,作为所有界面组件的父容器。
# setupUi()函数只创建窗体上的其他组件,而作为容器的窗体是靠外部传入的。
self.ui = Ui_MainWindow() # 创建UI对象
self.ui.setupUi(self) # 构造UI界面
# or
baseWidget = QtWidgets.Qwidget() # 创建窗体的基类QWidget的实例
ui = Ui_MainWindow()
ui.setupUi(baseWidget) # 以baseWidget作为传递参数,创建完整窗体
-
Ui_MainWindow的父类是object,不是Qt的窗体界面。
-
过程化的程序,难以实现业务逻辑功能的有效封装。
-
界面与业务逻辑分离的设计方法可以有多继承方法,另一种是单继承方法。
-
在多继承时,使用super()得到的是第一个基类。
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
如上程序中,super()执行之后得到的就是一个QMainWindow对象,可以作为参数传递给setupUi()函数。通过这样的多继承,Ui_MainWindow中定义的窗体上的所有界面组件对象就变成了新定义的类MainWindow的公共属性,可以直接访问这些界面组件。
-
使用
self.__ui = Ui_MainWindow()
设置私有属性,更符合面向对象封装隔离的设计思想。self.__ui.Lab
表示窗体上的对象标签,self.Lab
则表示MainWindow类里新定义的属性。两者不易混淆,有利于界面与业务逻辑的分离。 -
信号(Signal)/槽(Slot):GUI程序设计的主要内容就是对界面上各组件发射的特定信号进行响应,只需要知道什么情况下发射了哪些信号,然后合理地去响应和处理这些信号。
-
槽(Slot):槽实质上是一个函数,它可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射(emit)时,关联的槽函数会被自动执行。
-
用Qt Designer设计界面时,对于需要在窗体业务逻辑类里访问的界面组件,修改其objectName,以便在程序中进行区分。每个组件需要有一个唯一的objectName,自动生成的槽函数名称与objectName有关。
-
添加总布局后,当窗体大小改变时,各个组件都会自动改变大小。组件之间的层次关系可以在Object Inspector获取。
-
伙伴关系(Buddy )是为了在程序运行时,在窗体上用快捷键快速将输入焦点切换到某个组件上。
-
Qt的界面组件都是从QWidget继承而来的,都支持信号与槽的功能。
-
UI Designer工具栏里的“Edit Signals/Slots”使用可视化的方式实现信号与槽函数的关联。需要设置Sender、Signal、Receiver、Slot。
sender.signalName.connect(receiver.slotName)
- 在一个GroupBox中应用布局,体现在代码中就是:
groupBox = QGroupBox(Dialog)
# 以groupBox为父容器创建布局和组件
layout = QHBoxLayout(groupBox)
chkBox1 = QCheckBox(groupBox)
chkBox2 = QCheckBox(groupBox)
# 将部添加到layout中
layout.addWidget(chkBox1)
layout.addWidget(chkBox2)
-
toggled(bool)信号在复选框的状态变化时发射,复选框的勾选状态作为参数传递给函数。
-
下面的函数实现了信号与槽的关联。
QtCore.QMetaObject.connectSlotsByName(MainWindow)
# 槽函数的命名规则
on_objectName_signalName(signal parameters)
# 例子
on_btnClear_clicked()
-
@pyqtSlot()修饰符用于声明槽函数的参数类型。自定义的槽函数的函数名可以使用“do_”作为前缀,提高可读性。
-
使用PyQt5.QtCore.pyqtSignal()为一个类定义新的信号。类必须是QObject类的子类。信号具有connect()、disconnect()和emit(),分别对应关联槽函数、断开与槽函数的关联、发射信号。
-
尽量不要定义overload型信号。
-
资源文件(.qrc)最主要的功能是存储图标和图片文件,图标通常保存为十六进制编码数据。利用pyrcc5将 .qrc 文件转为对应的Python文件。
-
Qt C++类库和PyQt5之间存在差异的类和接口函数并不多。
第三章 GUI 应用程序设计
-
在对overload型信号编写槽函数时,如果不清楚哪个是默认的信号,最好直接使用@pyqtSlot()修饰符对参数类型进行声明。
-
QPushButton有一个checkable属性,如果设置为True, QPushButton按钮可以当作CheckBox或RadioButton使用。
-
属性 autoExclusive=True, checkable=True 可以将一组QPushButton设置为互斥的。
-
QSlider和QScrollBar最常用的一个信号是valueChanged(int),在拖动滑块改变当前值时就会发射这个信号。
-
QTimer主要的属性是interval,是定时中断的周期,单位是毫秒。QTimer主要的信号是timeout(),在定时中断时发射此信号。
timer.timeout.connect()
-
QMainWindow是主窗体类,可以作为一个应用程序的主窗体,具有主菜单栏、工具栏、状态栏等主窗体常见的界面元素。
-
QAction是直接从QObject继承而来的一个类,不是一个可视组件。QAction就是一个实现某些功能的“动作”,可以为其编写槽函数,使用一个QAction对象可以创建菜单项、工具栏按钮,点击菜单项或工具栏按钮就执行了关联的Action的槽函数。
-
互斥的 Action 通过QActionGroup分组对象实现:
format_group = QActionGroup(self)
format_group.setExclusive(True)
format_group.addAction(self.alignl_action) #左对齐
format_group.addAction(self.alignc_action) #居中
format_group.addAction(self.alignr_action) #右对齐
format_group.addAction(self.alignj_action) #两端
-
以Word程序为例,窗体最上方是菜单栏(Menu Bar),菜单栏下方是工具栏(Tool Bar),最下方是状态栏(Status Bar)。
-
状态栏 QStatusbar,addWidget()函数按从左到右顺序将一个组件添加到状态栏,addPermanentWidget()添加的组件则位于状态栏的最右边。
-
工具栏 QToolbar,addWidget():添加一个界面组件到工具栏;addAction():添加一个QAction对象并创建工具栏按钮; addSeparator():添加一个分隔条。
-
QAction常用的信号是triggered()和triggered(bool),它们是overload型信号。triggered(bool)是带有复选状态参数的信号。
-
QToolButton有一个setDefaultAction()函数,使其与一个Action关联,自动获取Action的文字、图标、ToolTip等设置作为按钮的相应属性。单击一个QToolButton按钮就会执行Action的槽函数,与工具栏上的按钮一样。
-
下拉菜单的实现方式:创建一个QMenu对象、选择列表项的Action添加作为菜单项;setMenu(QMenu_obj)为一个ToolButton按钮指定下拉菜单、QToolButton的setPopupMode()函数为一个ToolButton按钮的下拉式菜单设置不同的弹出方式;
-
每个从QWidget继承的类都有信号customContextMenuRequested(),这个信号在鼠标右键单击时发射,为此信号编写槽函数,可以创建和运行右键快捷菜单。
-
首先创建一个QMenu类型的对象menuList,然后利用QMenu的addAction()方法添加已经设计的Action作为菜单项。创建完菜单后,使用QMenu的exec()函数显示快捷菜单。
menuList = QMenu(self)
menuList.addAction(...)
# 类函数QCursor.pos()获得鼠标光标当前位置
menuList.exec(QCursor.pos())
-
QTreeWidget是创建和管理目录树结构的类。
-
ScrollArea上面放置一个QLabel组件,QLabel的pixmap属性可以显示图片。通过QPixmap对象的操作可进行缩放显示。当图片较小时,显示的图片可以自动居于scrollArea的中间,当显示的图片大小超过scrollArea可显示区域的范围时,scrollArea会自动显示水平或垂直方向的滚动条,用于显示更大范围的区域。
-
QPixmap存储图片数据,并且可以缩放图片,缩放只需调用相应函数,返回缩放后的图片副本。QPixmap.load(fileName)函数直接载入一个图片文件的内容。scaledToHeight(height, mode = Qt.FastTransformation):返回一个缩放后的图片的副本,图片缩放到一个高度height。
-
scaledToWidth(width, mode = Qt.FastTransformation):返回一个缩放后的图片的副本,图片缩放到一个宽度width。
-
scaled(width, height, ratio = Qt.IgnoreAspectRatio , mode = Qt.FastTransformation):返回一个缩放后的图片的副本,图片缩放到宽度width和高度height。
-
QLabel.setPixmap(pixmap)函数显示一个QPixmap类对象pixmap存储的图片。
-
QTableWidget是PyQt5中的表格组件类,每一个单元格是一个QTableWidgetItem对象。
-
QGroupBox组件是常用的容器类组件,可以在一个GroupBox里放置其他界面组件且进行布局。QGroupBox有两个属性:checkable和checked。当checked为False时,GroupBox组件内部的所有组件都被禁用。
-
layoutLeftMargin、layoutTopMargin、layoutRightMargin和layoutBottomMargin这4个属性用于设置布局组件与父容器的4个边距,默认为9。
-
水平布局类QHBoxLayout和垂直布局类QVBoxLayout都有一个属性spacing,用于设置布局内组件之间的间隔,默认为6。
-
水平布局QHBoxLayout和垂直布局QVBoxLayout都有一个layoutStretch属性,用于设置各组件宽度分配比例。
# groupBox内有3的组件,如下设置只有一个组件可随窗口伸缩
self.horizontalLayout.setStretch(0, 0, 1)
- Lay Out Horizontally in Splitter左右分割布局。
第4章 Model/View结构
-
Model/View(模型/视图)结构:源数据由模型(Model)读取,然后在视图(View)组件上显示和编辑,在界面上编辑修改的数据又通过模型保存到源数据。将数据模型和用户界面分离开来。
-
将界面组件与原始数据分离,又通过数据模型将界面和原始数据关联起来,从而实现界面与原始数据的交互操作。
- Data(源数据)是原始数据。
- View(视图或视图组件)是界面组件,视图从数据模型获得数据然后显示在界面上。
- Model(模型或数据模型)与源数据通信,并为视图组件提供数据接口。
- Delegate(代理或委托)在视图与模型之间交互操作时提供临时编辑组件的功能。
-
Delegate代理负责从数据模型获取相应的数据,然后显示在编辑器里,修改数据后又将数据保存到数据模型中。
-
通过数据模型存取的每个数据都有一个模型索引,视图组件和代理都通过模型索引来获取数据。保证数据的表示与数据存取方式的分离。
-
要获得一个模型索引,必须提供3个参数:行号、列号、父项的模型索引。
-
在构造数据项的模型索引时,必须指定正确的行号、列号和父节点。
-
QFileSystemModel为本机的文件系统提供一个数据模型,可用于访问本机的文件系统。
-
QStringListModel是用于处理字符串列表的数据模型,可以作为QListView的数据模型,在界面上显示和编辑字符串列表。QListView的setModel()函数用于设置一个数据模型。
-
数据模型与视图组件之间信号与槽作用的结果,当数据模型的内容发生改变时,通知视图组件更新显示。数据模型的数据与界面上视图组件显示的内容是同步的。
-
QStandardItemModel通常与QTableView组成Model/View结构,实现通用的二维数据的管理。
-
为TableView组件的某列或某个单元格设置自定义代理组件,根据数据的类型限定使用不同的编辑组件。
第5章 事件处理
-
基于窗体(Widget)的应用程序都是由事件(event)驱动的,鼠标单击、按下某个按键、重绘某个组件、最小化窗口都会产生相应的事件,应用程序对这些事件作出相应的响应处理以实现程序的功能。
-
app.exec_()开启了应用程序的事件处理循环。
-
QEvent还有很多子类表示具体的事件,如QKeyEvent表示按键事件,QMouseEvent表示鼠标事件,QPaintEvent表示窗体绘制事件。
-
当一个事件发生时,PyQt5会根据事件的具体类型用QEvent相应的子类创建一个事件实例对象,然后传递给产生事件的对象的event()函数进行处理。
-
QWidget定义了很多的默认事件处理函数,都会传递一个event参数,但是event的类型由具体事件类型决定。
-
用户在继承于QWidget或其子类的自定义类中可以重新实现这些默认的事件处理函数,从而实现一些需要的功能。如重新实现mouseReleaseEvent()函数对鼠标单击事件进行处理,为QWidget添加clicked()信号。
-
事件与信号是有区别的,但是也有关联。Qt为某个界面组件定义的信号通常是对某个事件的封装,例如QPushButton有clicked()信号和clicked(bool)信号,就可以看作是对mouseReleaseEvent()事件的不同封装。
-
QLabel没有doubleClicked()信号,可以通过事件处理和自定义信号创建一个具有doubleClicked()信号的新的标签类。
-
事件与信号的关系:信号可以看作是对事件的一种封装。
-
QEvent.Paint事件类型的默认处理函数是paintEvent(),就是用于绘制窗体背景图片的函数。
-
事件过滤器(event filter):将一个对象的事件委托给另一个对象来监测并处理。
-
如下程序,self是两个QLabel组件所在的窗体,这样,界面组件LabHover和LabDBClick就将窗体注册为其事件监测者,在LabHover或LabDBClick组件上触发的事件会发送给窗体进行处理。
self.ui.labHover.installEventFilter(self)
self.ui.labelDBClick.installEventFilter(self)
# 窗体通过重新实现eventFilter()函数对被监测的对象及其事件进行处理
def eventFilter(self, watched, event):
# 通过watched判断哪个是被监测对象
# 根据event.type()判断事件类型并作出相应处理
# 执行父类的eventFilter()函数
return super().event.Filter(watched, event)
-
QApplication类型的应用程序执行exec_()函数后就开始了事件的循环处理。事件队列未能得到及时处理,用户会感觉到响应迟滞。有两种解决方案:
- 采用多线程方法。
- 另外一种简单的处理方法是使用QCoreApplication的类函数processEvents()。
-
在一个耗时较长的计算处理过程中不允许用户用鼠标或键盘操作。
from PyQt5.QtWidgets import qApp
qApp.processEvents(QEventLoop.ExcludeUserInputEvents)
-
拖放操作涉及:mousePressEvent()、mouseMoveEvent()、dragEnterEvent()、dropEvent() 事件函数。
-
QLabel组件的scaledContents属性设置为True,让图片适应QLabel组件的大小。
-
setAcceptDrops()是QWidget类定义的函数,用于设置一个窗体组件是否接受放置操作。将界面组件设置为不接受放置,而窗体接受放置,事件也是传播到组件所在的父容器,也就是由窗口处理。
-
MIME (Multipurpose Internet Mail Extensions)是多功能因特网邮件扩展。QMimeData是对MIME数据的封装,在拖放操作和剪切板操作中都用QMimeData类描述传输的数据。
第6章 对话框与多窗口设计
-
若要打开一个文件,调用类函数QFileDialog.getOpenFileName()。
-
QColorDialog是选择颜色对话框,选择颜色使用类函数QColorDialog.getColor()。
-
QFontDialog是选择字体对话框,选择字体使用类函数QFontDialog.getFont()。
-
QProgressDialog是用于显示进度的对话框,可以在大的循环操作中显示操作进度。
-
QInputDialog有单行字符串输入、整数输入、浮点数输入、列表框选择输入和多行文本输入等多种输入方式。
-
消息对话框QMessageBox用于显示提示、警告、错误等信息,或进行确认选择。
-
常用的窗体基类是QWidget、QDialog和QMainWindow,在创建GUI应用程序时选择窗体基类就是从这3个类中选择。
-
QWidget:在没有指定父容器时可作为独立的窗口,指定父容器后可以作为父容器的内部组件。QWidget是所有界面组件的基类。
-
MDI(Multiple Document Interface)就是多文档界面,它是一种应用程序窗口管理方法,一般是在一个应用程序里打开多个同类型的窗口。
第8章 绘图
-
PyQt5提供了两种绘图方法。一种是使用QPainter类在QWidget类提供的画布上画图,可以绘制点、线、圆等各种基本形状,从而组成自己需要的图形。
-
所有界面组件都是QWidget的子类,界面上的按钮、编辑框等各种组件的界面效果都是使用QPainter绘制出来的。
-
PyQt5另外提供一种基于Graphics View架构的绘图方法,这种方法使用QGraphicsView、QGraphicsScene和各种QGraphicsItem图形项绘图,在一个场景中可以绘制大量图件,且每个图件是可选择、可交互的,如同矢量图编辑软件那样可以操作每个图件。Graphics View架构为用户绘制复杂的组件化图形提供了便利。
-
QPainter是用来进行绘图操作的类,一般的绘图设备包括QWidget、QPixmap、QImage等,这些绘图设备为QPainter提供了一个“画布”。
-
使用QPainter对象在一个QWidget窗体的paintEvent()事件函数里直接绘图。
-
可以从QWidget继承一个类,创建自定义界面组件。
-
在UI可视化设计时,可以使用提升法(promotion)将一个组件类提升为其某个子类。
-
PyQt5为绘制复杂的可交互的图形提供了Graphics View绘图架构,它是一种基于图形项(GraphicsItem)的模型/视图结构。
-
Graphics View架构主要由3部分组成,即场景、视图和图形项。
-
视图(View)是QGraphicsView提供绘图的视图组件,用于显示场景中的内容。可以为一个场景设置多个视图,用于对同一个数据集提供不同的视口。
-
QGraphicsItem可以被选择、拖放、组合,若编写信号的槽函数代码或事件函数响应代码,还可以实现各种编辑和操作功能。
-
QGraphicsView没有与mouseMoveEvent()相关的信号。从QGraphicsView继承定义一个类QmyGraphicsView,实现鼠标移动事件函数mouseMoveEvent()和鼠标按键事件函数mousePressEvent()的处理,并把事件转换为自定义信号,这样就可以在主程序里设计槽函数响应这些鼠标事件。
第9章 文件
-
os.gtcwd()函数获取当前路径。内建函数open()打开文本文件并读取文件内容。
-
PyQt5中用于文件读写操作的类是QFile,它提供了文件读写的接口函数,可以直接对文件进行读写。
-
Python自带的os和os.path模块中提供了大量的目录和文件操作相关的函数,如获取当前目录、新建目录、复制文件、分离文件的路径和基本文件名、判断文件是否存在等。
-
QFile类是直接与I/O设备打交道进行文件读写操作的类,使用QFile可以直接打开或保存文本文件。
-
除文本文件之外,其他的需要按照一定的格式定义读写的文件都可称为二进制文件。每种格式的二进制文件都有自己的格式定义,写入数据时按照一定的顺序,读出时也按照相应的顺序。
-
目录和文件操作包括获取当前目录、新建或删除目录、获取文件的基本文件名和后缀、复制或删除文件等操作。