QtDesigner & pyqt5 基本使用


控件基本用法

button

单击普通按钮

button能够说是Qt中与用户交互最基本的控件,最简单的就是单击:python

#初始化一个button控件
self.button_inputData = QtWidgets.QPushButton(self.widget)
#设置按钮上文本字体
font = QtGui.QFont()
font.setPointSize(20)
font.setBold(False)
font.setWeight(50)
self.button_inputData.setFont(font)
#设置控件名
self.button_inputData.setObjectName("button_inputData")
#设置按钮上显示的文本
self.button_inputData.setText('这是button显示的内容')
#设置信号-槽的链接,当用户点击该按钮后调用槽函数,参数为函数名
self.button_inputData.clicked.connect(self.button_inputData_clicked_Event)

保持状态的按钮

QToolButton类的按钮是专门为设计工具栏按钮提供的类,能够设置成单击第一次时按钮按下,触发clicked信号,并保持按下状态,直到用户再次点击此按钮,触发clicked信号,并弹起按钮,在程序运行期间任什么时候候均可检测按钮的“按下/弹起”状态。git

设置setCheckable(True)和setAutoExclusive(True)后按钮可保持按下状态,且状态可查询:
self.button.setCheckable(True)
self.button.setAutoExclusive(True)
查询按钮是按下仍是弹起的方法是:
self.button_openCamera.isChecked()
按钮按下返回值是True,按钮弹起返回值是False。github

应用代码以下:web

#QToolButton的初始化设置
self.button_openCamera = QtWidgets.QToolButton(win_recogFaceInVideo)
self.button_openCamera.setGeometry(QtCore.QRect(695, 15, 114, 32))
font = QtGui.QFont()
font.setPointSize(13)
self.button_openCamera.setFont(font)
self.button_openCamera.setCheckable(True)
self.button_openCamera.setAutoExclusive(True)
self.button_openCamera.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.button_openCamera.setObjectName("button_openCamera")
#设置setCheckable(True)和setAutoExclusive(True)后按钮可保持按下状态,且状态可查询
self.button_openCamera.setCheckable(True)
self.button_openCamera.setAutoExclusive(True)
#设置单击信号的槽函数
self.button_openCamera.clicked.connect(self.recog_in_camera)
#clicked槽函数中能够获取按钮“按下/弹起”的状态
def recog_in_camera(self):
    #若是按钮是按下状态,则执行下面的操做
    if  self.button_openCamera.isChecked():
        #更改此按钮button_openCamera的文本信息
        self.button_openCamera.setText('关闭摄像头')
        #设置另外一个按钮button_openVideoFile不可操做
        self.button_openVideoFile.setEnabled(False)
    else:
        #若按钮是弹起状态,则更改此按钮的文本信息
        self.button_openCamera.setText('打开摄像头')

label

label显示文字

label显示文字是空间最基本的用法了,以下:app

#初始化一个label控件,参数是父类,也就是承载这个控件的窗口win_recogFaceInVideo
self.label = QtWidgets.QLabel(win_recogFaceInVideo)
#设置控件大小和位置:宽20,高65,左上角坐标(781,406)
self.label.setGeometry(QtCore.QRect(20, 65, 781, 406))
#设置文本字体信息
font = QtGui.QFont()
font.setPointSize(30)
font.setBold(False)
font.setWeight(50)
font.setKerning(True)
self.label.setFont(font)
self.label.setTextFormat(QtCore.Qt.RichText)
#缩放对齐:不缩放、居中对齐
self.label.setScaledContents(False)
self.label.setAlignment(QtCore.Qt.AlignCenter)
#控件名
self.label.setObjectName("label")
#文本内容
self.label.setText('这是label显示的内容')

label显示图片

先给出个示例,实如今label控件中按原比例居中显示图片文件。
代码以下:ide

def show_img_in_lable_center( label, fname):
    #label表示要用来显示图片的那个标签~
    #fname表示事先获取到的要打开的图片文件名(含路径),可用QtWidgets.QFileDialog.getOpenFileName()获取哈~
    pix_map = QPixmap(fname)
    img_w = pix_map.width()
    img_h = pix_map.height()
    lab_w = label.width()
    lab_h = label.height()
    if (img_w > lab_w) | (img_h > lab_h):
        #若图片宽高大于label宽高,则在label居中显示按图片原始比例缩放后的图片
        w_rate = float(img_w) / float(lab_w)
        h_rate = float(img_h) / float(lab_h)
        if w_rate >= h_rate:
            w = lab_w
            h = int(img_h / w_rate)
        else:
            w = int(img_w / h_rate)
            h = lab_h
    else:
        #若图片宽高都小于label宽高,则按图片原始大小显示
        w = img_w
        h = img_h
    label.setPixmap(pix_map.scaled(w, h))

label显示视频

label显示视频的问题实际就是label定时显示图片,只须要引入一个定时和加入截取视频画面的过程。
网上找到的C++的代码:svg

VideoCapture capture;//声明视频读入类
       capture.open(0);//从摄像头读入视频 0表示从摄像头读入
 
       if (!capture.isOpened())//先判断是否打开摄像头
       {
           cout<<"can not open";
           cin.get();
           return -1;
       }
       namedWindow(name);
       while (1) {
           Mat cap;//定义一个Mat变量,用于存储每一帧的图像
           capture>>cap;//读取当前帧
           if (!cap.empty())//判断当前帧是否捕捉成功 **这步很重要
               imshow(name, cap);//若当前帧捕捉成功,显示
           else
               cout<<"can not ";
           waitKey(30);//延时30毫秒
       }
 
       return 0;

本身写的定时处理视频帧而后显示在label中的代码比较复杂,思路是同样的,详情参考: win_recogFaceInVideo.py
须要注意:cv2处理图像数据的格式是bgr格式,所以必须注意格式转换。
主要代码以下:函数

# -*- coding: utf-8 -*-
# 识别视频中人脸
import face_recognition
import cv2
from ui_win_recogFaceInVideo import Ui_win_recogFaceInVideo
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtCore import QTimer
import sys
import myLib, face_recog
from face_recog import *

class Win_RecogFaceInVideo(QWidget, Ui_win_recogFaceInVideo):
    def __init__(self, parent=None ):
        super(Win_RecogFaceInVideo, self).__init__(parent)
        self.setupUi(self)
        ...
        #创建信号槽链接,点击button_openCamera按钮,启动摄像头,画面显示在label中
        self.button_openCamera.clicked.connect(self.recog_in_camera)
        #创建信号槽链接,点击button_openVideoFile按钮,读取视频文件显示在label中
        self.button_openVideoFile.clicked.connect(self.open_video_file)
    #以上均可以不关心===================================================
    #省略无关代码若干===================================================
    video_capture = []
    def open_video_file(self):
        ...
        fname, _ = myLib.loadFile(self,'video')#加载视频文件名,不重要
        ...
        ###==============这里才是重点==============###
        #初始化读取视频帧的Capture
        self.video_capture = cv2.VideoCapture(fname)
        #启动定时器,设置好超时的槽函数,超时时间10ms
        self.timer_camera = QTimer()
        self.timer_camera.start(10)
        self.timer_camera.timeout.connect(self.play1pic)  # 链接槽函数

    def recog_in_camera(self):
        if  self.button_openCamera.isChecked():#判断是否须要关闭摄像头
            #初始化抓取摄像头画面的Capture
            self.video_capture = cv2.VideoCapture(0)
            #启动定时器,设置好超时的槽函数,超时时间10ms
            self.timer_camera = QTimer()
            self.timer_camera.start(10)  # 1000ms == 1s
            self.timer_camera.timeout.connect(self.play1pic)  # 链接槽函数
        else:
            self.close_camera()
    #关闭摄像头的方法
    def close_camera(self):
        #释放摄像头抓取器
        self.video_capture.release()
        #中止定时器
        self.timer_camera.stop()
    #这是重点->>在label中显示一帧画面的方法play1pic()
    def play1pic(self):
        #抓取一帧画面:bgr格式的
        ret, frame = self.video_capture.read()
        if ret:#若是抓取成功,才继续画面处理和显示的操做
            #face_recog.recog_in()是根据一帧bgr数据进行人脸识别,并处理画面后,将数据转换成QImage格式后返回的过程,详细在下面
            Qimg = face_recog.recog_in(frame, update_features=False, frame_type='bgr', scale_rate=4.0)
            #将处理事后返回的QImage数据居中的显示在label中,
            #注意QPixmap.fromImage()方法将QImage数据又转成了QPixmap的格式
            #label中只能显示QPixmap格式的图像哈~
            myLib.show_img_in_lable_center(self.label,QPixmap.fromImage(Qimg))
        else:#若是抓取失败,说明视频文件读完了,或者摄像头故障?,中止抓取
            #释放抓取器
            self.video_capture.release()
            #中止定时器
            self.timer_camera.stop()
            
#补充两个跟label中显示视频有关的两个函数定义,部分操做与此话题有关,无关部分删去了:
def recog_in( frame ,frame_type = 'rgb' ):
    #预处理,准备好rgb和bgr格式的帧数据
    if frame_type == "rgb":
        rgb_frame= frame
        bgr_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)  #cv2处理图像须要bgr格式
    else:
        rgb_frame = cv2.cvtColor(frame2, cv2.COLOR_BGR2RGB)
        bgr_frame = frame
    ###此处省略图像处理代码若干=====emm..不少行
    #总之最终要将cv2抓到的数据或者处理过的数据显示出来,这些数据都是bgr格式的
    #因此要转成rgb格式的,cv2.cvtColor转出来的数据是np格式的RGB数据
    rgb_npImg = cv2.cvtColor(bgr_frame, cv2.COLOR_BGR2RGB)
    #而后经过QImage把np数据转成QImage格式的
    #参数分别是:np数据,图像宽,图像高,图像存储宽(单位byte,R/G/B各一字节,因此是宽乘三),最后一个是数据格式
    Qimg = QImage(rgb_npImg[:], rgb_npImg.shape[1], rgb_npImg.shape[0], rgb_npImg.shape[1] * 3, QImage.Format_RGB888)
    #返回转出来的QImage数据
    return Qimg
    
#在指定标签中居中显示指定图像文件
def show_img_in_lable_center( label, pix_map):
    #如下是计算要居中显示宽高比跟label不同的画面时,显示数据的实际宽高应该是多少
    #不重要
    img_w = pix_map.width()
    img_h = pix_map.height()
    lab_w = label.width()
    lab_h = label.height()
    if (img_w > lab_w) | (img_h > lab_h):
        w_rate = float(img_w) / float(lab_w)
        h_rate = float(img_h) / float(lab_h)
        if w_rate >= h_rate:
            w = lab_w
            h = int(img_h / w_rate)
        else:
            w = int(img_w / h_rate)
            h = lab_h
    else:
        w = img_w
        h = img_h
    #下面才是重点,用label.setPixmap()显示出来
    #在label中显示缩放后pix_map数据的画面
    label.setPixmap(pix_map.scaled(w, h))

其余基础操做

文件对话框

QtWidgets提供有相似“打开文件对话”框的类:QFileDialog,用来供用户选择文件或文件夹,获取文件/文件夹路径。工具

单个文件打开 QtWidgets.QFileDialog.getOpenFileName()
多个文件打开 QtWidgets.QFileDialog.getOpenFileNames()
文件夹选取 QtWidgets.QFileDialog.getExistingDirectory()
文件保存 QtWidgets.QFileDialog.getSaveFileName()
重点介绍QFileDialog.getOpenFileName()吧,后面几个的参数相似:字体

为了说明QFileDialog.getOpenFileName函数的用法,先把C++版的QFileDialog::getOpenFileName()的声明放这,便于理解参数类型,使用的时候自行对应到python的格式就好啦:

QString QFileDialog::getOpenFileName (
    QWidget * parent = 0,
    const QString & caption = QString(),
    const QString & dir = QString(),
    const QString & filter = QString(),
    QString * selectedFilter = 0,
    Options options = 0 )

参数
第一个参数parent:用于指定父组件。注意,不少Qt组件的构造函数都会有这么一个parent参数,并提供一个默认值0;这里要把调用资源管理器的Qt类传进去哈~若是是在类定义里调用的就传个self进去就行。
第二个参数caption:是对话框的标题;也就是将会显示在对话框上的标题,自行定义,string就行~
第三个参数dir:是对话框显示时默认打开的目录:.表明程序运行目录,/ 表明当前盘符的根目录(Windows,Linux下/就是根目录了),也能够是平台相关的,好比"C:\“等;例如我想打开程序运行目录下的Data文件夹做为默认打开路径,这里应该写成”./Data/",若想有一个默认选中的文件,则在目录后添加文件名便可:"./Data/teaser.graph"
第四个参数filter:是对话框的后缀名过滤器;好比咱们使用Image Files(*.jpg *.png)就让它只能显示后缀名是jpg或者png的文件。若是须要使用多个过滤器,使用;;分割,好比JPEG Files(*.jpg);;PNG Files(*.png)
第五个参数selectedFilter,是默认选择的过滤器;
第六个参数options,是对话框的一些参数设定,好比只显示文件夹等等,它的取值是enum QFileDialog::Option,每一个选项可使用|运算组合起来。

若是我要想选择多个文件就直接使用Qt提供的getOpenFileNames()函数咯,其返回值是一个QStringList。能够理解成一个只能存放QString的List。

实际使用中第五、6个参数我没用到,给个python中运用的实例:

from PyQt5 import QtCore, QtGui, QtWidgets
from ui_win_inputData import Ui_win_inputData 
#ui_win_inputData是用QtDesigner画的一个窗口界面文件生成的python文件,界面里有个名字叫button_choosePic的按钮
class Win_InputData(QWidget, Ui_win_inputData):
    def __init__(self, parent=None):
        super(Win_InputData, self).__init__(parent)
        self.setupUi(self)
        self.button_choosePic.clicked.connect(self.choosePic)
    def choosePic(self):
        fname, _ = QtWidgets.QFileDialog.getOpenFileName(self ,#第一个参数,父类
            '选择图片文件', #第二个参数,对话框的标题
            '/Users/tanyashi/Pictures', #对话框显示时默认打开的目录
            'Image files(*.jpg *.gif *.jpeg *.png)')    #对话框的后缀名过滤器
        #fname就是用户选择好的文件的文件名(含路径),后面就根据需求自行打开这个文件咯~
        #==============================================
        #再看看另外几个相似的方法使用:
        #从程序运行的路径开始,让用户选择一个文件夹路径
        directory1 = QFileDialog.getExistingDirectory(self,"选取文件夹","./")   
        print(directory1)
        #----------------------------------------------
        #从程序运行的路径开始,让用户选择一个全部类型或.txt格式的文件
        fileName1, filetype = QFileDialog.getOpenFileName(self,"选取文件","./","All Files (*);;Text Files (*.txt)")  #设置文件扩展名过滤,注意用双分号间隔
        print(fileName1,filetype)
        #----------------------------------------------
        #从"./"开始,容许用户选择多个文件
        files, ok1 = QFileDialog.getOpenFileNames(self,"多文件选择","./","All Files (*);;Text Files (*.txt)")
        print(files,ok1)
        #files是一个list,元素是文件名(含路径)的字符串
        #----------------------------------------------
        #从"./"开始,让用户选择一个用来保存文件的文件名(含路径)
        fileName2, ok2 = QFileDialog.getSaveFileName(self,"文件保存","./","All Files (*);;Text Files (*.txt)")

多个主界面之间切换

本例给出了三种窗口打开的模板。其中主界面打开主界面的方式比较实用,可理解后做为通用模板。

  • 本例中包含的三种窗口的打开方式:
    • 主界面打开 新的主界面
    • 主界面打开 对话框
    • 主界面打开 提示框

本例来自pyqt5 主界面打开新主界面的实现模板,感谢分享!

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
################################################
#######建立主窗口
################################################
class FirstMainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle('主界面')

        ###### 建立界面 ######
        self.centralwidget = QWidget()
        self.setCentralWidget(self.centralwidget)
        self.Layout = QVBoxLayout(self.centralwidget)

        # 设置顶部三个按钮
        self.topwidget = QWidget()
        self.Layout.addWidget(self.topwidget)
        self.buttonLayout = QHBoxLayout(self.topwidget)

        self.pushButton1 = QPushButton()
        self.pushButton1.setText("打开主界面")
        self.buttonLayout.addWidget(self.pushButton1)

        self.pushButton2 = QPushButton()
        self.pushButton2.setText("打开对话框")
        self.buttonLayout.addWidget(self.pushButton2)

        self.pushButton3 = QPushButton()
        self.pushButton3.setText("打开提示框")
        self.buttonLayout.addWidget(self.pushButton3)



        # 设置中间文本
        self.label = QLabel()
        self.label.setText("第一个主界面")
        self.label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setFont(QFont("Roman times", 50, QFont.Bold))
        self.Layout.addWidget(self.label)

        # 设置状态栏
        self.statusBar().showMessage("当前用户:一心狮")

        # 窗口最大化
        self.showMaximized()

        ###### 三个按钮事件 ######
        self.pushButton1.clicked.connect(self.on_pushButton1_clicked)
        self.pushButton2.clicked.connect(self.on_pushButton2_clicked)
        self.pushButton3.clicked.connect(self.on_pushButton3_clicked)




    # 按钮一:打开主界面
    windowList = []
    def on_pushButton1_clicked(self):
        the_window =SecondWindow()
        self.windowList.append(the_window)   ##注:没有这句,是不打开另外一个主界面的!
        self.close()
        the_window.show()


    # 按钮二:打开对话框
    def on_pushButton2_clicked(self):
        the_dialog = TestdemoDialog()
        if the_dialog.exec_() == QDialog.Accepted:
            pass



    # 按钮三:打开提示框
    def on_pushButton3_clicked(self):
        QMessageBox.information(self, "提示", "这是information框!")
        #QMessageBox.question(self, "提示", "这是question框!")
        #QMessageBox.warning(self, "提示", "这是warning框!")
        #QMessageBox.about(self, "提示", "这是about框!")





################################################
#######第二个主界面
################################################
class SecondWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle('第二主界面')

        # 设置中间文本
        self.label = QLabel()
        self.label.setText("第二个主界面")
        self.label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setFont(QFont("Roman times", 50, QFont.Bold))
        self.setCentralWidget(self.label)

        # 设置状态栏
        self.statusBar().showMessage("当前用户:一心狮")

        # 窗口最大化
        self.showMaximized()



    ###### 重写关闭事件,回到第一界面
    windowList = []
    def closeEvent(self, event):
        the_window = FirstMainWindow()
        self.windowList.append(the_window)  ##注:没有这句,是不打开另外一个主界面的!
        the_window.show()
        event.accept()




################################################
#######对话框
################################################
class TestdemoDialog(QDialog):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle('对话框')

        ### 设置对话框类型
        self.setWindowFlags(Qt.Tool)





################################################
#######程序入口
################################################
if __name__ == "__main__":
    app = QApplication(sys.argv)
    the_mainwindow = FirstMainWindow()
    the_mainwindow.show()
    sys.exit(app.exec_())