想要完成一个应用程序的开发,通常还需要一个可视化界面,QT就是可以帮助我们快速开发出可视化界面的一款工具,而利用QT实现页面布局,一般有两种方式,即通过qtdesigner和通过纯代码构建,第一种方式简单易见,可以通过拉取模块的方式快速实现页面的布局,而第二种方式需要自己心中首先构建好页面布局再进行编码,根据自己的需求进行选择。安装配置:https://blog.csdn.net/px41834/article/details/79383985
1、认识QtDesigner
打开QtDesigner,可以看到如下的界面,左侧是控件等,中间是页面的原始画布,右侧是其对应的属性,通过左侧拉取目标控件到画布上,然后在右侧属性中对其进行修改,可以实现界面的初始布局。
下面对其进行详细介绍,
(1)控件
布局(layouts)
布局:
|
空间间隔组(Spacers):
|
按钮组(Buttons)中各个按钮的名称依次解释如下:
|
项目视图组(Item Views):
|
项目组控件组(item widgets)
容器组(Containers):
|
输入部件组(Input Widgets):
展示控件组(display widgets)
还可以自定义一些控件,这里就不在赘述,详细可参考https://gitee.com/feiyangqingyun
(2)信号与槽
信号就是页面中的一些操作事件,传递给槽函数进行后续的处理,如点击信号,双击信号等,而槽函数就是对接收到的信号进行相应的函数。在QtDesigner中实现信号与槽,可以通过如下操作
2、一些小知识点
》信号与槽之间的传参
具体实例
基于lambda表达式:widget.signal.connect( lambda: slot(para) )
基于[]:widget.signal[par].connect(slot)
基于partial函数:widget.signal.connect( partial(slot,para) )
》多线程
实例(实现一个简单的视频播放器):
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author: albert time: 2020/6/20
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QPushButton,QLabel,QVBoxLayout,QFrame,QFileDialog
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QPixmap, QImage
from PyQt5 import QtGui
import cv2,time
class my_form(QWidget):
def __init__(self):
super(my_form,self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("load_video")
self.setGeometry(50,50,800,600)
###添加控件
self.bt1=QPushButton("load_video")
self.lab=QLabel()
self.lab.setFrameShape(QFrame.StyledPanel)
###添加布局
ly=QVBoxLayout(self)
ly.addWidget(self.lab)
ly.addWidget(self.bt1)
###添加槽函数
self.bt1.clicked.connect(self.play_video)
self.show()
def play_video(self):
videoName,videoType= QFileDialog.getOpenFileName(self,
"打开视频",
"",
" *.mp4;;*.avi;;All Files (*)")
self.th = Thread(videoName,self.lab.width(),self.lab.height()) ###变成类的属性,否则会出现线程错误
self.th.changePixmap.connect(self.setImage)
self.th.start()
def setImage(self, image): ###这是在label控件上显示图像或视频
self.lab.setPixmap(QPixmap.fromImage(image))
class Thread(QThread):#采用线程来播放视频
changePixmap = pyqtSignal(QImage)
def __init__(self,videoName,width,height):
super(Thread,self).__init__()
self.videoName=videoName
self.width=width
self.height=height
def run(self):
cap = cv2.VideoCapture(self.videoName)
while (cap.isOpened()==True):
ret, frame = cap.read()
if ret:
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QImage.Format_RGB888)#在这里可以对每帧图像进行处理,
p = convertToQtFormat.scaled(self.width, self.height, Qt.IgnoreAspectRatio)
self.changePixmap.emit(p)
time.sleep(0.01) #控制视频播放的速度
else:
break
def main():
app=QApplication(sys.argv)
window=my_form()
window.show()
app.exec_()
if __name__=="__main__":
main()
3、使用demo
(1)使用qtdesigner设计界面
通过上面对各控件的介绍,结合自己的需求进行拖拽布局,首先生成目标布局界面的ui文件,然后再利用pycharm里设计好的pyuic进行转换成可识别的py文件,最后再调用生成的布局py文件并显示,具体操作如下:
》ui布局
》转换布局py文件
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(526, 349)
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(370, 120, 51, 31))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setGeometry(QtCore.QRect(370, 180, 51, 31))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(Form)
self.pushButton_3.setGeometry(QtCore.QRect(370, 240, 51, 31))
self.pushButton_3.setObjectName("pushButton_3")
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(160, 50, 241, 20))
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(20)
self.label.setFont(font)
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(Form)
self.label_2.setGeometry(QtCore.QRect(80, 100, 261, 191))
self.label_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.label_2.setLineWidth(1)
self.label_2.setText("")
self.label_2.setObjectName("label_2")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "载入"))
self.pushButton_2.setText(_translate("Form", "检测"))
self.pushButton_3.setText(_translate("Form", "保存"))
self.label.setText(_translate("Form", "基于深度学习安全帽检测"))
》调用并显示
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QMainWindow
from load_test import Ui_Form
from PyQt5 import QtCore
class my_form(QMainWindow,Ui_Form):
def __init__(self):
super(my_form,self).__init__()
self.setupUi(self)
if __name__=="__main__":
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) ###保证按原来布局正常显示
app=QApplication(sys.argv)
t=my_form()
t.show()
app.exec_()
(2)窗口跳转:当窗口A调用窗口B的时候,两个窗口不能是同一类型。如把A写成QWidget类型,把窗口B改成Dialog类型,通过触发A上事件,就可以成功调用B。
class A(QWidget):
def __init__(self):
...省略...
self.btn = QPushButton('跳转按钮')
def initUI(self):
pass
class B(QDialog):
def __init__(self):
pass
def initUI(self):
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
a = A()
b = B()
a.show()
a.btn.clicked.connect(b.show) # 注意show,不要写成show()
app.exec_()
(3)垂直布局和水平布局,槽函数
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QPushButton,QFrame,QVBoxLayout,QHBoxLayout
from PyQt5.QtGui import QColor
class my_class(QWidget):
def __init__(self):
super(my_class,self).__init__()
self.initUI()
def initUI(self):
##窗体初始化
self.setWindowTitle("test3")
self.color=QColor(0,0,0)
dk=app.desktop()
self.setGeometry(dk.width()/2-self.width()/2,50,400,300)
##添加控件
btn1=QPushButton("red")
btn1.setCheckable(True)
btn1.clicked[bool].connect(self.setColor)
btn2=QPushButton("green")
btn2.setCheckable(True)
btn2.clicked[bool].connect(self.setColor)
btn3=QPushButton("blue")
btn3.setCheckable(True)
btn3.clicked[bool].connect(self.setColor)
self.frame=QFrame()
self.frame.setStyleSheet("QWidget{background-color:%s}"%self.color.name())
###控件布局
vly=QVBoxLayout()
vly.addWidget(btn1)
vly.addWidget(btn2)
vly.addWidget(btn3)
hly=QHBoxLayout(self) ###父容器种的声明需要带上self
hly.addLayout(vly)
hly.addWidget(self.frame)
self.show()
def setColor(self,p):
b=self.sender() ###接受信号,槽函数传参
v=255 if p else 0
print(p,b.text(),b)
if b.text() =="red":
self.color.setRed(v)
elif b.text() =="blue":
self.color.setBlue(v)
elif b.text()=="green":
self.color.setGreen(v)
print(self.color.name())
self.frame.setStyleSheet("QWidget{background-color:%s}"%self.color.name())
if __name__=="__main__":
app=QApplication(sys.argv)
t=my_class()
app.exec_()
4、打包
一般而言,当我们开发好了应用程序后,应该将其打包再进行发布,这里推荐使用Pyinstaller将其打包成.exe文件,其中pyinstaller使用方法可以参考《使用Pyinstaller转换.py文件为.exe可执行程序》。打包具体过程如下:
pyinstaller.exe -F call_login.py -w
成功的话,然后会在当前目录下生成三个文件,在dist目录下即可发现打包好的exe格式文件,双击即可运行。
参考链接:
https://blog.csdn.net/tsvico/article/details/77001750(Qt学习之Qt控件的介绍)
https://www.cnblogs.com/linyfeng/p/11223707.html([ PyQt入门教程 ] Qt Designer工具的使用)
https://blog.csdn.net/shangxiaqiusuo1/article/details/85253264(PyQt5实现多窗口切换的框架)