在通过QT Designer设计好我们需要的组件后,下面就是代码的使用啦!
PyQt5的使用(二)
1、新建main文件实现QT的各种功能
通过PY UIC将UI文件转换成Py文件后,会生成如下代码的逻辑功能Py文件
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(50, 50, 75, 23))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
#这里往下会显示出你QT Designer设计的组件
self.pushButton.setText(_translate("MainWindow", "选择"))
但往往为了让UI设计文件与逻辑功能文件分开,通常新建一个py文件,导入刚生成的GUI.py中的 Ui_MainWindow。
这里定义的mywindow类,继承PyQT中的QtWidgets.QMainWindow外,
就是需要继承刚才PY UIC将UI文件转换成Py文件后自动生成的主窗口类Ui_MainWindow
import sys
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QDockWidget, QListWidget
from PyQt5.QtGui import *
from GUI import Ui_MainWindow # 导入创建的GUI类
#这里定义的mywindow类,继承PyQT中的QtWidgets.QMainWindow外,
就是需要继承刚才PY UIC将UI文件转换成Py文件后自动生成的主窗口类Ui_MainWindow
class mywindow(QtWidgets.QMainWindow,Ui_MainWindow): #这里其实就是主窗口继承QtWidgets中的QMainWindow,还有就是QT生成的主窗口
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = mywindow()
window.show()
sys.exit(app.exec_())
1.1设置窗口的尺寸、标题和图标
通过mywindow()实例化window对象,window就代表我们的主窗口了,就可以通过window这个对象对窗口进行操作了。
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = mywindow()
window.resize(700, 500) # 把显示的主窗口尺寸设置为700 * 500
window.setWindowTitle('pyqt5--') # 把显示的主窗口左上角标题命名为pyqt5--
window.setWindowIcon(QIcon('1.jpg')) #设置主窗口左上角的图标
window.show()
sys.exit(app.exec_())
或者在创建的主窗口类中实现,self就相当于对象。
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, model_path, dataset_path, filename):
super(mywindow, self).__init__()
self.resize(700, 500)
。。。。。
。。。。。。
1.2QT界面初始化显示图片
通常我们是将button键触发和槽函数进行连接。其实,就是将QLabel直接直接通过 .setPixmap
直接显示图片。
def __init__(self, model_path, dataset_path, filename):
super(mywindow, self).__init__()
self.setupUi(self)
self.label.setScaledContents(True) #将要显示得图片自适应QLabel大小
self.label.setPixmap(QPixmap('img_1.png'))
所以这里代码运行时,界面就会有一个初始化界面啦。
1.3关闭窗口
在QT Designer中拖动push button并更改text为“关闭”,
这里的self.pushButton,pushButton就是上面组件的objectname。
就是将pushButton触发的点击事件与close_window槽函数进行连接
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.close_window)
def close_window(self):
sys.exit(0)
1.4选择并读取文件夹中文件
// QFileDialog.getOpenFileName()会有返回两个值:
文件地址和文件类型
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
#将 pushButton 的点击事情与槽函数进行连接
self.pushButton.clicked.connect(self.show_file)
#打开文件槽函数
def show_file(self):
image_path, filetype = QFileDialog.getOpenFileName()
print(image_path)
print(filetype)
这里我选择了一个文件夹下的一个图片文件,将图片路径地址打印出来。
1.5opencv读取本地文件夹图片与QLabel显示图片
这里我们通过将push_button组件“选择”与打开文件夹进行连接,获取到图片路径后,使用Opencv读入图片,并生成QImae图片数据,最后在QLabel中显示出来。
这里的 QImage.Format_RGB888
, 是因为图片是一个24位RGB图片,可以按需修改
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
#将 pushButton 的点击事情与槽函数进行连接
self.pushButton.clicked.connect(self.show_file)
#QLabel显示图片槽函数
def show_file(self):
#获取到文件夹中文件的路径地址
image_path, filetype = QFileDialog.getOpenFileName()
img = cv2.imread(image_path)
image_height, image_width, image_depth = img.shape
# opencv读出来的是BGR,而在QT中使用正常的RGB显示
QIm = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#创建QImage格式,并生成图片
QIm = QImage(QIm.data, image_width, image_height,
image_width * image_depth, QImage.Format_RGB888)
#在QLabel组件中显示QImage图片
self.label.setScaledContents(True) #让图片适应QLabel的大小
self.label.setPixmap(QPixmap.fromImage(QIm))
1.6主界面显示当前电脑时间
主要就是需要通过 QTimer()
、 QDate
、 QTime
来实现:
QTimer()
创建一个定时器,并且在设置好的定时时间到了后,产生信号并于槽函数进行连接
QDate
、 QTime
同过 .currentDate
来获取当前系统的日期和时间
最后将获得的日期和时间,转换成字符,在QLabel中显示
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
#创建一个定时器
self.datetime = QTimer()
# 启动获取系统时间/日期的定时器,定时时间为10ms,10ms产生一次信号
self.datetime.start(10)
self.datetime.timeout.connect(self.data_time)
def data_time(self):
#当前日期
date = QDate.currentDate()
self.label_2.setText(date.toString())
#当前时间
time = QTime.currentTime()
self.label_3.setText(time.toString())
1.7菜单栏的创建
主要是两种方法:
(1)结合QT Designer
双击“Type Here”, 输入“File(&F)”后按回车键。(&F)表示通过“Alt + F”快捷键直接打开。
接下来在当前菜单项,创建二级菜单
双击输入自己的内容,按回车
最后就是通过与槽函数进行连接,实现对应的功能了:
在菜单栏的操作中,注意槽函数的连接通过triggered.connect
来实现。
actionopen就是这个菜单项的objectName。这里我使用默认(可以按需修改)。
def __init__(self):
super(mywindow, self).__init__()
self.actionopen.triggered.connect(self.close_window)
(2)代码生成
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
menuBar = self.menuBar() # 实例化一个菜单栏
# 添加菜单栏中得菜单.......
fileMenu = menuBar.addMenu('文件(&F)')
editMenu = menuBar.addMenu('编辑(&E)')
formatMenu = menuBar.addMenu('格式(&O)')
helpMenu = menuBar.addMenu('帮助(&H)')
菜单栏创建完成后,就是在对应的菜单项下创建二级菜单了。
其实就是,QAction创建一个具体的动作,然后将这个动作与槽函数进行连接。
最后,通过 .addAction
选择将这这个二级菜单的动作添加到哪个一级菜单项中。
fileMenu = menuBar.addMenu('文件(&F)')
aFileNew = QAction('新建(&N)', self)
aFileNew.triggered.connect(self.close_window)
fileMenu.addAction(aFileNew)
再介绍一下快捷键的设置:
创建好QAction动作后,可以通过 .setShortcut
创建快捷键。
aFileOpen.setShortcut(Qt.CTRL + Qt.Key_O)
这个表示通过“ctrl + o”快捷键实现该QAction动作。
1.8创建子界面
其实不难,如果需要在子界面再加一些功能需求,其实各个界面之间都是独立的,最后通过槽函数连接打开对应的子界面后,就相当于在子界面操作你在子界面设置的这些功能了!
这里我们将上面的菜单栏联合起来,使用菜单栏中的打开子界面。
首先新建一个Widget窗口,生成.UI文件后,PY UIC生成逻辑文件.py。
我们依旧和上面主窗口一样,为了让UI设计文件与逻辑功能文件分开,通常新建一个py文件。
#这里其实就是主窗口继承那里类似,因为是创建的QWidget窗口,所以这里自己新建的py文件继承QtWidgets中的QWidget,还有就是QT生成的QWidget窗口的py逻辑功能文件
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QDockWidget, QListWidget
from PyQt5.QtGui import *
from second import Ui_Form # 导入子UI界面
class secondwindow(QtWidgets.QWidget, Ui_Form): # 创建子UI类
def __init__(self):
super(secondwindow, self).__init__()
self.setupUi(self)
接着就是在主窗口中的菜单栏的打开子界面
在主窗口中实例化子界面,再通过将菜单项的QAction动作与打开子界面的槽函数连接。
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow): # 这里其实就是主窗口继承QtWidgets中的QMainWindow,还有就是QT生成的主窗口
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
#实例化子界面
self.second_window = secondwindow()
self.actionopen_o.triggered.connect(self.open_second)
def open_second(self):
self.second_window.show()
然后在子界面的一些常规操作:设置窗口大小、标题、图标…都和上面详细讲的主窗口方法一样。。
2、QT结合摄像头读取、显示、保存
为了方便对摄像头的各个功能的调用,这里创建一个相机类,里面封装了我们需要用的方法:
打开摄像头、读取摄像头数据、将读取的摄像头数据转换成QT可以显示的QImage格式、关闭摄像头
class camera():
def __init__(self):
#self.capture表示打开摄像头的对象
self.capture = cv2.VideoCapture(0)
if self.capture.isOpened():
print("isopenned")
# 读取摄像头数据
def read_camera(self):
ret, pic_data = self.capture.read()
pic_data = cv2.flip(pic_data, 1) # 摄像头是和人对立的,将图像左右调换回来正常显示。
if not ret:
print("获取摄像头数据失败")
return None
return pic_data
# 把数据转换成QT界面能显示的数据格式
def camera_to_pic(self):
pic = self.read_camera()
# 摄像头是BGR方式存储,需要转换成RGB
self.currentframe = cv2.cvtColor(pic, cv2.COLOR_BGR2RGB)
# 设置宽高
#self.currentframe = cv2.cvtColor(self.currentframe, (640, 480))
# 转换为界面能够显示的格式
# 获取画面的宽度与高度
height, width = self.currentframe.shape[:2]
# 先转换为QImage类型图片(画面),创建QImage类对象,使用摄像头画面数据
# QImage(data,width,height,format)创建:数据,宽度,高度,格式
qimg = QImage(self.currentframe, width, height, QImage.Format_RGB888)
qpixmap = QPixmap.fromImage(qimg)
return qpixmap
# 摄像头关闭
def close_camera(self):
self.capture.release()
2.1QT显示摄像头画面
这里最大的问题就是QT显示摄像头画面的时候,不能达到一个很流畅的实时拍摄画面。
这里和上面的QT显示当前系统一个道理,需要创建一个定时器,然后启动获取系统时间/日期定时器,
设置好多长时间产生一次信号,然后与槽函数进行连接。
这里就与show_cameradata槽函数连接,调用上面创建好的摄像机类的读取画面的方法,并转成QT数据格式QImage,并在QLabel中显示出来。
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow): # 这里其实就是主窗口继承QtWidgets中的QMainWindow,还有就是QT生成的主窗口
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.open_photo)
def open_photo(self):
# 实例化一个摄像头
self.cameravideo = camera()
#创建定时器
self.timeshow = QTimer()
self.timeshow.start(10)
self.timeshow.timeout.connect(self.show_cameradata)
def show_cameradata(self):
pic = self.cameravideo.camera_to_pic()
self.label.setPixmap(QPixmap(pic))
2.2保存QT显示的当前帧摄像头画面
这里遇到的问题就是在确认采集画面时,直接关闭摄像头发生了错误,又或者是保存了当前帧后,当前帧不能够在QLabel中显示,又继续捕获新的画面:
原因
就在于定时器没有关闭,不断地在发送信号,关闭定时器,再关闭摄像头,就可以捕获当前帧画面并显示在Qlabel中了。
cv2.imwrite
方法保存画面到本地
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow): # 这里其实就是主窗口继承QtWidgets中的QMainWindow,还有就是QT生成的主窗口
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
self.pushButton_2.clicked.connect(self.save_img)
def save_img(self):
pic_data = self.cameravideo.read_camera()
image_height, image_width, image_depth = pic_data.shape
QIm = cv2.cvtColor(pic_data, cv2.COLOR_BGR2RGB)
QIm = QImage(QIm.data, image_width, image_height, # 创建QImage格式的图像,并读入图像信息
image_width * image_depth,
QImage.Format_RGB888)
self.label.setScaledContents(True) # 将图片在QT界面中显示完全
self.label.setPixmap(QPixmap.fromImage(QIm))
# 关闭定时器
self.timeshow.stop()
# 关闭摄像头
self.cameravideo.close_camera()
self.name = self.lineEdit.text() #.text()方法获得lineEdit组件的输入内容
os_path = 'D:\\QT\\' + str(self.name)
os.mkdir(os_path) # 根据用户名字创建好对应名字的文件夹后,接下来就是将对应名字的文
# 图片保存下来
img_path = os_path + '\\' + str(self.name) + '.jpg'
print(img_path)
cv2.imwrite(str(img_path), pic_data)
保存成功!