Qt signály a sloty

Z GeoWikiCZ
Skočit na navigaci Skočit na vyhledávání

Jednoduché příklady

Widget QPushButton

Do kostry Qt aplikace doplníme tři řádky, které postupně vytvoří objekt typu QPushButton (tlačítko), spojí signál clicked() objektu button se slotem quit() objektu app a zobrazí widget button

#include <QApplication>
#include <QPushButton>

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

    QPushButton* button = new QPushButton("Quit");
    QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit()));
    button->show();
    
    return app.exec();
}

Výsledná minimalistická aplikace obsahuje jediné tlačítko.

Qt push button-quit.png

Stisknutí tlačítka generuje signál clicked(), který je spojen se slotem quit() objektu app, který danou aplikaci ukončí.

Widgety QHBoxLayout, QSpinBox a QSlider

Demo Qt aplikace "Enter Your Age"

Qt Enter Your Age.png

používá mechanismus signálů a slotů pro synchronizaci nastavení hodnot widgetů QSpinBox a QSlider. Umístění grafických prvků v okně aplikace řídí widget QHBoxLayout.

// hlavickove soubory se jmenuji stejne jako prislusne tridy
#include <QApplication>
#include <QSpinBox>
#include <QSlider>
#include <QHBoxLayout>

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

    // hlavni okno aplikace (titulek: zadej svuj vek)
    QWidget* window = new QWidget;
    window->setWindowTitle("Enter Your Age");

    // komponenty pro interaktivni nastaveni hodnoty
    QSpinBox* spinbox = new QSpinBox;
    QSlider*  slider  = new QSlider(Qt::Horizontal);
    spinbox->setRange(0, 130);
    slider ->setRange(0, 130);

    // zmeny v hodnotach komponent jsou vzajemne synchronizovany
    QObject::connect(spinbox, SIGNAL(valueChanged(int)), slider,  SLOT(setValue(int)));
    QObject::connect(slider,  SIGNAL(valueChanged(int)), spinbox, SLOT(setValue(int)));
    spinbox->setValue(35);

    // horizontalni rozmisteni komponent v okne aplikace
    QHBoxLayout* layout = new QHBoxLayout;
    layout->addWidget(spinbox);
    layout->addWidget(slider);
    window->setLayout(layout);

    window->show();

    return app.exec();
}

Třída Counter

Třída Counter (čítač) je definována jako veřejný potomek třídy QObject

#ifndef COUNTER_H
#define COUNTER_H

#include <QObject>

class Counter : public QObject
 {
     Q_OBJECT

 public:
     Counter() { m_value = 0; }

     int value() const { return m_value; }

 public slots:
     void setValue(int value);

 signals:
     void valueChanged(int newValue);

 private:
     int m_value;
 };

#endif // COUNTER_H

Makro Q_OBJECT musí být použito pro každou třídu, která má definovat vlastní Qt signály a sloty. Zdrojový text je zpracován nejprve preprocesorem, výsledkem je standardní C++ kód, který je následně zpracován C++ překladačem.

Návěští public slots: (rozšíření syntaxe C++) uvozuje defininici slotů, které definujeme stejně jako standardní C++ členské funkce (metody). Podobně návěští signals: uvozuje definici signálů, které jsou ale narozdíl od slotů definovány preprocesorem.

Jediné v čem se definice slotů liší od standardních C++ metod je v tom, že příkazem emit emitují signály.

#include "counter.h"

 void Counter::setValue(int value)
 {
     if (value != m_value) {
         m_value = value;
         emit valueChanged(value);
     }
 }

Objek, který emituje signál neví nic o objektech, které jsou registrovány pro přijetí daného signálů. Povšimněte si, že metoda setValue(int) obsahuje podmínku, která zabraňuje emitování signálů v případě, že se stav daného objektu nemění.

Spojení signálů a slotů zajišťuje metoda QObject::connect, kteráv následujícím příkladu spojuje signál emitovaný objektem a a slotem objektu b.

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

int main()
{
    using std::cout;

    Counter a, b;
    QObject::connect(&a, SIGNAL(valueChanged(int)),
                     &b, SLOT  (setValue(int))   );

    cout << "a, b intial values : " << a.value() << "  " << b.value() << "\n";
    b.setValue(333);
    cout << "a, b        values : " << a.value() << "  " << b.value() << "\n";
    a.setValue(12);
    cout << "a, b final  values : " << a.value() << "  " << b.value() << "\n";
}

Uvedený příklad demonstruje, že signály a sloty můžeme používat nejen v grafických widgetech Qt. Výstup dané konzolové aplikace je

a, b intial values : 0  0
a, b        values : 0  333
a, b final  values : 12  12