从开发流程看 PyQt5 入门

从开发流程看 PyQt5 入门

  近期笔者开发了几个基于PyQt5的小项目,也算是对PyQt5及其开发流程有了一定的了解,故想以备忘的目的记录下来,供各位读者和自己参考。

  本文将以PyQt5的开发流程为线索,介绍基本PyQt5图形界面应用的基本功能和原理,并拓展相关知识,覆盖PyQt5入门所需要的各方面。其余进阶内容,读者可以借助完整的文档支持和丰富的参考资料自行探索。(有需要再查阅文档即可)

基本介绍

PyQt5,是跨平台图形用户界面框架Qt的Python支持包。其提供了丰富的图形控件库,与优秀的跨平台性能(包括Windows, macOS, Linux, iOS, Android)。Qt官方提供的Python支持为PySide库,但语法与PyQt基本没有差异,本文就以PyQt5为例展开。

另外,Qt提供了跨语言的通用UI开发设计器Qt Designer,可以以图形化的方式构建UI界面,并可提供预览。设计完成的文件通过PyQt5自带的工具PyUIC转换为PyQt5代码,可被Python主逻辑直接引用。转换后的代码样例如下:

PyUIC

关于如何安装环境,以及转换设计文件,本文不再赘述,请读者另行搜索教程。

窗体设计与结构

前端的第一部分是设计UI粗稿,需要使用Qt Designer等窗体设计器。

Qt的基类

所有的Qt对象都是基于Object基类拓展(事实上,所有的Python类都是以object类作为缺省基类)。

打开Qt Designer,新建项目,可以看到几种模板,分别代表了三类Qt基类:

  • QMainWindow:带有MenuBar, StatusBar, and centralwidget的窗体。
    • 自带菜单栏(一般位于应用最上部标题栏下,第一个总是File : )),状态栏(最下面一条)
    • 以上三个控件必须以window.setXXX方式指定,否则相当于没有初始化,不会在窗体上显示
    • 一般使用该类创建功能较为完整的窗体,可以省去一些初始化菜单栏等控件的时间
  • Widget:一般控件类,为不带任何初始控件的空白窗体。
    • 可以直接进行编辑,没有初始模板,但编码上较方便
    • 一般用于简单窗体
  • QDialog:顾名思义,对话框类,自定义对话框内容
    • 一般用于特殊的自定义对话框
    • Qt提供了多种样式的对话框(FileDialog等),可以直接调用,一般不需要自定义对话框

Qt的对象结构

Qt以树形结构组织对象。每一个初始对象(包括窗体)创建时,都需要一个Parent参数(可为空),用于指定其父对象。一般,父子关系用于表示容器控件的包含关系。例如,在QMainWindow类窗体中,所有的窗体控件都包含在CenterWidget控件中,也就以其为父对象。

一个MenuBar的属性结构类似下图例:

Class Structure

控件与布局

在Qt Designer中,所有控件被分类与控件菜单中,拖动到窗体合适位置就会创建,也可以修改大小与属性。控件的主要属性如下:

  • objectName:作为QObject的属性,为任何一个Qt对象的基本属性,缺省以控件类型与编号命名。在设计窗体时,建议同时将控件按照类型+功能的格式命名,避免产生名称混乱。
  • enabled: 控件是否可用,disable的控件为灰色,无法响应用户操作(但可以由代码控制)
  • size: 控件的尺寸,即长x宽
  • Text: (部分控件)控件上展示的文字
  • StyleSheet: 控件应用的样式表(在QSS中会使用)

其余部分属性为控件特有,需要使用时请参阅手册。

布局是前端设计的另一个重要部分,使用布局,我们可以有规则地安排控件,并方便地修改及调用。布局种类如下:

  • Vertical Layout: 垂直布局,控件垂直分布,并占满当前整个空间宽度
  • Horizontal Layout: 水平布局,控件水平分布,并占满当前整个空间高度
  • Grid Layout: 网格布局,控件呈网格状分布,可调网格比例
  • Form Layout: 表单分布,控件整体按照表单样式分布

在较简单的项目中,可以不使用Layout,直接按照绝对坐标安放控件。

后端调用

为了使前后端分离,方便后续迭代前端布局样式、改进后端代码,降低耦合度,我们使用窗口主逻辑引用前端布局类的方式实现调用前端的功能。

调用前端布局

一个简单的窗体程序框架如下(以QMainWindow基类为例)

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from mainWindowUI import Ui_MainWindow


class MainWindow(QMainWindow):
   def __init__(self, parent=None) -> None:
      super(MainWindow, self).__init__(parent)
      self.ui = Ui_MainWindow()
      self.ui.setupUi(self)

      # Other Initialize Code

   def someFunction(self):
      pass


if __name__ == '__main__':
   app = QApplication(sys.argv)
   main_window_instance = MainWindow()
   main_window_instance.show()
   sys.exit(app.exec_())
  • MainWindow类继承QMainWindow基类,在初始化时必须调用其超类的初始化,super().__init__
  • 使用PyUIC转换工具将UI设计文件转换为Python文件,引用到框架中,将self.ui设置为该前端的一个实例,并调用setupUi方法,初始化窗体控件
  • 主模块中声明一个QApplication,并加入系统参数,声明一个窗体Instance,并调用show()方法显示窗体,最后使用sys.exit函数,在窗体关闭后退出

信号连接

  信号与槽是Qt的核心机制。信号与槽的功能类似于VB.net的事件,后端逻辑通过事件捕获前端控件的各种状态,比如单击、鼠标进入、选项改变等。在Qt中,这种机制被信号与槽取代。

  • 信号:由前端的各种事件触发,自定义信号由代码触发

  • 槽:是信号的处理程序(函数),一个槽连接上信号后,每当信号被触发(emit),就会调用槽,以完成响应任务。

  • 信号与槽通过connect方法进行连接

一般信号

  一般信号类似于事件,由前端控件的状态变化触发。可以在前端设计器中连接控件之间的简单信号,大多数需要后端处理的信号,要在主逻辑类初始化时手动进行连接。

self.ui.pushButton.clicked.connect(MainWindow.someFunc)
  • 注意:连接信号的事件不需要加括号(是信号本身),槽也不需要括号(代表函数本身)

  • 其他信号类型参阅Qt Documentation

自定义信号

Qt允许自定义信号,用代码可以触发该信号,并能指定信号附加参数。

Qt5以上版本的信号需要在类中以类变量的形式提前声明:

from PyQt5.QtCore import pyqtSignal

SOME_SIGNAL = pyqtSignal()
SOME_SIGNAL_WITH_PARAM_INT = pyqtSignal(int)

使用emit方法触发自定义信号:

SOME_SIGNAL.emit()
SOME_SIGNAL_WITH_PARAM_INT.emit(some_int)

信号的连接方法与一般信号相同,这里不再赘述。

整体架构

完整的PyQt项目一般至少由三部分构成:

  • 前端设计代码,由设计器文件转换得到
  • 后端逻辑代码,由后端编程得到
  • 主逻辑代码,通过引用前后端文件,实现窗体显示与信号连接
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值