Mechanizm sygnałów i slotów Oprogramowanie i wykorzystanie stacji roboczych Dr inż. Tomasz Olas olas@icis.pcz.pl Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska Mechanizm sygnałów i slotów umożliwia komunikację pomiędzy obiektami. Sygnał jest komunikatem informujacym, o wystapieniu pewnego zdarzenia. Obiekty z biblioteki Qt emituja ((emit)) sygnał w momencie wystapienia zdarzenia, np. gdy użytkownik nacisnał przycisk (QPushButton) - przycisk emituje sygnał clicked. Slot jest specyficzna metoda obiektu z biblioteki Qt, które może obsługiwać zdarzenie, np. zamykajaca aplikacje Qt (quit z klasy QApplication). Zarówno sygnały, jak i sloty moga posiadać parametry, poprzez które można przekazywać dodatkowe informacje o zaistniałym zdarzeniu. Sygnały można dowolnie łaczyć ze slotami (o ile posiadaja takie same parametry). p. 1/30 Sygnały i sloty - przykład użycia Sygnały i sloty - definicja klasy definicja klasy zawierajacej sygnały i sloty powinna znajdować się w osobnym pliku nagłówkowym (np. myclass.h) class MyClass: public QObject Q_OBJECT public: MyClass(); protected slots: void MySlot(); void MySlot2(int value); signals: void MySignal(); void MySignal2(int value); ; p. 3/30
Sygnały i sloty - deklaracja metod Sygnały i sloty - łaczenie, rozłaczanie Sloty sa zwykłymi metodami (poza faktem, że moga być połaczone z sygnałami) i należy je zdefiniować tak jak zwykłe metody: void MyClass::MySlot()... Sygnały należy jedynie zadeklarować i nie wolno ich definiować (odpowiedni kod zostanie wygenerowany przez narzędzie MOC). Do zgłoszenia (wyemitowania) wystapienia określonego zdarzenia modelowanego przez sygnał służy konstrukcja emit nazwa_sygnału(parametry): emit MySignal();... int a = 10; emit MySignal2(a); Do połaczenia sygnału ze slotem służy statyczna metoda connect z klasy QObject: bool QObject::connect(const QObject* sender, const char* signal, const QObject* receiver, const char* member) Do określenia sygnałów i slotów należy wykorzystać makra SIGNAL() i SLOT(). Przykład: MyClass a; MyClass b; QObject::connect(&a, SIGNAL(MySignal()), &b, SLOT(MySlot())); QObject::connect(&a, SIGNAL(MySignal2(int)), &b, SLOT(MySlot(int))); Do rozłaczania połaczeń sygnałów ze slotami służa metody disconnect z klasy QObject: bool disconnect(const char * signal=0, const QObject* receiver=0, const char * member=0); bool disconnect(const QObject* receiver, const char * member=0); p. 5/30 Sygnały i sloty - kompilacja Makefile i moc Pliki zawierajace definicje klas zawierajacych sygnały i sloty należy przetworzyć narzędziem MOC: moc myclass.h -o myclass_moc.cpp Zostanie w ten sposób wygenerowany dodatkowy plik źródłowy, który należy zlinkować z pozostałymi plikami źródłowymi projektu. Np.: g++ -o myprogram myclass.cpp myclass_moc.cpp -lqt-mt OBJS = main.o mywidget.o mywidget.moc.o all: program %.o: %.cpp g++ $(CXXFLAGS) -c $< %.moc.cpp: %.cpp moc -o $@ $*.h program: $(OBJS) g++ -o program $(OBJS) -lqt-mt clean: rm *.o rm *.moc.o rm *.moc.cpp p. 7/30
Klasa QTimer QTimer - przykład Klasa QTimer służy do generowania zdarzenia QTimerEvent w stałych odstępach czasu. Tworzac obiekt klasy QTimer określamy do którego obiektu będa takie zdarzenia kierowane: QTimer(QObject * parent=0) Użyteczne metody: int start(int msec, bool singleshot = FALSE) void stop() void changeinterval(int msec) Obsługa zdarzenia może zostać zrealizowana przy wykorzystaniu metody QObject::timerEvent(QTimerEvent *), lub poprzez sygnał timeout(). Z jednym obiektem może być zwiazanych dowolna liczba sygnałów.... QTimer *timer = new QTimer(myObject); connect(timer, SIGNAL(timeout()), myobject, SLOT(timerDone())); timer->start(10000, TRUE); QTimer *t = new QTimer( myobject); connect(t, SIGNAL(timeout()), SLOT(processOneThing())); t->start(1000);... p. 9/30 Rysowanie Rysowanie - typowe wykorzystanie Do rysowania służy klasa QPainter. Służy ona do rysowania w obszarach obiektów klas dziedziczacych po klasie QPaintDevice (widgety, ale również obiekty klas QPixmap, QPicture i QPrinter). Do rysowania służy zestaw niskopoziomowych metod klasy QPainter umożliwiajacych rysowanie linii, elips, prostokatów, wpisywanie tekstu, wklejanie rysunków, itp. Standardowo do rysowania wykorzystywany jest normalny układ współrzędnych, ale może on zostać zmodyfikowany przy wykorzystaniu zbioru transformacji. Typowe zastosowanie: Utworzyć obiekt klasy QPainter Ustawić pędzel, sposób wypełnienia, czcionkę, itp. Wywołać metody do rysowania Usunać obiekt klasy QPainter W większości przypadków rysowanie odbywa się przy obsłudze zdarzenie paintevent: void MyWidget::paintEvent(QPaintEvent* e) QPainter paint(this); paint.setpen(qt::blue); paint.drawtext(rect(), AlignCenter, "The Text"); Przy wywyołaniu konstruktora określa się obiekt na którym będa dokonywane operacje rysowania. p. 11/30
QPainter - współrzędne QPainter - ustawienia void MyWidget::paintEvent( QPaintEvent * ) QPainter p( this ); p.setpen( darkgray ); p.drawrect( 1,2, 5,4 ); p.setpen( lightgray ); p.drawline( 9,2, 7,7 ); Czcionka - setfont(const QFont &font), font(), fontinfo(), Pędzel - setbrush(brushstyle style), brush(), Pióro - setpen(const QPen &pen), pen(), Tło (Opaque lub Transparent) setbackgroundmode(bgmode m), backgroundmode(), Kolor tła - setbackgroundcolor(const QColor &c), backgroundcolor(), Pozycja wirtualnego kursora (metoda LineTo - moveto(int x, int y), pos(), Transformacje układu współrzędnych, Obcinanie - setclipping(bool enable), setclipregion(const QRegion &rgn, CoordinateMode m = CoordDevice). p. 13/30 Transformacje układu wpółrzędnych I Macierz transformacji I W klasie QPainter zaimplementowano mechanizm transformacji 2D układu wpółrzędnych. Jest on analogiczny do modelu opisanego w ksiażce Foley & Van Dam i stosowanego w standardzie OpenGL. Składa się on z trzech etapów: określenie transformacji ((transformations)) układu współrzędnych modelu, ustalenie okna ((window)), poprzez które określamy granice widoku we współrzędnych modelu, określenie widoku ((viewport)) we współrzędnych urzadzenia graficznego (projekcja modelu na urzadzeniu). Nie wszystkie wyżej wymienione etapy musza zawsze występować. Przy określaniu transformacji wykorzystywana jest tzw. macierz transformacji ((transformation matrix)). Jest ona wykorzystywana do ustawienia położenia obiektów w modelu. Do modyfikacji macierzy transformacji służa metody: void QPainter::rotate(double a), void QPainter::scale(double sx, double sy), void QPainter::translate(double dx, double dy), void QPainter::shear(double sh, double sv), void QPainter::resetMatrix(). p. 15/30
Transformacje - przykład 1 Macierz transformacji II void Transformation::paintEvent(QPaintEvent* e) QPainter p(this); p.setpen(qt::red); p.drawline(0, 0, 50, 50); p.setpen(qt::darkred); p.drawtext(0, 0, 60, 20, Qt::AlignHCenter Qt::AlignVCenter, "(0,0)"); p.drawtext(50, 50, 60, 20, Qt::AlignHCenter Qt::AlignVCenter, "(50,50)"); p.translate(0, height()); p.rotate(270); p.setpen(qt::blue); p.drawline(0, 0, 50, 50); p.setpen(qt::darkblue); p.drawtext(0, 0, 60, 20, Qt::AlignHCenter Qt::AlignVCenter, "(0,0)"); p.drawtext(50, 50, 60, 20, Qt::AlignHCenter Qt::AlignVCenter, "(50,50)"); p. 17/30 Klasa QMatrix określa dwuwymiarowe transformacje układu współrzędnych. Wykorzystywana jest w tym celu macierz o rozmiarze 3 3: m11 m12 0 m21 m22 0 dx dy 1 Macierz transformacji przekształca punkt na płaszczyźnie na punkt o innych współrzędnych: = m11 x+m21 y+dx y = m22 y+m12 x+dy, x gdzie (x,y) sa współrzędnymi oryginalnego punktu, natomiast współrzędne (x,y ) określaja punkt po transformacji. Macierz transformacji III m11 m12 0 m21 m22 0 dx dy 1 elementy dx i dy macierzy transformacji określaja odpowiednio poziome i pionowe przesunięcie układu współrzędnych, elementy m11 i m22 odpowiadaja za skalowanie po odpowiednio po osi x i y, elementy m12 i m21 określaja poziome i pionowe ścinanie. W klasie QMatrix można bezpośrednio ustawić te wartości: QMatrix(double m11, double m12, double m21, double m22, double dx, double dy), setmatrix(double m11, double m12, double m21, double m22, double dx, double dy). Macierz transformacji - przykład QMatrix m; m.translate(10, -20); m.rotate(25); m.scale(1.2, 0.7); double a = pi/180 * 25; double sina = sin(a); double cosa = cos(a); QMatrix m1(1, 0, 0, 1, 10, -20); QMatrix m2(cosa, sina, -sina, cosa, 0, 0); QMatrix m3(1.2, 0, 0, 0.7, 0, 0); QMatrix m; m = m3 * m2 * m1; p. 19/30
Operacje na macierzach transformacji Ustawienie okna Macierz jednostkowa: 1 0 0 0 1 0 0 0 1 Do załadowania macierzy jednostkowej do aktualnej macierzy transformacji służy metoda void QPainter::resetMatrix(), Metody do operowania na stosie macierzy transformacji: void QPainter::save(), void QPainter::restore(). Ustawiane okno określa granice modelu, którego projekcja będzie wyświetlana na urzadzeniu graficznym. Określajac okno wykorzystujemy współrzędne logiczne (modelu). Do ustawienia okna służa metody: void QPainter::setWindow(int x, int y, int w, int h), void QPainter::setWindow(const QRect & r). Domyślnie współrzędne okna sa takie same jak granice urzadzenia graficznego. p. 21/30 Ustawienie widoku Widok określa położenie i rozmiary prezentowanego modelu na danym urzadzeniu graficznym. Ustalajac widok wykorzystuje się współrzędne urzadzenia graficznego. Do określenia widoku wykorzystuje się metody: void QPainter::setViewport(int x, int y, int w, int h), void QPainter::setViewport (const QRect & r). Domyślne współrzędne widoku sa identyczne z współrzędnymi urzadzenia graficznego. p. 23/30 Transformacje - przykład 2 void Transformation::paintEvent(QPaintEvent* e) QPainter p(this); p.setwindow(-200, -200, 400, 400); p.setviewport(10, 10, width() - 20, height() - 20); p.setbrush(qt::solidpattern); p.drawellipse(-200, -200, 400, 400); p.setfont(qfont("helvetica", 40, QFont::Bold)); p.rotate(-90); for (int i = 1; i <= 12; ++i) p.rotate(30); p.setpen(qpen(qt::white, 3)); p.drawline(190, 0, 200, 0); p.setpen(qpen(qt::yellow, 3)); QString number; number.setnum(i); p.drawtext(150, -20, 40, 40, Qt::AlignHCenter Qt::AlignVCenter, number);
QInputDialog QInputDialog - przykład QString gettext ( QWidget * parent, const QString & title, const QString & label, QLineEdit::EchoMode mode = QLineEdit::Normal, const QString & text = QString(), bool * ok = 0, Qt::WindowFlags f = 0 ), int getinteger ( QWidget * parent, const QString & title, const QString & label, int value = 0, int minvalue = -2147483647, int maxvalue = 2147483647, int step = 1, bool * ok = 0, Qt::WindowFlags f = 0 ), double getdouble ( QWidget * parent, const QString & title, const QString & label, double value = 0, double minvalue = -2147483647, double maxvalue = 2147483647, int decimals = 1, bool * ok = 0, Qt::WindowFlags f = 0 ), QString getitem ( QWidget * parent, const QString & title, const QString & label, const QStringList & list, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags f = 0 ). #include <qapplication.h> #include <qinputdialog.h> #include <unistd.h> int main(int argc, char** argv) QApplication app(argc, argv); bool ok; QString application = QInputDialog::getText(NULL, "Run", "Nazwa programu:", QLineEdit::Normal, QString::null, &ok, 0 ); if (ok == true) execlp(application, application, NULL); p. 25/30 QColorDialog QFontDialog QColor QColorDialog::getColor ( const QColor & initial = Qt::white, QWidget * parent = 0 ), QRgb QColorDialog::getRgba ( QRgb initial, bool * ok = 0, QWidget * parent = 0 ). QFont getfont ( bool * ok, QWidget * parent = 0 ), QFont getfont ( bool * ok, const QFont & initial, QWidget * parent, const QString & caption ). p. 27/30
QMessageBox QFileDialog StandardButton information ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultbutton = NoButton ), StandardButton critical ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultbutton = NoButton ), StandardButton question ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultbutton = NoButton ), StandardButton warning ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultbutton = NoButton ), void about ( QWidget * parent, const QString & title, const QString & text ), void aboutqt ( QWidget * parent, const QString & title = QString() ). QString getopenfilename ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedfilter = 0, Options options = 0 ), QString getsavefilename ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedfilter = 0, Options options = 0 ), QString getexistingdirectory ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), Options options = ShowDirsOnly ), QStringList getopenfilenames ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedfilter = 0, Options options = 0 ). question information warning critical p. 29/30