PyQt5是基于Qt5设计思路的Python图形用户界面工具包,可以协助用户创建图形界面。
PyQt5文档:
安装
PyQt5主程序包
在控制台中执行:
pip install PyQt5
PyQt5工具包
如果您的计算机上已安装Qt环境或QtCreator等工具,可以跳过此步骤。
在控制台中执行:
pip install PyQt5-Tools
第三方控件
此处以QCustomPlot绘图控件的PyQt5版本为例。
pip install QCustomPlot_PyQt5
建立窗体
推荐采用窗体逻辑和业务代码分离的设计,以保证程序的可维护性。
绘制窗体
您可以使用QtCreator、Qt Designer等工具可视化地绘制窗体。如果您已经安装了Qt开发环境或QtCreator,您可以直接启动这些工具。如果您使用PyQt5-Tools,您可以在Qt包根目录的site-packages\qt5_applications\Qt\bin\目录中找到designer.exe界面设计器。
请注意:如果您使用了“提升控件”功能将控件提升为第三方控件,请确保“头文件”一项使用包含该第三方控件的包的名称(同时添加.h扩展名)。例如,若您将QWidget提升为QCustomPlot,则应配置“提升的类名”为QCustomPlot,“头文件”为QCustomPlot_PyQt5.h。
这里假设您将窗体文件保存为MainWindow.ui。
将窗体文件转换为Python文件
PyQt无法直接识别UI格式的窗体文件,因此您需要将其转换为可执行的Python文件。
在控制台中执行:
python -m PyQt5.uic.pyuic MainWindow.ui -o ui_MainWindow.py
此时,得到的ui_MainWindow.py文件即为窗体代码文件,该文件定义了窗体UI基类Ui_MainWindow,包含了用于初始化窗体上的控件的setupUi()函数。
建立窗口代码文件
由于此时窗体界面信息和业务逻辑是分离的,因此需要创建名为MainWindow.py的业务代码文件,定义名为MainWindow的、同时继承QMainWindow和Ui_MainWindow基类的业务代码类:
# PyQt5 modules from PyQt5.QtCore import * from PyQt5.QtWidgets import * # QCustomPlot for PyQt5 from QCustomPlot_PyQt5 import * # UI File from ui_MainWindow import Ui_MainWindow # MainWindow implementation class MainWindow(QMainWindow, Ui_MainWindow) : # MainWindow constructor def __init__(self) : # Initialize base classes super().__init__() # Initialize widgets self.setupUi(self) # Application init pass #End Sub # MainWindow destructor def __del__(self) : pass #End Sub # Do cleaning works when closing def closeEvent(self, evtEvent) : # Generally you don't need to delete an object manually #self.__del__() evtEvent.accept() #End Sub #End Class
建立程序入口点
和基于C++的Qt一样,PyQt需要先建立QApplication对象启动事件循环,随后执行主窗口显示等任务,最后将执行结果返回给操作系统。此处将程序入口写入Main.py文件中:
# Public libraries import sys # PyQt5 modules from PyQt5.QtWidgets import QApplication # MainWindow classes from MainWindow import MainWindow # Main entry point if __name__ == "__main__" : # Create QApplication object and start main event loop appCurrent = PyQt5.QtWidgets.QApplication(sys.argv) # Show main window frmMainWindow = MainWindow() frmMainWindow.show() # Wait until main event loop exits sys.exit(appCurrent.exec_()) #End If
运行Main.py脚本,即可启动并展示主窗口。
使用信号与槽
PyQt的信号(Signal)与槽(Slot)思路与C++版本的Qt是一致的。但是在定义和使用时存在略微差异。
定义信号
任何继承自PyQt5.QtCore.QObject或其派生类的类均可定义类型为PyQt5.QtCore.pyqtSignal的对象实例,并将该对象实例作为信号使用:
SampleSignalWithNoParameters = pyqtSignal()
PyQt5.QtCore.pyqtSignal的构造函数可以输入一个列表,表示该信号可以传递的参数的类型。将多个数据类型使用方括号“[]”括起表示该参数可以传递多种类型的信号。例如,若一个信号的第一个参数必须为整数,而第二个参数可以为整数或字符串,则可以使用下面的方式定义:
SampleSignalWith2Parameters = pyqtSignal(int, [int,str])
定义槽
槽函数的定义与常规成员函数一致。
连接信号与槽
信号对象提供的PyQt5.QtCore.pyqtSignal.connect()函数可用于将信号与槽连接:
objEmitter.SampleSignal.connect(objReceiver.SampleSlot)
信号对象提供的PyQt5.QtCore.pyqtSignal.disconnect()函数可用断开信号与槽的连接:
objEmitter.SampleSignal.disconnect(objReceiver.SampleSlot)
发射信号
信号对象提供的PyQt5.QtCore.pyqtSignal.emit()函数可用于发射信号并传递参数:
self.SampleSignal.emit(objParam1, objParam2, ...)
示例程序
SignalSlotTest.py:定义信号发生器类SignalEmitter和接收器类SignalReceiver。
# PyQt5 modules from PyQt5.QtCore import * # Sample signal emitter class SignalEmitter(QObject) : # Sample signal with no parameters SampleSignalWithNoParameters = pyqtSignal() # Sample signal with 1 string parameter SampleSignalWith1Parameter = pyqtSignal(str) # Sample signal with 2 parameters, both can be Integer or String SampleSignalWith2Parameters = pyqtSignal([int,str], [int,str]) # Signal emitting test def TestEmittingSignals(self) : # Emit signal with no parameters self.SampleSignalWithNoParameters.emit() # Emit signal with 1 parameter self.SampleSignalWith1Parameter.emit("Picsell Dois") # Emit signal with 2 parameters self.SampleSignalWith2Parameters.emit(245, "Suicune") #End Sub #End Class # Sample signal receiver class SignalReceiver(QObject) : # Slot with no parameters def SampleSlotWithNoParameters(self) : print("SampleSlotWithNoParameters: Executed with no parameters received.") #End Sub # Slot with 1 parameter def SampleSlotWith1Parameter(self, sData : str) : print(f"SampleSlotWithWith1Parameter: Received {sData}") #End Sub # Slot with 2 parameters def SampleSlotWith2Parameters(self, iData1 : int, sData2 : str) : print(f"SampleSlotWithWith1Parameter: Received {iData1} and {sData2}") #End Sub #End Class
Main.py:程序主入口。
# Public libraries import sys # PyQt5 modules from PyQt5.QtWidgets import QApplication # Signal emitter and receiver classes from SignalSlotTest import SignalEmitter,SignalReceiver # Main entry point if __name__ == "__main__" : # Create QApplication object and start main event loop appCurrent = QApplication(sys.argv) # Create signal emitter and receiver objects objEmitter = SignalEmitter() objReceiver = SignalReceiver() # Connect signals and slots objEmitter.SampleSignalWithNoParameters.connect(objReceiver.SampleSlotWithNoParameters) objEmitter.SampleSignalWith1Parameter.connect(objReceiver.SampleSlotWith1Parameter) objEmitter.SampleSignalWith2Parameters.connect(objReceiver.SampleSlotWith2Parameters) # Test emitting signals objEmitter.TestEmittingSignals() # Wait until main event loop exits #sys.exit(appCurrent.exec_()) #End If
参考资料
https://www.riverbankcomputing.com/static/Docs/PyQt5/
https://pypi.org/project/PyQt5/
https://pypi.org/project/QCustomPlot-PyQt5/
https://blog.csdn.net/weixin_42475060/article/details/130327901
https://www.nixgnauhcuy.cn/8d34424033d0/
https://blog.csdn.net/yg2496194392/article/details/129944809
https://blog.csdn.net/qq_62095154/article/details/122947262
https://www.cnblogs.com/chenhaiming/p/9930628.html
https://blog.csdn.net/huayunhualuo/article/details/102718509