第四篇 -- 信號與槽的使用


學習書籍《Python Qt GUI與數據可視化編程》

一、信號與槽功能概述

信號(Signal):就是在特定情況下被發射(emit)的一種通告,例如一個PushButton按鈕最常見的信號就是鼠標單擊時發射的clicked()信號,一個ComboBox最常見的信號是選擇的項變化時發射的CurrentIndexChanged()信號。GUI程序設計的主要內容就是對界面上各組件發射的特定信號進行響應,只需要知道什么情況下發射了哪些信號,然后合理地去響應和處理這些信號就可以了。

槽(Slot):就是對信號響應的函數。槽實質上是一個函數,它可以被直接調用。槽函數與一般的函數不同的是:槽函數可以與一個信號關聯,當信號被發射時,關聯的槽函數會被自動執行。Qt的類一般都有一些內建(build-in)的槽函數,例如QWidget有一個槽函數close(),其功能是關閉窗口。如果將一個PushButton按鈕的clicked()信號與窗體的close()槽函數關聯,那么點擊按鈕時就會關閉窗口。

 

二、組件的信號與內建槽函數的關聯

1. 先畫一個圖

屬性設置表格如下:

對象名 類名稱 屬性設置 功能
Dialog QDialog windowTitle="Demo2-3信號與槽" 窗體的類名稱是Dialog,objectName不要修改
textEdit QPlainTextEdit

Text="PyQt5 編程指南\nPython 和 Qt."

Font.PointSize=20

Font.bold=True

用於顯示文字,可編輯
chkBoxUnder QCheckBox Text="Underline" 設置字體的下划線特定
chkBoxItalix QCheckBox Text="Italic" 設置字體的斜體特性
chkBoxBold QCheckBox Text="Bold" 設置字體的粗體特性
radioBlack QRadioButton Text="Black" 設置字體顏色為黑色
radioRed QRadioButton Text="Red" 設置字體顏色為紅色
radioBlue QRadioButton Text="Blue" 設置字體顏色為藍色
btnClear QPushButton Text="清空" 清空文本框內容
btnOK QPushButton Text="確定" 返回確定,並關閉窗口
btnClose QPushButton Text="退出" 退出程序

 

2. 界面組件布局管理

 

布局組件 功能
Vertival Layout 垂直布局,組件自動在垂直方向上分布
Horizontal Layout 水平布局,組件自動在水平方向上分布
Grid Layout 網格狀布局,網格狀布局大小改變時,每個網格的大小都改變
Form Layout 窗體布局,與網格布局類似。但是只有最右側的一列網格會改變大小
Horizontal Spacer 一個用於水平分隔的空格
Vertical Spacer 一個用於垂直分隔的空格

使用:先拖一個布局組件到窗體上,例如窗體下方的3個按鈕的布局,先放一個Horizontal Layout到窗體上,布局組件會以紅色矩形框顯示,在向布局組件里拖放3個PushButton和兩個Horizontal Spacer,就可以得到3個按鈕的水平布局。每個布局還有layoutTopMargin、layoutBottomMargin、layoutLeftMargin、layoutRightMargin這四個屬性用於調整布局邊框與內部組件之間的上、下、左、右的邊距大小。

在設計窗體的上方有一個工具欄,用於使界面進入不同的設計狀態,以及進行布局設計,工具欄商各按鈕的功能如下:

按鈕及快捷鍵 功能
Edit Widget(F3) 界面設計進入編輯狀態,也就是正常的設計狀態
Edit Signals/Slots(F4) 進入信號與槽的可視化設計狀態
Edit Buddies 進入伙伴關系編輯狀態,可以設置一個Lable與一個組件成為伙伴關系
Edit Tab Order 進入Tab順序編輯狀態,Tab順序是指在鍵盤上按Tab鍵時,輸入焦點在界面各組件之間跳動的順序

3. 組件的信號與內建槽函數的關聯

Qt的界面組件都是從QWidget繼承而來的,都支持信號與槽的功能。每個類都有一些內建的信號和槽函數。例如QPushButton按鈕類常用的信號是clicked(),在按鈕被單擊時發射此信號。QDialog是對話框類,它有以下3個內建的槽函數。

  • accept():功能是關閉對話框,表示肯定的選擇,例如“確定”。
  • reject():功能是關閉對話框,表示否定的選擇,例如“取消”。
  • close():功能是關閉對話框

這3個槽函數都可以關閉對話框,但是表示對話框的返回值不同,我們希望將“確定”按鈕與對話框的accept()槽函數關聯,將“退出”按鈕與對話框的close()槽函數關聯。

可以在Qt Designer里使用可視化的方式實現信號與槽函數的關聯。在Qt Designer里單擊上方工具欄里的“Edit Signals/Slots”按鈕,窗體進入信號與槽函數編輯狀態。

鼠標點選“確定”按鈕,在按住鼠標左鍵拖動到窗體的空白區域后釋放左鍵,這時出現關聯設置對話框

此對話框里左邊的列表框里顯示了btnOK的信號(上圖顯示的是btnClear,因為btnOK之前自己已經關聯過,就不重復關聯了),選擇clicked(),右邊的列表框里顯示了Dialog的槽函數,選擇accept(),然后單擊“OK”按鈕。同樣的方法可以將btnClose的clicked()信號與Dialog的close()槽函數關聯,值得注意的是,如果沒有看到close()槽函數,可以將下方的“Show signals and slots inherited from QWidget”打勾。

設置好這兩個按鈕的信號與槽關聯后,在窗體右下方的Signals Slots編輯器里就顯示了這兩個關聯。實際上可以直接在Signals Slots編輯器進行某個組件的內建信號與其他組件的內建槽函數關聯。

4. 將ui文件轉換為py

Dialog.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'Dialog.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 300)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        self.groupBox = QtWidgets.QGroupBox(Dialog)
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.chkBoxUnder = QtWidgets.QCheckBox(self.groupBox)
        self.chkBoxUnder.setObjectName("chkBoxUnder")
        self.horizontalLayout_3.addWidget(self.chkBoxUnder)
        self.chkBoxItalic = QtWidgets.QCheckBox(self.groupBox)
        self.chkBoxItalic.setObjectName("chkBoxItalic")
        self.horizontalLayout_3.addWidget(self.chkBoxItalic)
        self.chkBoxBold = QtWidgets.QCheckBox(self.groupBox)
        self.chkBoxBold.setObjectName("chkBoxBold")
        self.horizontalLayout_3.addWidget(self.chkBoxBold)
        self.verticalLayout.addWidget(self.groupBox)
        self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
        self.groupBox_2.setTitle("")
        self.groupBox_2.setObjectName("groupBox_2")
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.groupBox_2)
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.radioBlack = QtWidgets.QRadioButton(self.groupBox_2)
        self.radioBlack.setObjectName("radioBlack")
        self.horizontalLayout_4.addWidget(self.radioBlack)
        self.radioRed = QtWidgets.QRadioButton(self.groupBox_2)
        self.radioRed.setObjectName("radioRed")
        self.horizontalLayout_4.addWidget(self.radioRed)
        self.radioBlue = QtWidgets.QRadioButton(self.groupBox_2)
        self.radioBlue.setObjectName("radioBlue")
        self.horizontalLayout_4.addWidget(self.radioBlue)
        self.verticalLayout.addWidget(self.groupBox_2)
        self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.plainTextEdit.setFont(font)
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.verticalLayout.addWidget(self.plainTextEdit)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem)
        self.btnClear = QtWidgets.QPushButton(Dialog)
        self.btnClear.setObjectName("btnClear")
        self.horizontalLayout_2.addWidget(self.btnClear)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.btnOK = QtWidgets.QPushButton(Dialog)
        self.btnOK.setObjectName("btnOK")
        self.horizontalLayout_2.addWidget(self.btnOK)
        self.btnClose = QtWidgets.QPushButton(Dialog)
        self.btnClose.setObjectName("btnClose")
        self.horizontalLayout_2.addWidget(self.btnClose)
        self.verticalLayout.addLayout(self.horizontalLayout_2)

        self.retranslateUi(Dialog)
        self.btnOK.clicked.connect(Dialog.accept)
        self.btnClose.clicked.connect(Dialog.close)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Demo2-3信號與槽"))
        self.chkBoxUnder.setText(_translate("Dialog", "Underline"))
        self.chkBoxItalic.setText(_translate("Dialog", "Italic"))
        self.chkBoxBold.setText(_translate("Dialog", "Bold"))
        self.radioBlack.setText(_translate("Dialog", "Black"))
        self.radioRed.setText(_translate("Dialog", "Red"))
        self.radioBlue.setText(_translate("Dialog", "Blue"))
        self.plainTextEdit.setPlainText(_translate("Dialog", "PyQt5 編程指南\n"
"Python 和 Qt."))
        self.btnClear.setText(_translate("Dialog", "清空"))
        self.btnOK.setText(_translate("Dialog", "確定"))
        self.btnClose.setText(_translate("Dialog", "退出"))
View Code

 

5. 窗體業務邏輯類文件myDialog.py

# # 與UI窗體類對應的業務邏輯類
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from Dialog import Ui_Dialog


class QmyDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)  # 調用父類構造函數,創建QWidget窗體
        self.ui = Ui_Dialog()  # 創建UI對象
        self.ui.setupUi(self)  # 構造UI


if __name__ == "__main__":
    app = QApplication(sys.argv)  # 創建app,用QApplication類
    form = QmyDialog()
    form.show()
    sys.exit(app.exec_())
View Code

 

6. 應用程序主程序文件appMain.py

# # GUI應用程序主程序
import sys
from PyQt5.QtWidgets import QApplication
from myDialog import QmyDialog

app = QApplication(sys.argv)  # 創建GUI應用程序
mainform = QmyDialog()  # 創建主窗體
mainform.show()  # 顯示主窗體
sys.exit(app.exec_())
View Code

 

 

notes: 程序myDialog.py可以當做主程序直接運行,但是建議單獨編寫一個主程序文件appMain.py,appMain.py的功能是創建應用程序和主窗體,然后顯示主窗體,並開始運行應用程序。它將myDialog.py文件的測試運行部分單獨拿出來作為一個文件。當一個應用程序有多個窗體,並且窗體之間有數據傳遞時,appMain.py負責創建應用程序的主窗體並運行起來,這樣使整個應用程序的結構更清晰。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM