真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

PyQt5快速入門(二)PyQt5信號(hào)槽機(jī)制

PyQt5快速入門(二)PyQt5信號(hào)槽機(jī)制

一、信號(hào)槽機(jī)制簡(jiǎn)介

1、信號(hào)槽簡(jiǎn)介

信號(hào)槽是Qt的核心機(jī)制,也是PyQt編程中對(duì)象進(jìn)行通信的機(jī)制。在Qt中,QObject對(duì)象和PyQt中所有繼承自QWidget的控件都支持信號(hào)槽機(jī)制。當(dāng)信號(hào)發(fā)射時(shí),連接的槽函數(shù)會(huì)自動(dòng)執(zhí)行。在PyQt5中,信號(hào)與槽函數(shù)通過(guò)object.signal.connect()方法進(jìn)行連接。
信號(hào)槽特點(diǎn)如下:
(1)一個(gè)信號(hào)可以連接多個(gè)槽
(2)一個(gè)信號(hào)可以連接另一個(gè)信號(hào)
(3)信號(hào)參數(shù)可以是任意Python類型
(4)一個(gè)槽可以監(jiān)聽多個(gè)信號(hào)
(5)信號(hào)與槽的連接方式可以是同步連接,也可以是異步連接。
(6)信號(hào)與槽的連接可以跨線程
(7)信號(hào)可以斷開
在編寫一個(gè)類時(shí),要首先定義的類的信號(hào)與槽,在類中信號(hào)與槽進(jìn)行連接,實(shí)現(xiàn)對(duì)象之間的數(shù)據(jù)傳輸。當(dāng)事件或狀態(tài)發(fā)生變化時(shí),會(huì)發(fā)出信號(hào),進(jìn)而觸發(fā)執(zhí)行事件或信號(hào)關(guān)聯(lián)的槽函數(shù)。信號(hào)槽機(jī)制示意如下:
PyQt5快速入門(二)PyQt5信號(hào)槽機(jī)制

創(chuàng)新互聯(lián)主營(yíng)文圣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,app軟件開發(fā),文圣h5微信小程序開發(fā)搭建,文圣網(wǎng)站營(yíng)銷推廣歡迎文圣等地區(qū)企業(yè)咨詢

2、定義信號(hào)

PyQt的內(nèi)置信號(hào)是自動(dòng)定義的,使用PyQt5.QtCore.pyqtSignal函數(shù)可以為QObject對(duì)象創(chuàng)建一個(gè)信號(hào),使用pyqtSignal函數(shù)可以把信號(hào)定義為類的屬性。

class pyqtSignal:
    def __init__(self, *types, name: str = ...) -> None: ...

types參數(shù)表示定義信號(hào)時(shí)參數(shù)的類型,name參數(shù)表示信號(hào)的名稱,默認(rèn)使用類的屬性名稱。
使用pyqtSignal函數(shù)創(chuàng)建一個(gè)或多個(gè)重載的未綁定的信號(hào)作為類的屬性,信號(hào)只能在QObject的子類中定義。信號(hào)必須在類創(chuàng)建時(shí)定義,不能在類創(chuàng)建后作為類的屬性動(dòng)態(tài)添加進(jìn)來(lái)。使用pyqtSignal函數(shù)定義信號(hào)時(shí),信號(hào)可以傳遞多各參數(shù),并指定信號(hào)傳遞參數(shù)的類型,參數(shù)類型是標(biāo)準(zhǔn)的Python數(shù)據(jù)類型,包括字符串、日期、布爾類型、數(shù)字、列表、字典、元組。

from PyQt5.QtCore import pyqtSignal, QObject

class StandardItem(QObject):
    # 定義信號(hào),信號(hào)有兩個(gè)參數(shù),兩個(gè)參數(shù)的類型分別為str,str,信號(hào)名稱為dataChanged
    data_changed = pyqtSignal(str, str, name="dataChanged")

    # 更新信息,發(fā)送信號(hào)
    def update(self):
        self.dataChanged.emit("old status", "new status")

3、操作信號(hào)

使用connect函數(shù)可以將信號(hào)綁定到槽函數(shù)上,使用disconnect函數(shù)可以解除信號(hào)與槽函數(shù)的綁定,使用emit函數(shù)可以發(fā)射信號(hào)。
QObject.signal.connect(self, slot, type=None, no_receiver_check=False)
建立信號(hào)到槽函數(shù)的連接,type為連接類型。
QObject.signal.disconnect(self, slot=None)
斷開信號(hào)到槽的連接
emit(self, *args)
發(fā)送信號(hào),args為可變參數(shù)。

import sys
from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication

class StandardItem(QObject):
    # 定義信號(hào),信號(hào)有兩個(gè)參數(shù),兩個(gè)參數(shù)的類型分別為str,str,信號(hào)名稱為dataChanged
    data_changed = pyqtSignal(str, str, name="dataChanged")

    # 更新信息,發(fā)送信號(hào)
    def update(self):
        self.dataChanged.emit("old status", "new status")

    # 定義槽函數(shù)
    def onDataChanged(self, old, new):
        print(old)
        print(new)

if __name__ == "__main__":
    app = QCoreApplication(sys.argv)

    item = StandardItem()
    item.dataChanged.connect(item.onDataChanged)
    item.update()

    sys.exit(app.exec_())

# OUTPUT:
# old status
# new status

二、信號(hào)與槽應(yīng)用

1、內(nèi)置信號(hào)與槽函數(shù)

內(nèi)置信號(hào)是QObject對(duì)象自動(dòng)定義的信號(hào),內(nèi)置槽函數(shù)是QObject對(duì)象自動(dòng)定義的槽函數(shù),可以通過(guò)QObject.signal.connect函數(shù)將QObject對(duì)象的內(nèi)置信號(hào)連接到QObject對(duì)象的槽函數(shù)。

2、內(nèi)置信號(hào)與自定義槽函數(shù)

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton

class MainWindow(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("MainWindow Demo")
        self.resize(800, 600)

        button = QPushButton("close", self)
        # 連接內(nèi)置信號(hào)與自定義槽
        button.clicked.connect(self.onClose)

    # 自定義槽函數(shù)
    def onClose(self):
        self.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

點(diǎn)擊按鈕時(shí)觸發(fā)按鈕內(nèi)置的clicked信號(hào),執(zhí)行綁定的自定義槽函數(shù)onClose。

3、自定義信號(hào)與內(nèi)置槽函數(shù)

import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton

class MainWindow(QWidget):
    closeSignal = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("MainWindow Demo")
        self.resize(800, 600)

        button = QPushButton("close", self)
        # 連接內(nèi)置信號(hào)與自定義槽
        button.clicked.connect(self.onClose)
        # 連接自定義信號(hào)closeSignal與內(nèi)置槽函數(shù)close
        self.closeSignal.connect(self.close)

    # 自定義槽函數(shù)
    def onClose(self):
        # 發(fā)送自定義信號(hào)
        self.closeSignal.emit()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

通過(guò)連接內(nèi)置信號(hào)clicked到自定義槽函數(shù)onClose,在自定義槽函數(shù)onClose內(nèi)發(fā)送自定義信號(hào)closeSignal,并將自定義信號(hào)closeSignal與內(nèi)置槽函數(shù)close連接。

4、自定義信號(hào)與自定義槽函數(shù)

import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton

class MainWindow(QWidget):
    closeSignal = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("MainWindow Demo")
        self.resize(800, 600)

        button = QPushButton("close", self)
        # 連接內(nèi)置信號(hào)與自定義槽
        button.clicked.connect(self.onClicked)
        # 連接自定義信號(hào)closeSignal與內(nèi)置槽函數(shù)close
        self.closeSignal.connect(self.onClose)

    # 自定義槽函數(shù)
    def onClicked(self):
        # 發(fā)送自定義信號(hào)
        self.closeSignal.emit()

    # 自定義槽函數(shù)
    def onClose(self):
        self.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

三、信號(hào)槽應(yīng)用進(jìn)階

1、自定義信號(hào)槽

通常通過(guò)類變量定義信號(hào)對(duì)象,在__init__函數(shù)前定義自定義信號(hào)。

class TestObject(QObject):
    # 定義無(wú)參的信號(hào)
    noParametersSignal = pyqtSignal()
    # 定義一個(gè)參數(shù)的信號(hào),參數(shù)類型為int
    oneParameterSignal = pyqtSignal(int)
    # 定義一個(gè)參數(shù)的重載版本的信號(hào),參數(shù)類型可以為int或str
    oneParameterOverloadSignal = pyqtSignal([int], [str])
    # 定義兩個(gè)參數(shù)的重載版本的信號(hào),參數(shù)類型為int,str或int,int
    twoParametersOverloadSignal = pyqtSignal([int, str], [int, int])
    # 定義一個(gè)list參數(shù)類型的信號(hào)
    oneParameterSignalList = pyqtSignal(list)
    # 定義一個(gè)dict參數(shù)類型的信號(hào)
    oneParameterSignalDict = pyqtSignal(dict)

類的槽函數(shù)定義與類的普通方法定義相同。

class TestObject(QObject):
    # 定義無(wú)參的信號(hào)
    noParametersSignal = pyqtSignal()
    # 定義一個(gè)參數(shù)的信號(hào),參數(shù)類型為int
    oneParameterSignal = pyqtSignal(int)
    # 定義一個(gè)參數(shù)的重載版本的信號(hào),參數(shù)類型可以為int或str
    oneParameterOverloadSignal = pyqtSignal([int], [str])
    # 定義兩個(gè)參數(shù)的重載版本的信號(hào),參數(shù)類型為int,str或int,int
    twoParametersOverloadSignal = pyqtSignal([int, str], [int, int])

    # 定義無(wú)參的槽函數(shù)
    def onNoParameterSlot(self):
        pass

    # 定義一個(gè)參數(shù)的槽函數(shù),參數(shù)為整型nIndex
    def onOneParameterSlot(self, nIndex):
        pass

    # 定義兩個(gè)參數(shù)的槽函數(shù),參數(shù)為整型nIndex,字符串型sStatus
    def onTwoParametersSlot(self, nIndex, sStatus):
        pass

通過(guò)connect方法連接信號(hào)與槽函數(shù),信號(hào)與槽函數(shù)可以屬于同一個(gè)QObject對(duì)象,也可以是不同的QObject對(duì)象。

test = TestObject()
test.noParametersSignal.connect(test.onNoParameterSlot)
test.oneParameterSignal.connect(test.onOneParameterSlot)
test.twoParametersOverloadSignal.connect(test.onTwoParametersSlot)

信號(hào)的發(fā)送通過(guò)emit方法進(jìn)行發(fā)送。

def update(self):
    self.noParametersSignal.emit()
    self.oneParameterSignal.emit(100)
    self.oneParameterOverloadSignal("Hello, PyQt5")
    self.twoParametersOverloadSignal(100, "Hello, PyQt5")

2、信號(hào)槽傳遞自定義參數(shù)

Qt中信號(hào)發(fā)出的參數(shù)個(gè)數(shù)必須大于等于槽函數(shù)的參數(shù)個(gè)數(shù),PyQt使用自定義參數(shù)傳遞解決槽函數(shù)參數(shù)比信號(hào)參數(shù)多的問(wèn)題。使用Lambda表達(dá)式或functools的partial函數(shù)可以傳遞自定義參數(shù)給槽函數(shù),自定義參數(shù)類型可以是Python任意類型。

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout
from functools import partial

class MainWindow(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        button1 = QPushButton("Button1", self)
        button2 = QPushButton("Button2", self)

        layout = QHBoxLayout()
        layout.addWidget(button1)
        layout.addWidget(button2)
        self.setLayout(layout)

        self.setWindowTitle("MainWindow Demo")
        self.resize(800, 600)

        # lambda
        button1.clicked.connect(lambda: self.onButtonClicked(1))
        button2.clicked.connect(lambda: self.onButtonClicked(2))
        # partial
        button1.clicked.connect(partial(self.onButtonClicked, 1))
        button2.clicked.connect(partial(self.onButtonClicked, 2))

    # 自定義槽函數(shù)
    def onButtonClicked(self, n):
       print("Button {0} is Clicked".format(n))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

3、信號(hào)槽與裝飾器

PyQt中可以通過(guò)Python裝飾器定義信號(hào)與槽函數(shù),使用方法如下:

@PyQt5.QtCore.pyqtSlot(bool)
def on_發(fā)送者對(duì)象名稱_發(fā)射信號(hào)名稱(self, parameter):
    pass

發(fā)送者對(duì)象名稱是使用setObjectName為QObject對(duì)象設(shè)置的對(duì)象名稱,通過(guò)信號(hào)名稱連接到槽函數(shù)的connectSlotsByName函數(shù)如下:
QtCore.QMetaObject.connectSlotsByName(self, QObject)
connectSlotsByName用于將QObject子孫對(duì)象的某些信號(hào)根據(jù)名稱連接到某些QObject對(duì)象的相應(yīng)槽函數(shù)。

import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout

class MainWindow(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        button1 = QPushButton("Button1", self)
        button1.setObjectName("Button1")
        button2 = QPushButton("Button2", self)
        button2.setObjectName("Button2")

        layout = QHBoxLayout()
        layout.addWidget(button1)
        layout.addWidget(button2)
        self.setLayout(layout)

        self.setWindowTitle("MainWindow Demo")
        self.resize(800, 600)

        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot()
    def on_Button1_clicked(self):
        print("Button1 is clicked")

    @QtCore.pyqtSlot()
    def on_Button2_clicked(self):
        print("Button2 is clicked")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

四、事件處理機(jī)制

1、事件機(jī)制與信號(hào)槽機(jī)制的區(qū)別

PyQt為事件處理提供了高級(jí)別的信號(hào)槽機(jī)制和低級(jí)別的事件處理機(jī)制,信號(hào)槽機(jī)制是事件處理機(jī)制的高級(jí)封裝。使用控件時(shí),不用考慮事件處理機(jī)制,只需要關(guān)心信號(hào)槽即可;對(duì)于自定義派生控件,必須考慮事件處理機(jī)制,根據(jù)控件的行為需求重新實(shí)現(xiàn)相應(yīng)的事件處理函數(shù)。

2、事件處理的方法

PyQt提供了5種事件處理和過(guò)濾方法,分別為:
(1)重新實(shí)現(xiàn)事件處理函數(shù)
常用的事件處理函數(shù)如paintEvent、mouseMoveEvent、mousePressEvent、mouseReleaseEvent等。
(2)重新實(shí)現(xiàn)QObject.event事件分發(fā)函數(shù)
在增加新的事件時(shí),需要重新實(shí)現(xiàn)QObject.event方法,并增加新事件的分發(fā)路由。
(3)安裝事件過(guò)濾器
如果對(duì)QObject對(duì)象調(diào)用installEventFilter方法,則為QObject對(duì)象安裝事件過(guò)濾器。QObject對(duì)象的所有事件都會(huì)先傳遞到事件過(guò)濾器eventFilter函數(shù),在事件過(guò)濾器eventFilter函數(shù)中可以丟棄或修改某些事件,對(duì)感興趣的事件使用自定義的事件處理機(jī)制,對(duì)其它事件使用默認(rèn)事件處理機(jī)制。事件過(guò)濾機(jī)制會(huì)對(duì)QObject的所有事件進(jìn)行過(guò)濾,因此如果要過(guò)濾的事件比較多則會(huì)影響程序性能。
(4)在QApplication安裝事件過(guò)濾器
在QApplication對(duì)象安裝事件過(guò)濾器將會(huì)對(duì)所有QObject對(duì)象的所有事件進(jìn)行過(guò)濾,并且會(huì)首先獲得事件,即將事件發(fā)送給其它任何一個(gè)事件過(guò)濾器前,都會(huì)首先發(fā)送給QApplication的事件過(guò)濾器。
(5)重新QApplication的notify方法
PyQt使用QApplication對(duì)象的notify方法進(jìn)行分發(fā)事件,要想在任何事件過(guò)濾器前捕獲事件唯一的方法就是重新實(shí)現(xiàn)QApplication的notify方法。

3、事件處理實(shí)例

QDialog對(duì)話框在ESC按鍵按下時(shí)會(huì)自動(dòng)退出,使用事件處理和過(guò)濾對(duì)按下ESC按鍵進(jìn)行處理。
(1)重新實(shí)現(xiàn)事件處理函數(shù)

import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import Qt

class Dialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

    # 重新實(shí)現(xiàn)keyPressEvent
    def keyPressEvent(self, event):
        if event.key() != Qt.Key_Escape:
            QDialog.keyPressEvent(self, event)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    dialog = Dialog()
    dialog.exec_()

    sys.exit(app.exec_())

(2)重新實(shí)現(xiàn)event函數(shù)

import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeyEvent

class Dialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

    # 重新實(shí)現(xiàn)keyPressEvent
    def event(self, event):
        if event.type() == QKeyEvent.KeyPress and event.key() == Qt.Key_Escape:
            return True
        else:
            return QDialog.event(self, event)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    dialog = Dialog()
    dialog.exec_()

    sys.exit(app.exec_())

(3)QObject安裝事件過(guò)濾器

import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeyEvent

class Dialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.installEventFilter(self)

    def eventFilter(self, watched, event):
        if event.type() == QKeyEvent.KeyPress and event.key() == Qt.Key_Escape:
            return True
        else:
            return QDialog.eventFilter(self, watched, event)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    dialog = Dialog()
    dialog.exec_()

    sys.exit(app.exec_())

(4)QApplication安裝事件過(guò)濾器

import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeyEvent

class Dialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

    def eventFilter(self, watched, event):
        if event.type() == QKeyEvent.KeyPress and event.key() == Qt.Key_Escape:
            return True
        else:
            return QDialog.eventFilter(self, watched, event)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    dialog = Dialog()
    app.installEventFilter(dialog)
    dialog.exec_()

    sys.exit(app.exec_())

網(wǎng)站欄目:PyQt5快速入門(二)PyQt5信號(hào)槽機(jī)制
本文來(lái)源:http://weahome.cn/article/jggccj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部