जवाबों:
क्यूटी प्रलेखन शायद यह सबसे अच्छा बताते हैं:
क्यूटी में, घटनाएं ऑब्जेक्ट हैं, जो अमूर्त
QEvent
वर्ग से ली गई हैं , जो उन चीजों का प्रतिनिधित्व करती हैं जो या तो किसी एप्लिकेशन के भीतर हुई हैं या बाहरी गतिविधि के परिणामस्वरूप जिनके बारे में एप्लिकेशन को पता होना चाहिए। घटनाएँ किसीQObject
उपवर्ग के किसी भी उदाहरण से प्राप्त और नियंत्रित की जा सकती हैं , लेकिन वे विगेट्स के लिए विशेष रूप से प्रासंगिक हैं। यह दस्तावेज़ बताता है कि कैसे घटनाओं को एक विशिष्ट एप्लिकेशन में वितरित और नियंत्रित किया जाता है।
तो घटनाओं और संकेत / स्लॉट एक ही चीजों को पूरा करने वाले दो समानांतर तंत्र हैं। सामान्य तौर पर, एक घटना एक बाहरी संस्था (उदाहरण के लिए, कीबोर्ड या माउस व्हील) द्वारा उत्पन्न की जाएगी और इवेंट लूप के माध्यम से वितरित की जाएगी QApplication
। सामान्य तौर पर, जब तक आप कोड सेट नहीं करते, तब तक आप ईवेंट नहीं बना पाएंगे। QObject::installEventFilter()
उपयुक्त कार्यों को ओवरराइड करके आप उन्हें उप-वर्गीकृत ऑब्जेक्ट में घटनाओं को फ़िल्टर या संभाल सकते हैं।
सिग्नल और स्लॉट उत्पन्न करना और प्राप्त करना बहुत आसान है और आप किसी भी दो QObject
उपवर्गों को जोड़ सकते हैं । उन्हें मेटाक्लास के माध्यम से नियंत्रित किया जाता है (अधिक के लिए आपकी moc_classname.cpp फ़ाइल पर एक नज़र डालें), लेकिन अधिकांश इंटरक्लास संचार जो आप उत्पन्न करेंगे वे संभवतः सिग्नल और स्लॉट का उपयोग करेंगे। सिग्नल तुरंत या एक कतार के माध्यम से स्थगित हो सकते हैं (यदि आप थ्रेड का उपयोग कर रहे हैं)।
एक संकेत उत्पन्न किया जा सकता है।
Qt में, सिग्नल और इवेंट दोनों ऑब्जर्वर पैटर्न के कार्यान्वयन हैं । उनका उपयोग विभिन्न स्थितियों में किया जाता है क्योंकि उनके पास अलग-अलग ताकत और कमजोरियां हैं।
सबसे पहले हम यह परिभाषित करते हैं कि 'Qt घटना' से हमारा क्या अभिप्राय है: Qt वर्ग में एक वर्चुअल फंक्शन, जो आपसे अपेक्षित है कि यदि आप ईवेंट को हैंडल करना चाहते हैं तो आप के बेस क्लास में उसे फिर से लागू कर दें। यह टेम्पलेट विधि पैटर्न से संबंधित है ।
ध्यान दें कि मैंने " हैंडल " शब्द का उपयोग कैसे किया । दरअसल, यहाँ संकेतों और घटनाओं के इरादे के बीच एक बुनियादी अंतर है:
अंतर यह है कि जब आप घटना को "हैंडल" करते हैं, तो आप एक व्यवहार के साथ "प्रतिक्रिया" करने की जिम्मेदारी लेते हैं जो कक्षा के बाहर उपयोगी होती है। उदाहरण के लिए, उस ऐप पर विचार करें जिस पर एक बटन है जिस पर एक नंबर है। ऐप को उपयोगकर्ता को बटन पर ध्यान केंद्रित करने और "ऊपर" और "नीचे" कीबोर्ड कुंजियों को दबाकर नंबर बदलने की आवश्यकता है। अन्यथा बटन को सामान्य की तरह कार्य करना चाहिए QPushButton
(इसे क्लिक किया जा सकता है, आदि)। क्यूटी में यह आपके स्वयं के पुन: प्रयोज्य "घटक" (उपवर्ग QPushButton
) का निर्माण करके किया जाता है , जो पुन: लागू होता है QWidget::keyPressEvent
। स्यूडोकोड:
class NumericButton extends QPushButton
private void addToNumber(int value):
// ...
reimplement base.keyPressEvent(QKeyEvent event):
if(event.key == up)
this.addToNumber(1)
else if(event.key == down)
this.addToNumber(-1)
else
base.keyPressEvent(event)
देख? यह कोड एक नया अमूर्त प्रस्तुत करता है: एक विजेट जो एक बटन की तरह काम करता है, लेकिन कुछ अतिरिक्त कार्यक्षमता के साथ। हमने इस कार्यक्षमता को बहुत आसानी से जोड़ा:
keyPressEvent
एक संकेत दिया था , तो हमें यह तय करने की आवश्यकता होगी कि क्या विरासत में मिला QPushButton
या सिर्फ बाहरी रूप से संकेत से जुड़ा था। लेकिन उस बेवकूफ हो सकता है, के बाद से क्यूटी में आप कर रहे हैं हमेशा वारिस के उम्मीद जब एक कस्टम व्यवहार के साथ एक विजेट (अच्छे कारण के लिए - पुनर्प्रयोग / प्रतिरूपकता) लेखन। इसलिए keyPressEvent
एक घटना बनाकर , वे अपने इरादे को व्यक्त करते हैं जो keyPressEvent
कार्यक्षमता का सिर्फ एक बुनियादी निर्माण खंड है। यदि यह एक संकेत था, तो यह उपयोगकर्ता-सामना करने वाली चीज़ की तरह दिखाई देगा, जब इसका इरादा नहीं है।keyPressEvent
एक संकेत था।क्यूटी के डिजाइन सुविचारित है - वे हमें बनाया सफलता के गड्ढे में गिर जाते हैं सही काम करने के लिए आसान बना और गलत बात करना बहुत मुश्किल (keyPressEvent एक घटना बनाने के द्वारा) द्वारा।
दूसरी ओर, सबसे सरल उपयोग पर विचार करें QPushButton
- बस इसे तत्काल करना और इसे क्लिक करने पर अधिसूचित करना :
button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())
यह स्पष्ट रूप से कक्षा के उपयोगकर्ता द्वारा किया जाना है :
QPushButton
हर बार उप-वर्ग करना होता है तो हम चाहते हैं कि हमें एक क्लिक के बारे में सूचित करने के लिए कुछ बटन चाहिए, जिसके लिए बिना किसी अच्छे कारण के बहुत सारे उपवर्गों की आवश्यकता होगी ! एक विजेट जो हमेशा "हैलो वर्ल्ड" दिखाता है, messagebox
जब क्लिक किया जाता है तो यह केवल एक ही मामले में उपयोगी होता है - इसलिए यह पूरी तरह से पुन: प्रयोज्य नहीं है। फिर, हमारे पास बाहरी रूप से इसे जोड़कर - सही काम करने के अलावा कोई विकल्प नहीं है।clicked()
- या कई सिग्नल को कनेक्ट कर सकते हैं sayHello()
। संकेतों के साथ कोई उपद्रव नहीं है। सबक्लासिंग के साथ आपको कुछ क्लास आरेखों को बैठना होगा और जब तक आप एक उपयुक्त डिज़ाइन तय नहीं कर लेते हैं।ध्यान दें कि एक जगह का QPushButton
उत्सर्जन clicked()
इसके mousePressEvent()
कार्यान्वयन में है। इसका मतलब यह नहीं है clicked()
और mousePressEvent()
विनिमेय हैं - बस वे संबंधित हैं।
इसलिए संकेतों और घटनाओं के अलग-अलग उद्देश्य होते हैं (लेकिन इसमें संबंधित हैं कि दोनों आपको कुछ होने की सूचना के लिए "सदस्यता" देते हैं)।
मुझे अब तक के जवाब पसंद नहीं हैं। - मुझे इस प्रश्न के भाग पर ध्यान केंद्रित करने दें:
क्या घटनाएं सिग्नल / स्लॉट्स का अमूर्त हिस्सा हैं?
संक्षिप्त उत्तर: नहीं। लंबे उत्तर से एक "बेहतर" सवाल उठता है: संकेत और घटनाएं कैसे संबंधित हैं?
एक निष्क्रिय मुख्य लूप (उदाहरण के लिए Qt) आमतौर पर ऑपरेटिंग सिस्टम के चयन () कॉल में "अटक" जाता है। वह कॉल एप्लिकेशन को "स्लीप" बनाता है, जबकि यह सॉकेट्स या फाइलों का एक गुच्छा या कर्नेल से जो कुछ भी मांगता है: यदि इन पर कुछ बदलता है, तो चयन () कॉल रिटर्न दें। - और कर्नेल, दुनिया के मालिक के रूप में जानता है कि ऐसा कब होता है।
उस चुनिंदा () कॉल का परिणाम हो सकता है: सॉकेट पर नया डेटा X11 से कनेक्ट होता है, एक पैकेट जिसे हम यूडीपी पोर्ट पर सुनते हैं, आदि - आदि। वह सामान न तो क्यूटी सिग्नल है, न ही क्यूटी इवेंट, और Qt मुख्य लूप स्वयं तय करता है यदि यह ताजा डेटा को एक, दूसरे में बदल देता है या इसे अनदेखा करता है।
क्यूटी एक विधि (या कई) को keyPressEvent () की तरह कह सकता है, प्रभावी रूप से एक क्यूटी घटना में बदल सकता है। या क्यूटी एक सिग्नल का उत्सर्जन करता है, जो वास्तव में उस सिग्नल के लिए पंजीकृत सभी कार्यों को देखता है, और उन्हें एक के बाद एक कॉल करता है।
उन दो अवधारणाओं का एक अंतर यहां दिखाई दे रहा है: एक स्लॉट में इस बात का कोई वोट नहीं है कि उस सिग्नल पर पंजीकृत अन्य स्लॉट को कॉल किया जाएगा या नहीं। - इवेंट एक चेन की तरह अधिक होते हैं, और ईवेंट हैंडलर यह तय करता है कि यह उस चेन को बाधित करता है या नहीं। संकेत इस संबंध में एक तारे या पेड़ की तरह दिखते हैं।
एक घटना ट्रिगर हो सकती है या पूरी तरह से एक संकेत में बदल सकती है (सिर्फ एक का उत्सर्जन करें, और "सुपर ()") को कॉल न करें। एक संकेत को एक घटना में बदल दिया जा सकता है (एक घटना हैंडलर को कॉल करें)।
क्या सार मामले पर निर्भर करता है: क्लिक किया गया () - सिग्नल एब्स्ट्रैक्ट माउस इवेंट (एक बटन नीचे और ऊपर फिर से बहुत अधिक घूमने के बिना)। कीबोर्ड इवेंट निचले स्तर से सार होते हैं (या é जैसी चीजें मेरे सिस्टम पर कई महत्वपूर्ण स्ट्रोक हैं)।
हो सकता है कि ध्यान केंद्रित () विपरीत का एक उदाहरण है: यह क्लिक किया गया () सिग्नल का उपयोग कर सकता है (और इस प्रकार सार), लेकिन मुझे नहीं पता कि यह वास्तव में करता है या नहीं।
इवेंट लूप द्वारा ईवेंट भेजे जाते हैं। प्रत्येक GUI प्रोग्राम को एक इवेंट लूप की आवश्यकता होती है, जो भी आप इसे Qt, Win32 या किसी अन्य GUI लाइब्रेरी का उपयोग करके विंडोज या लिनक्स लिखते हैं। साथ ही प्रत्येक थ्रेड का अपना ईवेंट लूप होता है। Qt में "GUI इवेंट लूप" (जो सभी Qt अनुप्रयोगों का मुख्य लूप है) छिपा हुआ है, लेकिन आप इसे कॉल करना शुरू करते हैं:
QApplication a(argc, argv);
return a.exec();
आपके कार्यक्रम के लिए भेजे गए संदेश OS और अन्य एप्लिकेशन ईवेंट के रूप में भेजे जाते हैं।
सिग्नल और स्लॉट क्यूटी तंत्र हैं। मॉक (मेटा-ऑब्जेक्ट कंपाइलर) का उपयोग करके संकलन की प्रक्रिया में, उन्हें कॉलबैक फ़ंक्शन में बदल दिया जाता है।
घटना में एक रिसीवर होना चाहिए, जो इसे भेजना चाहिए। किसी और को वह घटना नहीं मिलनी चाहिए।
उत्सर्जित सिग्नल से जुड़े सभी स्लॉट निष्पादित किए जाएंगे।
आपको सिग्नल के बारे में घटनाओं के रूप में नहीं सोचना चाहिए, क्योंकि जैसा कि आप क्यूटी प्रलेखन में पढ़ सकते हैं:
जब एक सिग्नल उत्सर्जित होता है, तो इससे जुड़े स्लॉट्स को सामान्य फ़ंक्शन कॉल की तरह, तुरंत निष्पादित किया जाता है। जब ऐसा होता है, सिग्नल और स्लॉट तंत्र किसी भी GUI इवेंट लूप से पूरी तरह से स्वतंत्र होते हैं।
जब आप कोई ईवेंट भेजते हैं, तो उसे कुछ समय तक इंतजार करना चाहिए जब तक कि ईवेंट लूप उन सभी ईवेंट को न भेज दे जो पहले आए थे। इस वजह से, ईवेंट या सिग्नल भेजने के बाद कोड का निष्पादन अलग है। किसी घटना को भेजने के बाद कोड तुरंत चलाया जाएगा। सिग्नल और स्लॉट तंत्र के साथ यह कनेक्शन प्रकार पर निर्भर करता है। आम तौर पर सभी स्लॉट्स के बाद इसे निष्पादित किया जाएगा। Qt का उपयोग करना: QueuedConnection, इसे घटनाओं की तरह ही तुरंत निष्पादित किया जाएगा। Qt प्रलेखन में सभी कनेक्शन प्रकारों की जाँच करें ।
When you send an event, it must wait for time when event loop dispatch all events that came earlier. Because of this, execution of the cod after sending event or signal is different
एक लेख है जो कुछ विस्तार से घटना प्रसंस्करण पर चर्चा करता है: http://www.packtpub.com/article/events-and-signals
यह यहां घटनाओं और संकेतों के बीच अंतर पर चर्चा करता है:
घटनाएँ और संकेत एक ही चीज़ को पूरा करने के लिए उपयोग किए जाने वाले दो समानांतर तंत्र हैं। सामान्य अंतर के रूप में, विजेट का उपयोग करते समय सिग्नल उपयोगी होते हैं, जबकि विजेट को लागू करते समय घटनाएं उपयोगी होती हैं। उदाहरण के लिए, जब हम QPushButton जैसे विजेट का उपयोग कर रहे हैं, तो हम निम्न-स्तरीय माउस प्रेस या कुंजी प्रेस घटनाओं की तुलना में इसके क्लिक किए गए () सिग्नल में अधिक रुचि रखते हैं जिसके कारण सिग्नल उत्सर्जित होता है। लेकिन अगर हम QPushButton वर्ग को लागू कर रहे हैं, तो हम माउस और प्रमुख घटनाओं के लिए कोड के कार्यान्वयन में अधिक रुचि रखते हैं। इसके अलावा, हम आमतौर पर घटनाओं को संभालते हैं लेकिन सिग्नल उत्सर्जन से अधिसूचित होते हैं।
यह इसके बारे में बात करने का एक सामान्य तरीका प्रतीत होता है, क्योंकि स्वीकृत उत्तर कुछ समान वाक्यांशों का उपयोग करता है।
ध्यान दें, कुबा ओबर के इस जवाब पर नीचे उपयोगी टिप्पणियां देखें, मुझे आश्चर्य होगा कि अगर यह थोड़ा सरल हो सकता है।
event
। सिग्नल और स्लॉट, समवर्ती , तरीके हैं, जबकि कनेक्शन तंत्र एक डेटा संरचना है जो सिग्नल को एक या अधिक स्लॉट को सूचीबद्ध करने की अनुमति देता है। मुझे आशा है कि आप देखते हैं कि कुछ "सबसेट" या घटनाओं के "संस्करण" के रूप में संकेत / स्लॉट्स की बात करना बकवास है, और इसके विपरीत। वे वास्तव में अलग अलग चीजें हैं जो कर रहे हैं ऐसा कुछ विगेट्स के संदर्भ में समान छोर तक इस्तेमाल किया जा रहा। बस। जितना अधिक आप सामान्य करते हैं, उतना कम सहायक आप IMHO बन जाते हैं।
टीएल; डीआर: सिग्नल और स्लॉट अप्रत्यक्ष विधि कॉल हैं। घटनाएँ डेटा संरचनाएँ हैं। इसलिए वे काफी अलग जानवर हैं।
एकमात्र समय जब वे एक साथ आते हैं, जब स्लॉट कॉल थ्रेड सीमाओं के पार किए जाते हैं। स्लॉट कॉल तर्क को डेटा संरचना में पैक किया जाता है और एक कार्यक्रम के रूप में प्राप्त होने वाले धागे की घटना कतार में भेज दिया जाता है। प्राप्त करने वाले थ्रेड में, QObject::event
विधि तर्कों को अनपैक करती है, कॉल निष्पादित करती है, और संभवत: परिणाम रोकती है यदि यह एक अवरुद्ध कनेक्शन था।
यदि हम गुमनामी को सामान्य करने के लिए तैयार हैं, तो व्यक्ति लक्ष्य वस्तु के तरीके को लागू करने के तरीके के रूप में घटनाओं के बारे में सोच सकता है event
। यह एक अप्रत्यक्ष विधि कॉल है, एक फैशन के बाद - लेकिन मुझे नहीं लगता कि यह इसके बारे में सोचने का एक उपयोगी तरीका है, भले ही यह एक सच्चा बयान हो।
घटनाएँ (उपयोगकर्ता / नेटवर्क इंटरैक्शन के एक सामान्य अर्थ में) आमतौर पर क्यूटी में सिग्नल / स्लॉट के साथ नियंत्रित की जाती हैं, लेकिन सिग्नल / स्लॉट अन्य बहुत सारे काम कर सकते हैं।
QEvent और उसके उपवर्ग मूल रूप से आपके कोड के साथ संवाद करने के लिए फ्रेमवर्क के लिए थोड़े मानकीकृत डेटा पैकेज हैं। यदि आप किसी तरह से माउस पर ध्यान देना चाहते हैं, तो आपको केवल QMouseEvent API को देखना होगा, और लाइब्रेरी डिजाइनरों को हर बार पहिया को सुदृढ़ करने की आवश्यकता नहीं है, जब आपको यह पता लगाना होगा कि माउस ने किसी कोने में क्या किया है। क्यूटी एपीआई।
यह सच है कि यदि आप किसी प्रकार की घटनाओं (फिर से सामान्य स्थिति में) की प्रतीक्षा कर रहे हैं, तो आपका स्लॉट एक तर्क के रूप में QEvent उपवर्ग को लगभग निश्चित रूप से स्वीकार करेगा।
उस कहा के साथ, संकेत और स्लॉट निश्चित रूप से QEvents के बिना उपयोग किया जा सकता है, हालांकि आप पाएंगे कि सिग्नल को सक्रिय करने के लिए मूल प्रेरणा अक्सर किसी प्रकार की उपयोगकर्ता सहभागिता या अन्य अतुल्यकालिक गतिविधि होगी। कभी-कभी, हालांकि, आपका कोड बस एक बिंदु तक पहुंच जाएगा, जहां एक निश्चित सिग्नल को बंद करना सही काम होगा। उदाहरण के लिए, एक लंबी प्रक्रिया के दौरान एक प्रगति बार से जुड़े सिग्नल को बंद करने से उस बिंदु पर QEvent शामिल नहीं होता है।
लेव वे खेंग द्वारा 'इवेंट प्रोसेसिंग' पढ़ते हुए मुझे यह सवाल मिला । यह भी कहता है:
जैस्मिन ब्लैंचेट कहती हैं:
मुख्य कारण है कि आप मानक फ़ंक्शन कॉल, या सिग्नल और स्लॉट के बजाय घटनाओं का उपयोग क्यों करेंगे, यह है कि घटनाओं का उपयोग सिंक्रोनस और एसिंक्रोनसली दोनों तरह से किया जा सकता है (यह निर्भर करता है कि आप सेंडइवेंट () या पोस्टवेंट्स ()) कॉल करते हैं, जबकि फ़ंक्शन या कॉल करना एक स्लॉट हमेशा तुल्यकालिक होता है। घटनाओं का एक और लाभ यह है कि उन्हें फ़िल्टर किया जा सकता है।
एक और मामूली व्यावहारिक विचार: संकेतों को छोड़ने या प्राप्त करने के लिए विरासत की आवश्यकता होती है, QObject
जबकि किसी भी विरासत की वस्तु एक घटना पोस्ट या भेज सकती है (क्योंकि आप इसे लागू करते हैं QCoreApplication.sendEvent()
या postEvent()
) यह आमतौर पर एक मुद्दा नहीं है: लेकिन संकेतों का उपयोग करने के लिए PyQt को अजीब तरह QObject
से पहले सुपर क्लास होने की आवश्यकता होती है, और आप केवल संकेत भेजने में सक्षम होने के लिए अपने वंशानुक्रम क्रम को पुनर्व्यवस्थित नहीं करना चाहते हैं। "
मेरी राय में घटनाएँ पूरी तरह से बेमानी हैं और उन्हें बाहर निकाला जा सकता है। ऐसा कोई कारण नहीं है कि संकेतों को घटनाओं या संकेतों द्वारा प्रतिस्थापित नहीं किया जा सकता है, सिवाय इसके कि क्यूटी पहले से ही सेट है जैसा कि है। कतारबद्ध संकेतों को घटनाओं द्वारा लपेटा जाता है और घटनाओं को संकेतों द्वारा लिपटा जा सकता है, उदाहरण के लिए:
connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});
(लेकिन अब में नहीं) में mouseMoveEvent()
पाए गए सुविधा फ़ंक्शन को बदल देगा और उन संकेतों को संभाल लेगा जो एक दृश्य प्रबंधक आइटम के लिए उत्सर्जित करेगा। तथ्य यह है कि कुछ बाहरी इकाई द्वारा आइटम की ओर से संकेत उत्सर्जित होता है और क्यूटी घटकों की दुनिया में अक्सर होता है, भले ही इसकी अनुमति नहीं है (क्यूटी घटक अक्सर इस नियम को दरकिनार करते हैं)। लेकिन Qt पुराने कोड के टूटने के डर से कई अलग-अलग डिज़ाइन के फैसलों का एक समूह है और बहुत अधिक पत्थर में डाली जाती है (जो अक्सर किसी भी तरह होता है)।QWidget
QQuickItem
mouseMove
QObject
जब आवश्यक हो, तो माता-पिता-बच्चे पदानुक्रम को प्रचारित करने के लिए घटनाओं का लाभ होता है। सिग्नल / स्लॉट कनेक्शन एक फ़ंक्शन को कॉल करने का एक वादा है, सीधे या परोक्ष रूप से, जब एक निश्चित शर्त पूरी होती है। सिग्नल और स्लॉट के साथ संबद्ध हैंडलिंग पदानुक्रम नहीं है।
accepted
एक सिग्नल के लिए एक संदर्भ पैरामीटर और इसे संभालने वाले स्लॉट्स जोड़ सकते हैं या आपके पास accepted
फ़ील्ड के साथ संदर्भ पैरामीटर के रूप में एक संरचना हो सकती है । लेकिन क्यूटी ने इसे बनाया डिजाइन विकल्प बनाया और वे अब पत्थर में सेट हैं।