• Nie Znaleziono Wyników

Krótko o sygnałach i slotach

N/A
N/A
Protected

Academic year: 2021

Share "Krótko o sygnałach i slotach"

Copied!
25
0
0

Pełen tekst

(1)

Programowanie w środowiskach RAD

Programowanie w środowiskach RAD

QtCreator, Qt i C++

QtCreator, Qt i C++

Roman Simiński

roman.siminski@us.edu.pl www.siminskionline.pl

Wprowadzenie do programowania w C++ z wykorzystaniem biblioteki Qt

Sygnały i sloty

(2)

Sygnały i sloty — motywacja

Sygnały i sloty — motywacja

Programowanie sterowane zdarzeniami wymaga określenia powiązania pomiędzy elementem generującym zdarzenie a elementem to zdarzenie

obsługującym.

W obrębie pojedynczej aplikacji GUI polega to zwykle na powiązaniu informacji o zdarzeniu związanym z elementem interfejsu, a podprogramem realizującym obsługę tego zdarzenia.

W różnych środowiskach i bibliotekach GUI stosuje się różne metody realizacji takich powiązań. Najpopularniejsze jest przypisywanie podprogramów do

dedykowanych handler'ów obsługi zdarzeń, co mniej lub bardzie bezpośrednio stanowi realizację mechanizmu wywołań zwrotnych (ang. call back).

W Qt zastosowano mechanizm dynamicznego wiązania sygnałów (ang. signals) generowanych przez nadawcę z podprogramami obsługi, zwanymi slotami (ang.

slots).

(3)

Sygnały i sloty — koncepcja

Sygnały i sloty — koncepcja

Sloty i sygnały stanowią podstawę działania GUI, jednak ich zastosowanie nie ogranicza się tylko do zadań związanych z interfejsem.

Sygnały mogą być emitowane przez elementy interfejsu (obiekty Qt), każdy element może emitować wiele sygnałów o różnych nazwach.

(4)

Sygnały i sloty — koncepcja

Sygnały i sloty — koncepcja

Każdy sygnał ma swoją nazwę, nazwy sygnałów mogą się powtarzać w różnych elementach.

Przykładowy sygnał dla klasy QPushButton: clicked

clicked clicked

Sygnał emitowany przez element interfejsu Sygnał emitowany przez element interfejsu

(5)

Sygnały i sloty — koncepcja

Sygnały i sloty — koncepcja

Sygnały wyemitowane przez elementy interfejsu powinny dotrzeć do odpowiednich podprogramów obsługi.

Aby tak się stało, należy powiązać sygnały z podprogramami obsługi.

Void ?calculate() { . . . } Void ?calculate() { . . . } void ?clear() { . . . } void ?clear() { . . . } clicked clicked

Sygnał emitowany przez element interfejsu

(6)

Sygnały i sloty — koncepcja

Sygnały i sloty — koncepcja

Powiązanie sygnał-podprogram obsługi realizuje funkcja connect.

Aby takie powiązanie zadziałało, podprogram obsługi musi slotem — specjalnie zdefiniowaną funkcją składową pewnej klasy.

void ?calculate() { . . . } void ?calculate() { . . . } void clear() { . . . } void clear() { . . . } connect connect connect connect clicked clicked

Sygnał emitowany przez element interfejsu

Sygnał emitowany przez element interfejsu Podprogram obsługiPodprogram obsługi void ?clear() { . . . } void ?clear() { . . . }

(7)

Sygnały i sloty — koncepcja

Sygnały i sloty — koncepcja

Sloty i sygnały są zgodne z koncepcją programowania obiektowego.

Sygnał jest emitowany przez pewien obiekt Qt — najczęściej jest to obiekt klasy

interfejsowej, np. klasy QPushButton.

Slot jest funkcją składową pewnego obiektu Qt — często klasy interfejsowej, np.

klasy reprezentującej okno, ale również klasy niezwiązanej z GUI.

Obiekty klasy QPushButton

Obiekty klasy QPushButton class FuelWin

: public QDialog { Q_OBJECT . . . private slots: void calculate(); void clear(); . . . }; class FuelWin : public QDialog { Q_OBJECT . . . private slots: void calculate(); void clear(); . . . };

(8)

Sygnały i sloty — elementy

Sygnały i sloty — elementy

Nadawca sygnału — obiekt klasy Qt, emituje sygnał o określonej nazwie. Odbiorca sygnału — obiekt klasy Qt, odbiera sygnał poprzez aktywowanie odpowiedniego slotu.

Powiązanie — para sygnał-slot, kojarząca sygnał nadawcy z odbiorcą.

Nadawca

Nadawca

Odbiorca

Odbiorca

Sygnał Slot Emisja Emisja Wywołanie slotu Wywołanie slotu

Powiązanie

Powiązanie

Sygnał Slot Odbiorca Nadawca

(9)

Czym jest slot?

Czym jest slot?

Jest funkcją składową pewnej klasy, zwykle jej rezultatem jest void.

Jest implementowany i może być wywoływany jak zwykła funkcja składowa. Jest deklarowany w odmienny sposób — w sekcji slots klasy:

class JakasKlasa : public QObject { Q_OBJECT . . . public slots: void publicznySlot(); protected slots: void zabezpieczonySlot(); private slots: void prywatnySlot(); . . . };

class JakasKlasa : public QObject

{ Q_OBJECT . . . public slots: void publicznySlot(); protected slots: void zabezpieczonySlot(); private slots: void prywatnySlot(); . . . };

Mechanizm slotów i sygnałów działa dla

obiektów klas pochodnych względem QObject Mechanizm slotów i sygnałów działa dla

(10)

Dlaczego używamy slotów?

Dlaczego używamy slotów?

Slot jest normalną funkcją C++, i może być wywoływany jak każda inna funkcja. Slot tym różni się od zwykłej funkcji, że może być wiązany z sygnałem

(sygnałami), a wywołanie slota jest wynikiem emisji sygnału (sygnałów).

Aby mechanizm slotów i sygnałów działał, konieczne jest wykorzystanie klasy bazowej QObject lub jej pochodnej.

Program qmake aktywuje moc i realizuje odpowiednie przetworzenie slotów i sygnałów do postaci standardowych konstrukcji C++.

(11)

Czym jest sygnał?

Czym jest sygnał?

Sygnał jest komunikatem reprezentowanym w definicji klasy jak deklaracja

funkcji o rezultacie void.

Sygnał ma tylko deklarację, programista nie definiuje sygnału.

Programista pisze nagłówek funkcji-sygnału — nazwa sygnału oraz listę parametrów sygnału.

Programista nie pisze ciała funkcji-sygnału — ciało jest generowane

automatycznie przez moc.

Sygnały definiuje się w sekcji signals:

class JakasKlasa : public QObject {

Q_OBJECT . . .

signals:

void sygnalBezParametrow();

void sygnalZParametrami( int p ); class JakasKlasa : public QObject

{

Q_OBJECT . . .

signals:

void sygnalBezParametrow();

void sygnalZParametrami( int p ); . . .

Mechanizm slotów i sygnałów

działa dla obiektów klas pochodnych względem QObject

Mechanizm slotów i sygnałów

działa dla obiektów klas pochodnych względem QObject

(12)

Emisja sygnałów

Emisja sygnałów

Emisja sygnału realizowana jest przez słowo kluczowe emit, stanowiące rozszerzenie Qt obsługiwane przez moc.

Nadawca emitujący sygnał zazwyczaj nie wie, kto jest jego odbiorą.

Emisja sygnału jest pewnego rodzaju rozgłoszeniem (ang. broadcast) informacji o zaistniałym zdarzeniu.

Emisja sygnału ma konsekwencje — powoduje uaktywnienie slota, o ile jakiś został do sygnału przywiązany.

{ . . . emit clicked(); . . . } { . . . emit clicked(); . . . } { . . . emit clicked(); . . . { . . . emit clicked(); . . . }

(13)

Powiązanie sygnał-slot

Powiązanie sygnał-slot

Powiązanie sygnał-slot realizowane poprzez wywołanie funkcji connect. Ta funkcja zdefiniowana jest w klasie QObject.

Dla elementów GUI projektowanych w systemie QtDesigner, powiązania zapisywane są w odpowiednim pliku opisu unterfejsu *.ui.

Powiązania mogą być ustanawiane i zrywane dynamicznie w czasie działania programu.

QObject::connect( nadawca, SIGNAL( sygnatura ), odbiorca, SLOT( sygnatura ) );

QObject::connect( nadawca, SIGNAL( sygnatura ), odbiorca, SLOT( sygnatura ) );

Ponieważ syntaktycznie sygnały i sloty deklarowane są jak funkcje, ich sygnatury mają postać:

nazwaSygnaluLubSlotu( <lista argumentow> ) nazwaSygnaluLubSlotu( <lista argumentow> )

(14)

Powiązanie sygnał-slot

Powiązanie sygnał-slot

void FuelWin::calculate() { . . . }

void FuelWin::calculate() { . . . } void FuelWin::clear() { . . . }

void FuelWin::clear() { . . . } connect connect connect connect clicked() clicked() Sygnały Sygnały Sloty Sloty

class FuelWin : public QDialog { Q_OBJECT private slots: void calculate(); void clear(); . . . };

class FuelWin : public QDialog

{ Q_OBJECT private slots: void calculate(); void clear(); . . . }; ui->pushButtonCalculate ui->pushButtonClear ui->pushButtonCalculate ui->pushButtonClear

connect( ui->pushButtonCalculate, SIGNAL( clicked() ), this, SLOT( calculate() ) ); connect( ui->pushButtonClear, SIGNAL( clicked() ), this, SLOT( clear() ) );

connect( ui->pushButtonCalculate, SIGNAL( clicked() ), this, SLOT( calculate() ) );

(15)

Powiązanie sygnał-slot, parametry

Powiązanie sygnał-slot, parametry

bool QObject::connect ( senderQObjectPtr, SIGNAL( signalName(argumentList)), receiverQObjectPointer, SLOT(slotName(argumentList)) OptionalConnectionType ); bool QObject::connect ( senderQObjectPtr, SIGNAL( signalName(argumentList)), receiverQObjectPointer, SLOT(slotName(argumentList)) OptionalConnectionType );

Powiązanie sygnał-slot mogą zawierać parametry:

QLabel *label = new QLabel;

QScrollBar *scrollBar = new QScrollBar;

QObject::connect( scrollBar, SIGNAL( valueChanged( int ) ), label, SLOT( setNum( int ) ) );

QLabel *label = new QLabel;

QScrollBar *scrollBar = new QScrollBar;

QObject::connect( scrollBar, SIGNAL( valueChanged( int ) ), label, SLOT( setNum( int ) ) );

Parametry mogą tylko zawierać typy argumentów, nie mogą zawierać nazw:

QLabel *label = new QLabel;

QScrollBar *scrollBar = new QScrollBar;

QLabel *label = new QLabel;

QScrollBar *scrollBar = new QScrollBar;

QObject::connect( scrollBar, SIGNAL( valueChanged( int n ) ),

Błędny zapis Błędny zapis

(16)

Powiązanie sygnał-slot, parametry

Powiązanie sygnał-slot, parametry

Listy parametrów sygnału i slotu powinny sobie odpowiadać — liczbą i typami. Dozwolone jest, gdy sygnał ma więcej parametrów, są one przy aktywowaniu slotu ignorowane.

Sytuacja odwrotna jest niedozwolona — jak mówi dokumentacja: „Qt can ignore

arguments, but not create values from nothing”.

Signals rangeChanged(int,int) rangeChanged(int,int) rangeChanged(int,int) valueChanged(int) valueChanged(int) valueChanged(int) textChanged(QString) clicked() Signals rangeChanged(int,int) rangeChanged(int,int) rangeChanged(int,int) valueChanged(int) valueChanged(int) valueChanged(int) textChanged(QString) clicked() Slots setRange(int,int) setValue(int) updateDialog() setRange(int,int) setValue(int) updateDialog() setValue(int) setValue(int) Slots setRange(int,int) setValue(int) updateDialog() setRange(int,int) setValue(int) updateDialog() setValue(int) setValue(int)   

(17)

Rozłączanie powiązania — funkcja disconnect

Rozłączanie powiązania — funkcja disconnect

bool QObject::disconnect ( senderQObjectPtr, SIGNAL( signalName(argumentList)), receiverQObjectPointer, SLOT(slotName(argumentList)) OptionalConnectionType ); bool QObject::disconnect ( senderQObjectPtr, SIGNAL( signalName(argumentList)), receiverQObjectPointer, SLOT(slotName(argumentList)) OptionalConnectionType );

Odłączenie odłączenie powiązań od wszystkich sygnałów:

disconnect( senderQObjectPtr, 0, 0, 0 );

disconnect( senderQObjectPtr, 0, 0, 0 );

Odłączenie odłączenie powiązań od pewnego sygnału:

disconnect( senderQObjectPtr, SIGNAL( mySignal() ), 0, 0);

disconnect( senderQObjectPtr, SIGNAL( mySignal() ), 0, 0); Odłączenie konkretnego odbiorcy od nadawcy sygnału:

Disconnect( senderQObjectPtr, 0, receiverQObjectPointer, 0); Szczególne przypadki:

(18)

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

QSlider *horizontalSlider QSlider *horizontalSlider

Wykorzystanie standardowych sygnałów i slotów do powiązania elementu QSlider,

QSpinBox jako elementów sterujących przeźroczystością okna.

QSpinBox *spinBox QSpinBox *spinBox

(19)

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Zmiana wartości w obiekcie QSpinBox ma spowodować zmianę pozycji QSlider, zmiana pozycji obiektu QSlider ma spowodować zmianę wartości QSpinBox.

connect connect connect connect zmiana wartości zmiana wartości ustaw wartość ustaw wartość zmiana przeźroczystości

(20)

connect

connect

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Zmiana wartości w obiekcie QSpinBox lub pozycji QSlider ma spowodować zmianę przeźroczystości okna (funkcja setWindowOpacity).

connect connect connect connect zmiana wartości zmiana wartości ustaw wartość ustaw wartość zmiana przeźroczystości

(21)

? connect ?

? connect ?

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Zmiana wartości w obiekcie QSpinBox lub pozycji QSlider ma spowodować zmianę przeźroczystości okna (funkcja setWindowOpacity).

connect connect connect connect valueChanged( int ) setValue( int ) setWindowOpacity( qreal ) setValue( int ) valueChanged( int )

(22)

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {

ui->setupUi(this);

// Powiazanie: zmiana pozycji suwaka zmiana wartosci spinbox'a→ connect( ui->horizontalSlider, SIGNAL( valueChanged( int ) ), ui->spinBox, SLOT( setValue( int ) ) );

// Powiazanie: zmiana wartosci spinbox'a zmiana pozycji suwaka→ connect( ui->spinBox, SIGNAL( valueChanged( int ) ),

ui->horizontalSlider, SLOT( setValue( int ) ) );

// ??? Powiazanie: zmiana wartosci spinbox'a zmiana przezroczystosci→ connect( ui->spinBox, SIGNAL( valueChanged( int ) ),

this, SLOT( setWindowOpacity( qreal ) ) ); }

Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {

ui->setupUi(this);

// Powiazanie: zmiana pozycji suwaka zmiana wartosci spinbox'a→

connect( ui->horizontalSlider, SIGNAL( valueChanged( int ) ), ui->spinBox, SLOT( setValue( int ) ) );

// Powiazanie: zmiana wartosci spinbox'a zmiana pozycji suwaka→

connect( ui->spinBox, SIGNAL( valueChanged( int ) ),

ui->horizontalSlider, SLOT( setValue( int ) ) );

// ??? Powiazanie: zmiana wartosci spinbox'a zmiana przezroczystosci→

connect( ui->spinBox, SIGNAL( valueChanged( int ) ), this, SLOT( setWindowOpacity( qreal ) ) );

}

Niezgodność typów Niezgodność typów

(23)

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

class Dialog : public QDialog {

Q_OBJECT

public:

explicit Dialog( QWidget *parent = 0 ); ~Dialog();

public slots:

void setTransparency( int val ); private:

Ui::Dialog *ui; };

. . .

void Dialog::setTransparency( int val ) {

setWindowOpacity( ( qreal )val / 100 ); }

class Dialog : public QDialog {

Q_OBJECT

public:

explicit Dialog( QWidget *parent = 0 ); ~Dialog();

public slots:

void setTransparency( int val );

private:

Ui::Dialog *ui; };

. . .

void Dialog::setTransparency( int val )

{

setWindowOpacity( ( qreal )val / 100 );

(24)

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Przykład wykorzystania standardowych sygnałów i slotów

Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {

ui->setupUi(this);

// Powiazanie: zmiana pozycji suwaka zmiana wartosci spinbox'a→ connect( ui->horizontalSlider, SIGNAL( valueChanged( int ) ), ui->spinBox, SLOT( setValue( int ) ) );

// Powiazanie: zmiana wartosci spinbox'a zmiana pozycji suwaka→ connect( ui->spinBox, SIGNAL( valueChanged( int ) ),

ui->horizontalSlider, SLOT( setValue( int ) ) );

// Powiazanie: zmiana wartosci spinbox'a zmiana przezroczystosci→ connect( ui->spinBox, SIGNAL( valueChanged( int ) ),

this, SLOT( setTransparency( int ) ) ); }

Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {

ui->setupUi(this);

// Powiazanie: zmiana pozycji suwaka zmiana wartosci spinbox'a→

connect( ui->horizontalSlider, SIGNAL( valueChanged( int ) ), ui->spinBox, SLOT( setValue( int ) ) );

// Powiazanie: zmiana wartosci spinbox'a zmiana pozycji suwaka→

connect( ui->spinBox, SIGNAL( valueChanged( int ) ),

ui->horizontalSlider, SLOT( setValue( int ) ) );

// Powiazanie: zmiana wartosci spinbox'a zmiana przezroczystosci→

connect( ui->spinBox, SIGNAL( valueChanged( int ) ), this, SLOT( setTransparency( int ) ) );

(25)

Dziękuję za uwagę

Dziękuję za uwagę

Pytania? Polemiki?

Teraz, albo:

Cytaty

Powiązane dokumenty

Uwaga: Osoba montująca pompę ciepła powinna połączyć styki przekaźników A i B równolegle (jak na powyższym schemacie) Aby uruchomić pompę wody, należy załączyć przekaźnik

Korzystanie z komputera roboczego podczas prac polowych Napełnianie zbiornika.. Korzystanie z komputera roboczego podczas

1. Gwarancja jakości na sprawne działanie sprzętu udzielana jest przez Ciarko Spółka z ograniczoną odpowiedzialnością Sp. Okulickiego 10, 38-500 Sanok, zwaną dalej Gwarantem

Jeżeli zamek nie jest połączony z tedee bridge możesz zaktualizować oprogramowanie ręcznie przy użyciu aplikacji tedee: ustawienia urządzenia / ogólne / wersja

Przewodnik użytkownika jest dokumentem, który towarzyszy zaworowi od momentu jego budowy i przez cały okres użytkowania, dlatego jest integralną częścią zaworu.. Wymagane

Jeśli w porę nie przerwiemy niewłaściwego zachowania swojego/dziecka wobec psa, to możemy być pewni, że jeśli dojdzie do niebezpiecznej sytuacji, to tylko my - dorośli będziemy

• Niniejszy sprzęt nie jest przeznaczony do użytkowania przez osoby (w tym dzieci) o ograniczonej zdolności fizycznej, czuciowej lub psychicznej, a

Pomoc żywnościowa jest przekazywana osobom najbardziej potrzebującym za pośrednictwem Organizacji Partnerskich Lokalnych jako zestaw artykułów spożywczych