2016-04-05 12 views
7

का उचित उपयोग मैं एक साधारण सिग्नल-स्लॉट तंत्र के साथ आने के लिए PyQt5 पर कुछ दस्तावेज़ों के माध्यम से पढ़ रहा हूं। डिजाइन डिजाइन के कारण मैं रुका हुआ हूं।पीईक्यूटी उत्सर्जित() और pyqtSignal()

पर विचार करें निम्नलिखित कोड:

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal) 
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication) 


class Example(QWidget): 

    def __init__(self): 
     super().__init__() 

     self.initUI() 

    def printLabel(self, str): 
     print(str) 

    def logLabel(self, str): 
     '''log to a file''' 
     pass 

    def initUI(self): 

     lcd = QLCDNumber(self) 
     sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(lcd) 
     vbox.addWidget(sld) 

     self.setLayout(vbox) 

     #redundant connections 
     sld.valueChanged.connect(lcd.display) 
     sld.valueChanged.connect(self.printLabel) 
     sld.valueChanged.connect(self.logLabel) 

     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 
     self.show() 


if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

, स्लाइडर में किए गए परिवर्तनों को ट्रैक करने के मैं बस प्रिंट और किए गए परिवर्तनों को लॉग इन करें। मुझे कोड के बारे में क्या पसंद नहीं है कि मुझे 3 अलग-अलग स्लॉट पर एक ही जानकारी भेजने के लिए sld.valueChanged स्लॉट तीन बार कॉल करने की आवश्यकता है।

क्या यह मेरा खुद का pyqtSignal बनाना संभव है जो एकल स्लॉट फ़ंक्शन के लिए पूर्णांक भेजता है। और बदले में स्लॉट फ़ंक्शन उन बदलावों को छोड़ देता है जिन्हें बनाने की आवश्यकता है?

  • हो सकता है कि मैं पूरी तरह से emit() के प्रयोजन के समझ में नहीं आता कि कोई अच्छा उदाहरण हैं की वजह से यह PyQt Signal-Slot docs में उद्देश्य है। हमें दिया गया है कि कोई पैरामीटर के साथ emit को कार्यान्वित करने का एक उदाहरण है।

मैं जो करना चाहता हूं वह एक ऐसा फ़ंक्शन तैयार करता है जो उत्सर्जन कार्य को संभालता है। निम्नलिखित पर विचार करें:

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal) 
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication) 


class Example(QWidget): 

    def __init__(self): 
     super().__init__() 

     #create signal 
     self.val_Changed = pyqtSignal(int, name='valChanged') 

     self.initUI() 

    def initUI(self): 

     lcd = QLCDNumber(self) 
     sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(lcd) 
     vbox.addWidget(sld) 

     self.setLayout(vbox) 

     sld.val_Changed.connect(self.handle_LCD) 
     self.val_Changed.emit() 

     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 
     self.show() 

    def handle_LCD(self, text): 
     '''log''' 
     print(text) 
     '''connect val_Changed to lcd.display''' 

if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

स्पष्ट रूप से यहां कुछ गंभीर डिज़ाइन त्रुटियां हैं। मैं फंक्शन कॉल के क्रम में अपने सिर को लपेट नहीं सकता। और मैं सही ढंग से pyqtSignal लागू नहीं कर रहा हूं। हालांकि मुझे विश्वास है कि निम्नलिखित 3 बिंदुओं को सही ढंग से बताते हुए मुझे उचित ऐप तैयार करने में मदद मिलेगी:

  1. एक पूर्वनिर्धारित सिग्नल के लिए: स्लॉट फ़ंक्शन को सिग्नल भेजें। सिग्नल मूल्यों का उपयोग करने के लिए स्लॉट को फिर से कार्यान्वित किया जा सकता है।
  2. कुछ पैरामीटर के साथ pyqtSignal ऑब्जेक्ट का उत्पादन करें। यह अभी तक स्पष्ट नहीं है कि इन मानकों का उद्देश्य क्या है और वे 'उत्सर्जित' पैरामीटर से अलग कैसे हैं।
  3. emit स्लॉट फ़ंक्शन को विशिष्ट सिग्नल मान भेजने के लिए पुन: कार्यान्वित किया जा सकता है। यह अभी भी स्पष्ट नहीं है कि मुझे पहले मौजूदा सिग्नल विधियों से अलग-अलग मान क्यों भेजने होंगे।

जो कुछ मैं करने की कोशिश कर रहा हूं उसके लिए कोड को पूरी तरह से बदलने के लिए स्वतंत्र महसूस करें क्योंकि मुझे अभी तक यह पता नहीं चला है कि यह अच्छी शैली के दायरे में है या नहीं।

उत्तर

11

आप अपना खुद का स्लॉट (किसी भी पायथन को कॉल करने योग्य) परिभाषित कर सकते हैं और सिग्नल से कनेक्ट कर सकते हैं, फिर उस स्लॉट से अन्य स्लॉट को कॉल करें।

class Example(QWidget): 

    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def printLabel(self, str): 
     print(str) 

    def logLabel(self, str): 
     '''log to a file''' 
     pass 

    @QtCore.pyqtSlot(int) 
    def on_sld_valueChanged(self, value): 
     self.lcd.display(value) 
     self.printLabel(value) 
     self.logLabel(value) 

    def initUI(self): 

     self.lcd = QLCDNumber(self) 
     self.sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(self.lcd) 
     vbox.addWidget(self.sld) 

     self.setLayout(vbox) 
     self.sld.valueChanged.connect(self.on_sld_valueChanged) 


     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 

इसके अलावा, अगर आप अपने खुद के संकेतों को परिभाषित करना चाहते हैं, वे pyqtSignal के वर्ग चर

class Example(QWidget): 
    my_signal = pyqtSignal(int) 

तर्कों के रूप में परिभाषित किया जा करने के लिए वस्तुओं के प्रकार है कि emit हो जाएगा परिभाषित है 'उस पर d संकेत है, तो इस मामले में, आप

self.my_signal.emit(1) 

फेंकना reimplemented किया जा सकता है विशिष्ट संकेत va भेजने के लिए कर सकता है स्लॉट फ़ंक्शन के लिए lues।यह अभी भी स्पष्ट नहीं है कि मुझे पहले मौजूदा सिग्नल विधियों से अलग मान भेजने की आवश्यकता क्यों होगी।

आपको आम तौर पर अंतर्निहित सिग्नल उत्सर्जित नहीं करना चाहिए। आपको केवल उन्हीं संकेतों को उत्सर्जित करने की आवश्यकता होनी चाहिए जिन्हें आप परिभाषित करते हैं। एक सिग्नल को परिभाषित करते समय, आप अलग-अलग प्रकार के साथ विभिन्न हस्ताक्षर परिभाषित कर सकते हैं, और स्लॉट चुन सकते हैं कि वे किस हस्ताक्षर से कनेक्ट करना चाहते हैं। उदाहरण के लिए, आप इस

my_signal = pyqtSignal([int], [str]) 

यह दो अलग-अलग हस्ताक्षर के साथ एक संकेत परिभाषित करेगा कर सकता है, और करने के लिए या तो एक

@pyqtSlot(int) 
def on_my_signal_int(self, value): 
    assert isinstance(value, int) 

@pyqtSlot(str) 
def on_my_signal_str(self, value): 
    assert isinstance(value, str) 

व्यवहार में, मैं शायद ही कभी संकेत हस्ताक्षर ओवरलोड एक स्लॉट कनेक्ट कर सकते हैं। मैं सामान्य रूप से एक ही सिग्नल को अधिभारित करने के बजाय अलग-अलग हस्ताक्षरों के साथ दो अलग-अलग सिग्नल बनाउंगा। लेकिन यह मौजूद है और पीईक्यूटी में समर्थित है क्योंकि क्यूटी में सिग्नल हैं जो इस तरह से अधिभारित होते हैं (उदाहरण के लिए QComboBox.currentIndexChanged)

+0

ऐसा लगता है कि '@pyqtSlot (int)' पर टिप्पणी करने से आउटपुट प्रभावित नहीं होता है। यह एक केस क्यों है? – Max

+0

ऐसा लगता है कि सजावटी का असली उद्देश्य ओवरलोडिंग उद्देश्यों के लिए भी अनुमति देता है। – Max

+0

यह सिर्फ अधिभार के लिए नहीं है। यह [उत्तर] (http://stackoverflow.com/a/14431607/1547004) इसे बहुत अच्छी तरह बताता है। यदि आप कभी थ्रेड में संकेत भेज रहे हैं, तो स्लॉट सजावट की भी आवश्यकता है। –

संबंधित मुद्दे