यह संकेत / स्लॉट कोड क्यों काम नहीं कर रहा है - पायथन, pyqt, pyqt5, संकेत-स्लॉट

मेरे पास एक मूल सिग्नल / स्लॉट कोड है जहां मैं एक विजेट में सिग्नल उत्सर्जित करना चाहता हूं, और उस सिग्नल को किसी अन्य विजेट में जोड़ना चाहता हूं।

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QMainWindow, QAction, QApplication, QWidget, QPushButton, qApp, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QFileDialog
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QImage
from PyQt5.QtCore import QSize, Qt, pyqtSignal, QObject
import sys, random
import qdarkstyle
from os import path

class SignalFactory(QObject):
selectedTextureToLoad = pyqtSignal()

class Application(QMainWindow):
def __init__(self):
super().__init__()
self.signals = SignalFactory()
self.mainArea = MainArea()

# Option 1 - Uncomment below / Works but strong coupling between widgets
# self.signals.selectedTextureToLoad.connect(self.mainArea.doSomeStuff)

self.setCentralWidget(self.mainArea)
self.setGeometry(300, 300, 800, 400)
self.show()

def emitStuff(self):
print("Emitting...")
self.signals.selectedTextureToLoad.emit()

class MainArea(QWidget):
def __init__(self):
super().__init__()
self.signals = SignalFactory()

# Option 2 - Uncomment below / Does not work
#self.signals.selectedTextureToLoad.connect(self.doSomeStuff)

def doSomeStuff(self):
print("Receiving...")

if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Application()
ex.emitStuff()
sys.exit(app.exec_())
  • अगर मैं विकल्प 1 को अनमोल करता हूं, तो कोड काम करता है, औरसिग्नल प्राप्त होता है। हालांकि, दो विगेट्स के बीच एक युग्मन है। इस मामले में यह ठीक है, क्योंकि एक विजेट दूसरे का अभिभावक है और स्वाभाविक रूप से अपने बच्चे का ट्रैक रखता है। लेकिन एक जटिल परिदृश्य में, इसका मतलब है कि सिग्नल को कॉन्फ़िगर करने के लिए कई विजेट्स का ट्रैक रखना, जो कि बहुत अच्छा नहीं है।

  • अगर मैं विकल्प 2 को अपूर्ण करता हूं, तो कोड काम नहीं करता है,और कंसोल केवल "उत्सर्जित ..." प्रदर्शित करता है। यह बहुत परेशान है, क्योंकि यह मेरी राय में सिग्नल को कॉन्फ़िगर करने के बिना सिग्नल को कॉन्फ़िगर करने का सबसे साफ तरीका है और इसे किसी अन्य स्थान से बाहर निकालना है।

क्या मैं यहाँ कुछ मौलिक याद कर रहा हूँ?

संपादित करें:

यदि आप इसे जोड़कर, इस तरह के कोड को संशोधित करते हैं returnASignal समारोह

from PyQt5.QtWidgets import QMainWindow, QAction, QApplication, QWidget, QPushButton, qApp, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QFileDialog
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QImage
from PyQt5.QtCore import QSize, Qt, pyqtSignal, QObject
import sys, random
import qdarkstyle
from os import path

def returnASignal():
print("Returning a signal")
return pyqtSignal()

class SignalFactory(QObject):
selectedTextureToLoad = returnASignal()

class Application(QMainWindow):
def __init__(self):
super().__init__()
self.signals = SignalFactory()
self.mainArea = MainArea()
# Option 2 - Uncomment below / Works but strong coupling between widgets
# self.signals.selectedTextureToLoad.connect(self.mainArea.doSomeStuff)
self.setCentralWidget(self.mainArea)
self.setGeometry(300, 300, 800, 400)
self.show()

def emitStuff(self):
print("Emitting...")
self.signals.selectedTextureToLoad.emit()

class MainArea(QWidget):
def __init__(self):
super().__init__()
self.signals = SignalFactory()
# Option 1 - Uncomment below / Does not work
self.signals.selectedTextureToLoad.connect(self.doSomeStuff)

def doSomeStuff(self):
print("Receiving...")

if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Application()
ex.emitStuff()
sys.exit(app.exec_())

इसे चलाने पर कंसोल इसे प्रदर्शित करता है:

Returning a signal
Emitting...

"एक सिग्नल लौटाना" केवल एक बार मुद्रित होता है और दो बार नहीं, जो दिखाता है कि हालांकि कई हैं SignalFactory उदाहरण, वे सब एक ही साझा करते हैं selectedTextureToLoad वस्तु। यह निश्चित रूप से एक उचित है स्थैतिक वर्ग के सदस्य और एक आवृत्ति चर नहीं। इसलिए, सिग्नल ऑब्जेक्ट हर जगह समान है, और मुझे अभी भी समझ में नहीं आता कि विकल्प 2 क्यों काम नहीं करता है।

उत्तर:

जवाब के लिए 2 № 1

यहाँ कोई असली रहस्य नहीं है। सिग्नल ऑब्जेक्ट्स वैसे ही व्यवहार करते हैं जैसे कक्षाओं में परिभाषित विधियां।

यदि आप इस तरह के कुछ डिबगिंग प्रिंट डालते हैं:

class SignalFactory(QObject):
selectedTextureToLoad = returnASignal()
print(selectedTextureToLoad)

def foo(self): pass
print(foo)

class Application(QMainWindow):
def __init__(self):
super().__init__()
self.signals = SignalFactory()
print(self.signals.selectedTextureToLoad)
print(self.signals.foo)
...

class MainArea(QWidget):
def __init__(self):
super().__init__()
self.signals = SignalFactory()
print(self.signals.selectedTextureToLoad)
print(self.signals.foo)

और अपना उदाहरण चलाएं, यह इस तरह के आउटपुट का उत्पादन करेगा:

Returning a signal
<unbound PYQT_SIGNAL []>
<function SignalFactory.foo at 0x7f2a57b1c268>
<bound PYQT_SIGNAL selectedTextureToLoad of SignalFactory object at 0x7f2a57b96828>
<bound method SignalFactory.foo of <__main__.SignalFactory object at 0x7f2a57b96828>>
<bound PYQT_SIGNAL selectedTextureToLoad of SignalFactory object at 0x7f2a57b96948>
<bound method SignalFactory.foo of <__main__.SignalFactory object at 0x7f2a57b96948>>
Emitting...

जैसा कि आप देख सकते हैं, सिग्नल और विधियां दोनों हैं बाध्य वस्तुओं जब कक्षा से उपयोग किए जाने पर उदाहरणों से और अनबाउंड ऑब्जेक्ट्स तक पहुंचाया जाता है। विधि को उदाहरण के लिए बाध्य होना चाहिए ताकि self पहले तर्क के रूप में पारित किया जा सकता है। इसी तरह, एक सिग्नल ऑब्जेक्ट को यह सुनिश्चित करने के लिए बाध्य होना चाहिए कि कनेक्टेड स्लॉट केवल सिग्नल प्राप्त करें इसे भेजे गए विशिष्ट उदाहरण से

तो वहाँ हैं दो संकेतों का नाम selectedTextureToLoad आपके उदाहरण में - प्रत्येक के उदाहरण के लिए एक SignalFactory वह बनाया गया है। आपका उदाहरण काम नहीं करता है क्योंकि doSomeStuff स्लॉट नहीं है "से जुड़ा हुआ है विशिष्ट बाध्य सिग्नल ऑब्जेक्ट जो उत्सर्जित किया selectedTextureToLoad संकेत।

सिग्नल स्लॉट तंत्र के लिए डिज़ाइन किया गया हैवस्तुओं के बीच संचार। ज्ञात प्रेषक के बिना संदेशों को प्रसारित करने की कोई सुविधा नहीं है, इसलिए एमिटर और रिसीवर के बीच स्पष्ट कनेक्शन हमेशा बनाए जाना चाहिए। यदि आप एक और सामान्य संकेत भेजना चाहते हैं, तो वैश्विक उदाहरण बनाएं SignalFactory


संबंधित सवाल
सबसे लोकप्रिय