1. 程式人生 > >PyQt訊號與槽之多視窗資料傳遞(七)

PyQt訊號與槽之多視窗資料傳遞(七)

前言

在pyqt程式設計過程中,經常會遇到輸入或選擇多個引數的問題,把多個引數寫到一個視窗中,主視窗會顯得很臃腫,所以,一般是新增一個按鈕,呼叫對話方塊,在對話方塊中進行引數的選擇,關閉對話方塊將引數返回給主視窗
pyqt提供了一些標準的對話方塊類,用於輸入資料,修改資料,更改應用的設定等,常見的有QFileDialog,QInputDialog,QColorDialog, QFontDialog等,在不同的視窗之間傳引數有兩種常用的方式,一種在自定義對話方塊之間通過屬性傳參,另一種在視窗之間使用訊號與槽機制傳參,這裡主要介紹第一種

例項一:單一視窗的資料傳遞

對於具有單一視窗的程式來說,一個控制元件的變化會影響另一個控制元件的變化,這中變化利用訊號與槽的關係非常容易解決

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class WinForm(QWidget):
    def __init__(self):
        super(WinForm, self).__init__()
        self.initUI()
    def initUI( self ):
        #先建立水平滑塊和Lcd控制元件
        lcd=QLCDNumber(self)
        slider=QSlider(Qt.Horizontal,self)

        #垂直佈局,新增控制元件
vbox=QVBoxLayout() vbox.addWidget(lcd) vbox.addWidget(slider) #設定窗口布局 self.setLayout(vbox) #設定滑塊數值訊號改變連線Lcd的更新 slider.valueChanged.connect(lcd.display) #設定初始位置以及初始大小,設定標題 self.setGeometry(300,300,350,150) self.setWindowTitle('訊號與槽:連線滑塊LCd'
) if __name__ == '__main__': app=QApplication(sys.argv) form=WinForm() form.show() sys.exit(app.exec_())

執行效果如圖
這裡寫圖片描述

例項二:多視窗資料傳遞:呼叫屬性

新建對話方塊子視窗屬性,我這裡的名字為: jia_13多視窗資料傳遞之呼叫屬性


from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class DateDialog(QDialog):
    def __init__(self,parent=None):
        super(DateDialog, self).__init__(parent)
        self.setWindowTitle('DateDialog')

        #在佈局中新增控制元件
        layout=QVBoxLayout(self)
        self.datetime=QDateTimeEdit(self)
        self.datetime.setCalendarPopup(True)
        self.datetime.setDateTime(QDateTime.currentDateTime())
        layout.addWidget(self.datetime)

        buttons=QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel,Qt.Horizontal,self)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

    def dateTime( self ):
        return self.datetime.dateTime()

    @staticmethod
    def getDateTime(parent=None):
        dialog=DateDialog(parent)
        result=dialog.exec_()
        date=dialog.dateTime()
        return (date.date(),date.time(),result==QDialog.Accepted)

再新建一個主視窗檔案,用來呼叫上一個子視窗

import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from jia_13多視窗資料傳遞之呼叫屬性 import DateDialog

class WinForm(QWidget):
    def __init__(self,parent=None):
        super(WinForm, self).__init__(parent)
        self.resize(400,90)
        self.setWindowTitle('對話方塊關閉時返回值給主視窗的例子')

        self.lineEdit=QLineEdit(self)
        self.button1=QPushButton('彈出對話方塊1')
        self.button1.clicked.connect(self.onButton1Clicked)

        self.button2=QPushButton('彈出對話方塊2')
        self.button2.clicked.connect(self.onButton2Clicked)

        gridLayout=QGridLayout(self)
        gridLayout.addWidget(self.lineEdit)
        gridLayout.addWidget(self.button1)
        gridLayout.addWidget(self.button2)

    def onButton1Clicked( self ):
        dialog=DateDialog(self)
        result=dialog.exec_()
        date=dialog.dateTime()
        self.lineEdit.setText(date.date().toString())
        print('\n日期對話方塊的返回值')
        print('date=%s'%str(date.date))
        print('time=%s'%str(date.time()))
        print('result=%s'%result)
    def onButton2Clicked( self ):
        date,time,result=DateDialog.getDateTime()
        self.lineEdit.setText(date.toString())
        print('\n 日期對話方塊的返回值')
        print('date=%s' %str(date))
        print('time=%s' %str(time))
        print('result=%s' %result)





if __name__ == '__main__':
    app=QApplication(sys.argv)
    form=WinForm()
    form.show()
    sys.exit(app.exec_())

執行程式,顯示如圖
這裡寫圖片描述

程式碼分析

在主視窗呼叫對話方塊有兩種方法,本例中,這兩種方法操作效果是一樣的,都需要點選彈出對話方塊按鈕,在對話方塊的時間日期控制元件中選擇日期,則會把選中的日期返回到主視窗的lineTeXt文字控制元件中

第一中方法:直接在主視窗程式中例項化該對話方塊,然後呼叫該對話方塊的函式,來獲取返回值,根據對話方塊的返回值單擊確認按鈕還是取消按鈕來進行下一步的操作,同理,對於上面的DateDialog,主視窗程式程式碼如下

 def onButton1Clicked( self ):
        dialog=DateDialog(self)
        result=dialog.exec_()
        date=dialog.dateTime()
        self.lineEdit.setText(date.date().toString())

第二種方法:在主視窗程式中呼叫子視窗的靜態函式,實際上這種方法與第一種方法是一樣的,只不過他利用靜態函式的特點,在子視窗的靜態函式中的建立例項化物件

 def onButton2Clicked( self ):
        date,time,result=DateDialog.getDateTime()
        self.lineEdit.setText(date.toString())

例項三:多視窗資料傳遞:訊號與槽

對於多視窗的資料傳遞,一般是通過子視窗發射訊號的,主視窗通過槽函式捕獲這個訊號,然後獲取訊號裡面的資料,子視窗發射的訊號有兩種:一種是發射內建pyqt訊號,一種是發射自定義的訊號
發射自定義的訊號,好處是它的引數可以自定義,可以為int list dict等各種型別與多個引數

新建一個子對話方塊檔案,這裡的名稱為:jia_14多視窗訊號傳遞之訊號與槽

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

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class DateDialog(QDialog):
    Signal_OneParameter = pyqtSignal(str)

    def __init__(self, parent=None):
        super(DateDialog, self).__init__(parent)
        self.setWindowTitle('子視窗:用來發射訊號')

        # 在佈局中新增部件
        layout = QVBoxLayout(self)

        self.label = QLabel(self)
        self.label.setText('前者發射內建訊號\n後者發射自定義訊號')

        self.datetime_inner = QDateTimeEdit(self)
        self.datetime_inner.setCalendarPopup(True)
        self.datetime_inner.setDateTime(QDateTime.currentDateTime())

        self.datetime_emit = QDateTimeEdit(self)
        self.datetime_emit.setCalendarPopup(True)
        self.datetime_emit.setDateTime(QDateTime.currentDateTime())

        layout.addWidget(self.label)
        layout.addWidget(self.datetime_inner)
        layout.addWidget(self.datetime_emit)

        # 使用兩個button(ok和cancel)分別連線accept()和reject()槽函式
        buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
            Qt.Horizontal, self)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

        self.datetime_emit.dateTimeChanged.connect(self.emit_signal)

    def emit_signal(self):
        date_str = self.datetime_emit.dateTime().toString()
        self.Signal_OneParameter.emit(date_str)

建立主視窗,呼叫對話方塊檔案


import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from jia_14多視窗訊號傳遞之訊號與槽 import DateDialog


class WinForm(QWidget):
    def __init__(self, parent=None):
        super(WinForm, self).__init__(parent)
        self.resize(400, 90)
        self.setWindowTitle('訊號與槽傳遞引數的示例')

        self.open_btn = QPushButton('獲取時間')
        self.lineEdit_inner = QLineEdit(self)
        self.lineEdit_emit = QLineEdit(self)
        self.open_btn.clicked.connect(self.openDialog)

        self.lineEdit_inner.setText('接收子視窗內建訊號的時間')
        self.lineEdit_emit.setText('接收子視窗自定義訊號的時間')

        grid = QGridLayout()
        grid.addWidget(self.lineEdit_inner)
        grid.addWidget(self.lineEdit_emit)

        grid.addWidget(self.open_btn)
        self.setLayout(grid)

    def openDialog(self):
        dialog = DateDialog(self)
        '''連線子視窗的內建訊號與主視窗的槽函式'''
        dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)
        '''連線子視窗的自定義訊號與主視窗的槽函式'''
        dialog.Signal_OneParameter.connect(self.deal_emit_slot)
        dialog.show()

    def deal_inner_slot(self, date):
        self.lineEdit_inner.setText(date.toString())


    def deal_emit_slot(self, dateStr):
        self.lineEdit_emit.setText(dateStr)



if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = WinForm()
    form.show()
    sys.exit(app.exec_())

執行程式,效果如下
這裡寫圖片描述

程式碼分析

下面程式碼表示,當空間datetime_emit的時間發生變化時,就會觸發,子視窗的槽函式emit_signal,而在這個槽函式中又會發射自定義訊號Signal_OneParameter,這個訊號函式是為了傳遞date_str引數給主函式

    def emit_signal(self):
        date_str = self.datetime_emit.dateTime().toString()
        self.Signal_OneParameter.emit(date_str)

對於主視窗,關鍵是獲取子視窗的訊號,並把它繫結在自己的槽函式上,這樣就實現了子視窗的控制元件與主視窗控制元件的繫結,核心程式碼如下

  def openDialog(self):
        dialog = DateDialog(self)
        '''連線子視窗的內建訊號與主視窗的槽函式'''
        dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)
        '''連線子視窗的自定義訊號與主視窗的槽函式'''
        dialog.Signal_OneParameter.connect(self.deal_emit_slot)
        dialog.show()