खोज…


परिचय

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

टिप्पणियों

इस विषय पर आधिकारिक दस्तावेज यहां देखे जा सकते हैं

एक छोटा सा उदाहरण

सिग्नल और स्लॉट वस्तुओं के बीच संचार के लिए उपयोग किए जाते हैं। सिग्नल और स्लॉट तंत्र क्यूटी की एक केंद्रीय विशेषता है और शायद वह हिस्सा जो अन्य रूपरेखाओं द्वारा प्रदान की गई विशेषताओं से सबसे अलग है।

न्यूनतम उदाहरण के लिए एक संकेत, एक स्लॉट और एक कनेक्शन के साथ एक वर्ग की आवश्यकता होती है:

counter.h

#ifndef COUNTER_H
#define COUNTER_H

#include <QWidget>
#include <QDebug>

class Counter : public QWidget
{
    /*
     * All classes that contain signals or slots must mention Q_OBJECT
     * at the top of their declaration.
     * They must also derive (directly or indirectly) from QObject.
     */
    Q_OBJECT

public:
    Counter (QWidget *parent = 0): QWidget(parent)
    {
            m_value = 0;

            /*
             * The most important line: connect the signal to the slot.
             */
            connect(this, &Counter::valueChanged, this, &Counter::printvalue);
    }

    void setValue(int value)
    {
        if (value != m_value) {
            m_value = value;
            /*
             * The emit line emits the signal valueChanged() from
             * the object, with the new value as argument.
             */
            emit valueChanged(m_value);
        }
    }

public slots:
    void printValue(int value)
    {
        qDebug() << "new value: " << value;
    }

signals:
    void valueChanged(int newValue);

private:
    int m_value;

};

#endif

main एक नया मान सेट करता है। हम यह जांच सकते हैं कि स्लॉट को कैसे कहा जाता है, मान को प्रिंट करना।

#include <QtGui>
#include "counter.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    Counter counter;
    counter.setValue(10);
    counter.show();

    return app.exec();
}

अंत में, हमारी परियोजना फ़ाइल:

SOURCES   = \
            main.cpp
HEADERS   = \
            counter.h

नया Qt5 कनेक्शन सिंटैक्स

पारंपरिक connect सिंटैक्स जो SIGNAL और SLOT मैक्रोज़ का उपयोग करता है, पूरी तरह से रनटाइम पर काम करता है, जिसमें दो कमियां हैं: इसमें कुछ रनटाइम ओवरहेड (जिसके परिणामस्वरूप बाइनरी साइज़ ओवरहेड भी है), और कोई कंपाइल-टाइम शुद्धता जाँच नहीं है। नया सिंटैक्स दोनों समस्याओं को हल करता है। एक उदाहरण में वाक्य रचना की जाँच करने से पहले, हम बेहतर जानते हैं कि विशेष रूप से क्या होता है।

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

यहाँ एक नमूना main.cpp है :

#include <QApplication>
#include <QDebug>
#include <QTimer>

inline void onTick()
{
   qDebug() << "onTick()";
}

struct OnTimerTickListener {
   void onTimerTick()
   {
       qDebug() << "OnTimerTickListener::onTimerTick()";
   }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    OnTimerTickListener listenerObject;

    QTimer timer;
    // Connecting to a non-member function
    QObject::connect(&timer, &QTimer::timeout, onTick);
    // Connecting to an object member method
    QObject::connect(&timer, &QTimer::timeout, &listenerObject, &OnTimerTickListener::onTimerTick);
    // Connecting to a lambda
    QObject::connect(&timer, &QTimer::timeout, [](){
        qDebug() << "lambda-onTick";
    });    

    return app.exec();
}

संकेत: पुराने सिंटैक्स ( SIGNAL / SLOT मैक्रोज़) के लिए आवश्यक है कि Qt मेटाकॉम्पलर (MOC) किसी भी वर्ग के लिए चलाया जाए जिसमें या तो स्लॉट या सिग्नल हों। कोडिंग दृष्टिकोण से इसका मतलब है कि ऐसी कक्षाओं के लिए Q_OBJECT मैक्रो होना आवश्यक है (जो इस वर्ग पर MOC चलाने की आवश्यकता को इंगित करता है)।

दूसरी ओर, नया सिंटैक्स, अभी भी संकेतों के लिए एमओसी के लिए काम करने की आवश्यकता है, लेकिन स्लॉट्स के लिए नहीं । यदि किसी वर्ग में केवल स्लॉट्स हैं और कोई सिग्नल नहीं है, तो उसके पास Q_OBJECT मैक्रो नहीं है और इसलिए वह MOC का आह्वान नहीं कर सकता है, जो न केवल अंतिम बाइनरी आकार को कम करता है, बल्कि संकलन समय (कोई MOC कॉल और कोई बाद में संकलक कॉल उत्पन्न नहीं करता है) को कम करता है *_moc.cpp फ़ाइल)।

अतिभारित सिग्नल / स्लॉट को जोड़ना

कई मामलों में बेहतर होने के बावजूद, Qt5 में नए कनेक्शन सिंटैक्स में एक बड़ी कमजोरी है: अतिभारित सिग्नल और स्लॉट कनेक्ट करना। संकलक को ओवरलोड को हल करने देने के लिए हमें static_cast s का उपयोग करने के लिए सदस्य फ़ंक्शन को qOverload करने की आवश्यकता है, या (Qt 5.7 में शुरू) qOverload और दोस्तों:

#include <QObject>

class MyObject : public QObject
{
    Q_OBJECT
public:
    explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}

public slots:
    void slot(const QString &string) {}
    void slot(const int integer) {}

signals:
    void signal(const QString &string) {}
    void signal(const int integer) {}
};

int main(int argc, char **argv)
{
    QCoreApplication app(argc, argv);

    // using pointers to make connect calls just a little simpler
    MyObject *a = new MyObject;
    MyObject *b = new MyObject;

    // COMPILE ERROR! the compiler does not know which overloads to pick :(
    QObject::connect(a, &MyObject::signal, b, &MyObject::slot);

    // this works, now the compiler knows which overload to pick, it is very ugly and hard to remember though...
    QObject::connect(
        a,
        static_cast<void(MyObject::*)(int)>(&MyObject::signal),
        b,
        static_cast<void(MyObject::*)(int)>(&MyObject::slot));

    // ...so starting in Qt 5.7 we can use qOverload and friends:
    // this requires C++14 enabled:
    QObject::connect(
        a,
        qOverload<int>(&MyObject::signal),
        b,
        qOverload<int>(&MyObject::slot));

    // this is slightly longer, but works in C++11:
    QObject::connect(
        a,
        QOverload<int>::of(&MyObject::signal),
        b,
        QOverload<int>::of(&MyObject::slot));

    // there are also qConstOverload/qNonConstOverload and QConstOverload/QNonConstOverload, the names should be self-explanatory
}

मल्टी विंडो सिग्नल स्लॉट कनेक्शन

सिग्नल और स्लॉट का उपयोग करके एक साधारण मल्टीविंडो उदाहरण।

एक मेनविंडो क्लास है जो मेन विंडो व्यू को नियंत्रित करता है। वेबसाइट वर्ग द्वारा नियंत्रित दूसरी विंडो।

दो वर्ग जुड़े हुए हैं ताकि जब आप वेबसाइट की विंडो पर एक बटन पर क्लिक करें तो मेनविंडो (एक पाठ लेबल बदला जाता है) में कुछ होता है।

मैंने एक सरल उदाहरण बनाया जो गीथहब पर भी है :

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "website.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    void changeText();

private slots:
    void on_openButton_clicked();

private:
    Ui::MainWindow *ui;

    //You want to keep a pointer to a new Website window
    Website* webWindow;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeText()
{
    ui->text->setText("New Text");
    delete webWindow;
}

void MainWindow::on_openButton_clicked()
{
    webWindow = new Website();
    QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
    webWindow->show();
}

website.h

#ifndef WEBSITE_H
#define WEBSITE_H

#include <QDialog>

namespace Ui {
class Website;
}

class Website : public QDialog
{
    Q_OBJECT

public:
    explicit Website(QWidget *parent = 0);
    ~Website();

signals:
    void buttonPressed();

private slots:
    void on_changeButton_clicked();

private:
    Ui::Website *ui;
};

#endif // WEBSITE_H

website.cpp

#include "website.h"
#include "ui_website.h"

Website::Website(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Website)
{
    ui->setupUi(this);
}

Website::~Website()
{
    delete ui;
}

void Website::on_changeButton_clicked()
{
    emit buttonPressed();
}

परियोजना की संरचना:

SOURCES += main.cpp\
        mainwindow.cpp \
    website.cpp

HEADERS  += mainwindow.h \
    website.h

FORMS    += mainwindow.ui \
    website.ui

यूआईएस की रचना पर विचार करें:

  • मुख्य विंडो: "पाठ" नामक एक लेबल और "ओपनबटन" नामक एक बटन
  • वेबसाइट विंडो: "changeButton" नामक एक बटन

तो कीपॉइंट्स सिग्नल और स्लॉट्स और विंडो पॉइंटर्स या संदर्भों के प्रबंधन के बीच संबंध हैं।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow