文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【Python】PyQt5入门

2023-10-20 21:52

关注

文章目录

0 前言

  最近接了一个小项目,主要任务是完成一个界面的设计,而且是基于Python,我第一反应就是使用大名鼎鼎的Qt来设计。Qt最早是用C语言开发的,但是后来也有了基于Python的第三方包,目前最新版是PyQt6.3,但是这个项目中使用的还是普及度更高的PyQt5。正好我也比较喜欢Python编程,于是边学边做,简单总结一些入门要点,授人与渔。

在此特别感谢Chat-GPT的帮助!真的是编程的利器!

1 PyQt5及其基本模块

  要使用PyQt5,首先需要进行安装:pip install PyQt5,如果想要尝鲜也可以安装PyQt6:pip install PyQt6
  PyQt5主要有三个部分:【摘抄自网上】

  了解包的结构还是非常有必要的,这样在看别人代码时能够有一个比较清晰的认识,也能快速定位到使用的包所在的位置。一般导入某个具体的类时会使用如下所示的import方式:

from PyQt5.QtWidgets import xxxx,xxxxfrom PyQt5.QtGui import xxxxx,xxxxfrom PyQt5.QtCore import xxxxxx,xxxxx

2 开发方式

  如果是用C++开发Qt,那必须得下载一个Qt Creator,来实现代码和界面进行关联,使开发过程更加便捷。但是用PyQt5的Python第三方包来开发,只需要下载一个Qt Designer用来设计UI界面即可。

  不过Qt Designer似乎不能通过下载一个执行程序来进行安装,而是通过下载第三方包的方式来下载。这里一般有两种方式。

PySide2和PyQt之间的兼容性据说不错,它们之间的关系可以在网上找到很多比较详细的叙述。

  因此实际开发项目时,是使用Qt Designer来设计UI界面,得到一个.ui的文件,然后利用PyQt5安装时自带的工具pyuic5将.ui文件转换为.py文件:

pyuic5 -o mywindow.py mywindow.ui #先是py文件名,再是ui文件名

当然,如果是使用VS Code写代码,也可以考虑安装一个插件,帮助你执行这行命令。

在这里插入图片描述

在这里插入图片描述

之后再新开一个py文件,进行逻辑编写,这样实现了界面与逻辑分离,代码结构更加清晰。如下图所示是一般项目的结构:
在这里插入图片描述

虽然网上有很多都是上来就写代码运行得到窗口的教程,但是个人建议初学者还是先使用软件设计好UI文件,再转换成代码的方式,这样更加直观,而且调整控件位置也更方便。

  综上所述,PyQt5的开发主要是两个核心:ui界面的设计逻辑代码的编写。前者主要是会玩Qt Designer这个软件即可;后者理清楚代码结构也不是很难。

3 UI界面设计(Qt Designer)

  先来看看ui界面怎么玩:打开Qt Designer,点击新建,会弹出一个窗口:
在这里插入图片描述

这里一般是选择Main Window或者Widget,其中Main Window继承自Widget,添加了一些内容,本质二者差不多。这里选择的是Widget。
  建好文件后,得到一个空白页面,接下来就是往里面拖动控件并设计样式了,如下图所示。
在这里插入图片描述

这部分内容过于琐碎,这里只记录一些要点,后续随缘更新,遇到问题建议点对点搜索。

4 逻辑代码的基本结构

  要想写好逻辑代码,首先要清楚它的基本结构。
  前面提到,除ui界面代码,还需要有一个逻辑代码,而逻辑代码个人感觉使用类的形式来组织更加方便,也更优雅。还记得创建ui时选择的类吗?是Widget还是Main Window,逻辑代码类最好是继承这个这个类,即QWidgetQMainWindow。一般的代码结构如下所示。

# 先导入主要的三个模块和各自内部常用的类from PyQt5 import QtCore, QtWidgets, QtGuifrom PyQt5.QtCore import pyqtSlotfrom PyQt5.QtWidgets import QApplication, QWidgetfrom PyQt5.QtGui import QColor# 再导入设计的ui界面转换成的py文件from Ui_window import Ui_Formclass mywindow(QWidget): #这里一定要继承QWidget类或者是QMainWindow类    '''初始化函数    '''    def __init__(self) -> None:        super().__init__() #先初始化父类【必须】        self.ui = Ui_Form()        self.ui.setupUi(self) #这个函数本身需要传递一个QWidget类,而该类本身就继承了这个,所以可以直接传入self(这就是继承的好处)    '''按钮连接的槽函数    '''    @pyqtSlot() #装饰器,表示该函数是按名称自动被连接    def on_pushButton_clicked(self):        print("Pressed the pushButton")if __name__ ==  "__main__":# 这里的代码逻辑基本相同    app = QApplication([]) #先建立一个app    wid = mywindow() #初始化一个对象,调用init函数,已加载设计的ui文件    wid.show() #显示这个ui    app.exec_() #执行app(运行界面,响应按钮等操作)

这里有一个需要注意,那就是按钮连接的槽函数,这里没有调用connect函数,而是使用了@pyqtSlot()这个装饰器,但前提就是要求函数命名要按照规则来:on_(控件对象名)_信号名(self,内置参数)。此外,想实现这个功能,还需要打开一个开关,这句代码默认在ui界面文件中就有,如下图所示。

在这里插入图片描述

5 常用控件及其使用方法

这部分内容过于琐碎,后续随缘更新,个人建议拿不准先问问Chat-GPT怎么说😅

5.1 QTableView //2023.4.11

  最近查一个代码的bug,发现界面运行起来之后内存在不断增加,通过逐行注释代码,最终找到问题所在。先看原始代码:

table:QTableView = self.ui.tabWidget1.widget(i).findChild(QTableView) #得到对应的表格model = QStandardItemModel()for j in range(len(self.packs[i])): #遍历一个列表items = [QStandardItem(str(j)), QStandardItem(self.packs[i][j])]model.appendRow(items)table.setModel(model)

以上代码是在一个类中的成员函数当中,理论上都是局部变量,那么在调用函数完毕后所有的局部变量的内存都需要释放,也就是程序总的内存占用应该是平衡的才对,但实际上就是在不断增长(任务管理器数字缓慢上升)
  通过控制变量,最终发现就是函数appendRow的问题,只要一注释这行,内存立刻稳定了。由于pyqt是C语言写的,这里也不方便溯源,所以没找到问题所在。

  最终还是解决了的,那就是换一个函数,通过在网上找TableView刷新数据的方式,最终使用setItem解决了这个问题。改变后的代码如下:

table:QTableView = self.ui.tabWidget1.widget(i).findChild(QTableView) #得到对应的标签页model = QStandardItemModel()for j in range(len(self.packs[i])):##这种方式会出现内存泄漏# items = [QStandardItem(str(j)), QStandardItem(self.packs[i][j])]# model.appendRow(items)model.setItem(j,0,QStandardItem(str(j)))model.setItem(j,1,QStandardItem(self.packs[i][j]))table.setModel(model)

6 参考链接

7 Qt中使用数据库

参考链接

8 拓展问题——python自带库Tkinter

  作为python自带的GUI库,虽然控件更少,但使用也更简单,比较适合界面不是很复杂的应用(貌似没有图形界面操作,只能用代码编写)

教程链接

9 其他问题

# 先导入主要的三个模块和各自内部常用的类from PyQt5 import QtCore, QtWidgets, QtGuifrom PyQt5.QtCore import pyqtSlot,pyqtSignalfrom PyQt5.QtWidgets import QApplication, QWidgetfrom PyQt5.QtGui import QColor# 再导入设计的ui界面转换成的py文件from Ui_window import Ui_Formclass mywindow(QWidget): #这里一定要继承QWidget类或者是QMainWindow类    '''初始化函数    '''    sig = pyqtSignal(list) #要定义为类属性,参数传发射数据的类型    def __init__(self) -> None:        super().__init__() #先初始化父类【必须】        self.ui = Ui_Form()        self.ui.setupUi(self) #这个函数本身需要传递一个QWidget类,而该类本身就继承了这个,所以可以直接传入self(这就是继承的好处)        self.sig.connect(self.func)    '''按钮连接的槽函数    '''    @pyqtSlot() #装饰器,表示该函数是按名称自动被连接    def on_pushButton_clicked(self):        print("Pressed the pushButton")def func(self, l:list) #这个函数的参数要和信号声明时的参数保持一致print("发送的数据为: ", l)if __name__ ==  "__main__":# 这里的代码逻辑基本相同    app = QApplication([]) #先建立一个app    wid = mywindow() #初始化一个对象,调用init函数,已加载设计的ui文件    wid.show() #显示这个ui    app.exec_() #执行app(运行界面,响应按钮等操作)# 其他线程中的函数,可以不在同一文件win = mywindow() #窗口变量# 一大堆显示函数# 线程刷新数据def thread1():s = [1,2,3,4,5]win.sig.emit(s) #参数还是要和声明信号时保持一致

总结来说,大概有这么几点:①信号声明最好是放在窗口类中,更加紧凑(有说这个信号只能在类中使用,不能直接定义一个全局变量);②声明时的参数,响应函数的参数,激发时传递的数据类型全部保持一致,这个很重要;③如果不同线程都会刷新界面,建议分开信号传递,不要都用一个信号,怕出问题。

关于在PyQt中使用多线程,可以看看这篇文章,写得很详细

来源地址:https://blog.csdn.net/ZHOU_YONG915/article/details/129400618

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯