赞
踩
我们从最简单的示例来认识PyQt5的程序框架
从 文件->新建项目,创建一个默认的python脚本
点击创建;目录结构如下图
直接点击右上角的绿色小三角,运行程序,可以看到下面的"Hi,Pycharm"输出。
这是pycharm创建一个默认python脚本文件,然而与本节的PyQt5还没有关系,我们可以修改下main.py内容如下:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets #导入PyQt5包中的几个模块
app = QtWidgets.QApplication(sys.argv) #创建App,用QApplication类
LabHello = QtWidgets.QLabel() #创建一个标签LabHello
LabHello.setText("Hello World, PyQt5") #设置标签文字
LabHello.setMinimumSize(400,200) #设置最小宽高
LabHello.show()
sys.exit(app.exec_()) #应用程序运行
运行脚本:效果如下
从代码可以看出,PyQt5的基本结构有:
Qt GUI 提供了两种方式来开发GUI程序,一种是纯代码的方式,一种是通过Qt Designer可视化界面来设计,当界面的元素很多,其中有各种的布局、按钮、信号、槽的情况下,使用可视化Designer通过简单的拖动,设置可以大大便利功能的开发。
那如何在PyQt5中使用Qt Desinger呢? 步骤主要有如下
首先,我们用QtCreator创建一个最贱的基于QWidget的窗口程序:如下
用Desinger编辑widget.ui,拖入一个QLabel和一个QPushButton
我们切换到编辑模式,可以看到ui文件内容,其实是个xml结构的文件,里面定义了元素的各种属性
我们运行下,可以看到程序的效果:跑题了,我们应该如何在Python下用UI文件呢?
pyuic5.exe 在Python安装目录的/scripts/目录下,打开cmd,进入到上面ui文件所在目录
C:\Users\wmm\Desktop\test\qt\L1,然后执行命令pyuic5 -o widget.py widget.ui
,可以看到当前目录生成了一个 widget,py文件,如下
widget.py文件内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Widget(object): def setupUi(self, Widget): Widget.setObjectName("Widget") Widget.resize(373, 233) self.pushButton = QtWidgets.QPushButton(Widget) self.pushButton.setGeometry(QtCore.QRect(140, 160, 80, 20)) self.pushButton.setObjectName("pushButton") self.label = QtWidgets.QLabel(Widget) self.label.setGeometry(QtCore.QRect(150, 110, 121, 21)) font = QtGui.QFont() font.setFamily("Agency FB") font.setPointSize(14) self.label.setFont(font) self.label.setObjectName("label") self.retranslateUi(Widget) QtCore.QMetaObject.connectSlotsByName(Widget) def retranslateUi(self, Widget): _translate = QtCore.QCoreApplication.translate Widget.setWindowTitle(_translate("Widget", "Widget")) self.pushButton.setText(_translate("Widget", "关闭")) self.label.setText(_translate("Widget", "Hello pyQt"))
可以看到定义了基于object的Ui_Widget类和 两个方法,def setupUi和 def retranslateUi
需要注意的是:
Ui_Widget是基于object,其本身并不是一个窗体,窗体是通过setupUi的参数Widget来传入的,Widget作为其控件的父窗口.
我们把上面生成widget.py拷贝我们第一步的main.py目录下
然后修改我们的main.py内容如下:
import sys
from PyQt5 import QtWidgets
import widget
app = QtWidgets.QApplication(sys.argv)
parentWidget = QtWidgets.QWidget() #创建窗口的基类QWidget的实例
ui = widget.Ui_Widget() #创建UI窗口的实例
ui.setupUi(parentWidget) #以baseWidget作为传递参数
ui.label.setText("修改了文本")
parentWidget.show()
sys.exit(app.exec_())
运行下main.py,结果如下
至此,我们已经在python中使用了我们在Qtcreator创建的ui文件,并且成功运行展示了窗口。
信号和槽是Qt框架的精髓,为了更全面的展示信号槽机制,我们对上面的ui文件做了些修改。如图
我们增加了两个按钮Text1 和 Text2, 一个QCheckBox,并且内置修改了关闭按钮的槽函数连接,仍然用 pyuic5 -o widget.py widget.ui
生成widget.py脚本,并且拷贝到我们的Pyqt工程中,打开widget.py,我们可以看到内容如下:
可以看到我们给窗口的元素重新设置了objectname.
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Widget(object): def setupUi(self, Widget): Widget.setObjectName("Widget") Widget.resize(373, 233) self.pbn_close = QtWidgets.QPushButton(Widget) self.pbn_close.setGeometry(QtCore.QRect(260, 180, 80, 20)) self.pbn_close.setObjectName("pbn_close") self.lab_hello = QtWidgets.QLabel(Widget) self.lab_hello.setGeometry(QtCore.QRect(90, 40, 251, 51)) font = QtGui.QFont() font.setFamily("微软雅黑") font.setPointSize(14) self.lab_hello.setFont(font) self.lab_hello.setObjectName("lab_hello") self.chb_visible = QtWidgets.QCheckBox(Widget) self.chb_visible.setGeometry(QtCore.QRect(40, 130, 73, 18)) self.chb_visible.setObjectName("chb_visible") self.pbn_text1 = QtWidgets.QPushButton(Widget) self.pbn_text1.setGeometry(QtCore.QRect(40, 180, 80, 20)) self.pbn_text1.setObjectName("pbn_text1") self.pbn_text2 = QtWidgets.QPushButton(Widget) self.pbn_text2.setGeometry(QtCore.QRect(140, 180, 80, 20)) self.pbn_text2.setObjectName("pbn_text2") self.retranslateUi(Widget) self.pbn_close.clicked.connect(Widget.close) #关闭按钮连接了Widget的close函数 QtCore.QMetaObject.connectSlotsByName(Widget) def retranslateUi(self, Widget): _translate = QtCore.QCoreApplication.translate Widget.setWindowTitle(_translate("Widget", "Widget")) self.pbn_close.setText(_translate("Widget", "关闭")) self.lab_hello.setText(_translate("Widget", "Hello pyQt")) self.chb_visible.setText(_translate("Widget", "隐藏")) self.pbn_text1.setText(_translate("Widget", "Text1")) self.pbn_text2.setText(_translate("Widget", "Text2"))
其中重点注意这两句:
self.pbn_close.clicked.connect(Widget.close)
QtCore.QMetaObject.connectSlotsByName(Widget)
可以看到在pyqt5里面,信号槽的链接方式是:
sender.signalName.connect(receiver.slotName)
QtCore.QMetaObject.connectSlotsByName(Widget)是使用qt的元对象默认将信号和槽函数关联起来,规则是:
on__<signal_name>()
比如我们上面的pbn_text1按钮,默认的槽函数链接会是:
on_pbn_text1_clicked()
我们都知道QPushButton 有clicked()信号,所以我们尝试在widget.py文件中定义槽函数
def onPbnText1Clicked(self):
t = self.pbn_text1.text()
self.lab_hello.setText(t)
并在def setupUi(self, Widget):
中添加这句self.pbn_text1.clicked.connect(self.onPbnText1Clicked)
运行程序,点击Text1按钮,可以看到
完整的widget.py文件内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Widget(object): def setupUi(self, Widget): Widget.setObjectName("Widget") Widget.resize(373, 233) self.pbn_close = QtWidgets.QPushButton(Widget) self.pbn_close.setGeometry(QtCore.QRect(260, 180, 80, 20)) self.pbn_close.setObjectName("pbn_close") self.lab_hello = QtWidgets.QLabel(Widget) self.lab_hello.setGeometry(QtCore.QRect(90, 40, 251, 51)) font = QtGui.QFont() font.setFamily("微软雅黑") font.setPointSize(14) self.lab_hello.setFont(font) self.lab_hello.setObjectName("lab_hello") self.chb_visible = QtWidgets.QCheckBox(Widget) self.chb_visible.setGeometry(QtCore.QRect(40, 130, 73, 18)) self.chb_visible.setObjectName("chb_visible") self.pbn_text1 = QtWidgets.QPushButton(Widget) self.pbn_text1.setGeometry(QtCore.QRect(40, 180, 80, 20)) self.pbn_text1.setObjectName("pbn_text1") self.pbn_text2 = QtWidgets.QPushButton(Widget) self.pbn_text2.setGeometry(QtCore.QRect(140, 180, 80, 20)) self.pbn_text2.setObjectName("pbn_text2") self.retranslateUi(Widget) self.pbn_close.clicked.connect(Widget.close) #关闭按钮连接了Widget的close函数 self.pbn_text1.clicked.connect(self.onPbnText1Clicked) QtCore.QMetaObject.connectSlotsByName(Widget) def retranslateUi(self, Widget): _translate = QtCore.QCoreApplication.translate Widget.setWindowTitle(_translate("Widget", "Widget")) self.pbn_close.setText(_translate("Widget", "关闭")) self.lab_hello.setText(_translate("Widget", "Hello pyQt")) self.chb_visible.setText(_translate("Widget", "隐藏")) self.pbn_text1.setText(_translate("Widget", "Text1")) self.pbn_text2.setText(_translate("Widget", "Text2")) def onPbnText1Clicked(self): t = self.pbn_text1.text() self.lab_hello.setText(t)
我们用一下内容,保存成human.py 来演示自定义信号、槽的用法
import sys from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal class Human(QObject): ## 定义一个带str类型参数的信号 nameChanged = pyqtSignal(str) ## overload型信号,两种参数,一种int,一种str ageChanged = pyqtSignal([int],[str]) def __init__(self,name='Mike',age=10,parent=None): super().__init__(parent) #调用父类构造函数 self.setAge(age) self.setName(name) def setAge(self,age): self.__age= age self.ageChanged.emit(self.__age) #int参数信号 if age<=18: ageInfo="你是 少年" elif (18< age <=35): ageInfo="你是 年轻人" elif (35< age <=55): ageInfo="你是 中年人" elif (55< age <=80): ageInfo="您是 老人" else: ageInfo="您是 寿星啊" self.ageChanged[str].emit(ageInfo) #str参数信号 def setName(self,name): self.__name = name self.nameChanged.emit(self.__name) class Responsor(QObject): @pyqtSlot(int) def do_ageChanged_int(self,age): print("你的年龄是:"+str(age)) @pyqtSlot(str) def do_ageChanged_str(self,ageInfo): print(ageInfo) # @pyqtSlot(str) def do_nameChanged(self, name): print("Hello,"+name) if __name__ == "__main__": ##测试程序 print("**创建对象时**") boy=Human("Boy",16) resp=Responsor() boy.nameChanged.connect(resp.do_nameChanged) ## overload的信号如果都定义了槽函数,两个槽函数不能同名,连接时需要给信号加参数区分 boy.ageChanged.connect(resp.do_ageChanged_int) #缺省参数,int型 boy.ageChanged[str].connect(resp.do_ageChanged_str) #str型参数 print("\n **建立连接后**") boy.setAge(35) #发射 两个ageChanged 信号 boy.setName("Jack") #发射nameChanged信号 boy.ageChanged[str].disconnect(resp.do_ageChanged_str) #断开连接 print("\n **断开ageChanged[str]的连接后**") boy.setAge(10) #发射 两个ageChanged 信号
运行结果:
可以看到,信号的定义需要注意一下几点:
## 定义一个带str类型参数的信号
nameChanged = pyqtSignal(str)
## overload型信号,两种参数,一种int,一种str,第一个int时默认信号参数
ageChanged = pyqtSignal([int],[str])
self.ageChanged[str].emit(ageInfo) #str参数信号
self.nameChanged.emit(self.__name) //name参数
boy.nameChanged.connect(resp.do_nameChanged)
修饰符@pyqtSlot用来声明槽函数的参数类型,特别是用在overload,以确保信号和槽函数能正确的连接
@pyqtSlot(int)
def do_ageChanged_int(self,age):
print("你的年龄是:"+str(age))
@pyqtSlot(str)
def do_ageChanged_str(self,ageInfo):
print(ageInfo)
boy.ageChanged[str].disconnect(resp.do_ageChanged_str) #断开连接
自定义信号时,尽量不要定义overload型信号,因为python的某些类型转换为C++时,对C++来说可能时同一种类型的参数,比如,若定义一个overload型的信号:
valueChanged = pyqtSignale([dict],[list])
dict和lict在Python中是不同的数据类型,但是转化为c++时,有可能就是同一个数据类型了,这样的连接方式就会出现问题。
资源文件主要功能是存储图片和图标文件。
在Qt Creator里,右键工程add new->选择Qt-> Qt Resource File
生成了L1.qrc文件
右键,可拿到该图片的路径 比如 “:/bg.png” 或 “qrc:/bg.png”
资源文件用过pyrcc5来编译成Python文件
pyrcc5 L1.qrc -o L1_rc.qrc
注意 编译后的资源文件名,必须是源文件名后面加"_rc"
如图可以展示图片了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。