Prosta apliacja w Qt4

Zanim rozpoczniemy pisanie jakiegokolwiek kodu powinniśmy zajrzeć do dokumentacji. Dostępnej pod adresem http://doc.trolltech.com/. Sama dokumentacja biblioteki qt4 przyda nam się przed i podczas pisania aplikacji. Oprócz udokumentowanych klas znajdują się tak także liczne przykłady,tutoriale czy galerię widgetów.

Co będziemy robić?

Przed rozpoczęciem lektury warto znać pojęcie dziedziczenia ,a także mieć już pewną wprawę w operowaniu C++. Okno w qt4 można stworzyć 'ręcznie' bądź przy użyciu specjalnej aplikacji(qtdesigner) dostarczanej wraz z biblioteką Qt. My zaczniemy od stworzenia ręcznie okna. W projekcie użyjemy komponentów takich jak:
  • QWidget
  • QPushButton
  • QTextEdit
Przystępujemy do tworzenia klasy SimpleApp. Oto simpleapp.h:
class SimpleApp:public QMainWindow
{
      Q_OBJECT

public:
      SimpleApp(QWidget *parent=0);
      ~SimpleApp();


private slots:
     void ShowDial();
     void AddText();


private:
     QWidget * widget;
     QTextEdit * text;
     QPushButton * add_text;
     QPushButton * show_dial;
     	
};
Klasa ta dziedziczy po QMainWindow, klasa ta zapewnia okno dla aplikacji. Q_OBJECT jest to specjalne makro które umożliwi nam korzystanie z własnych slotów i sygnałów(co to jest niebawem się dowiemy). Jeśli chodzi o QWidget jest to podstawowa klasa interfejsu użytkownika przechwytuje ona mysz,dane z klawiatury. Może być także użyty jako kontener dla innych widgetów itp.

Sloty i Sygnały czyli Who is Who?

Sloty i Sygnały są ważnym elementem frameworku qt4. Oto simpleapp.cpp:
SimpleApp::SimpleApp(QWidget *parent):QMainWindow(parent){
	/*widget=new QWidget();
	setCentralWidget(widget);

	text=new QTextEdit();
	add_text=new QPushButton(tr("Add Text"));
	show_dial= new QPushButton(tr("Show Dial"));
	*/
	connect(add_text,SIGNAL(clicked()),this,SLOT(AddText()));
	connect(show_dial,SIGNAL(clicked()),this,SLOT(ShowDial()));

	/*QVBoxLayout *mainLayoutt = new QVBoxLayout();
	mainLayoutt->addWidget(text);
	mainLayoutt->addWidget(add_text);
	mainLayoutt->addWidget(show_dial);
	widget->setLayout(mainLayoutt);*/
}

SimpleApp::~SimpleApp(){}

void SimpleApp::ShowDial(){
	QMessageBox::information(this, tr("jupi"),
                 tr("click ok"));
}

void SimpleApp::AddText(){
	text->clear();
	text->setText("Simple Text");
}
Wykomentowałem to co nas nie interesuje. Sygnały i sloty to sposób komunikacji pomiędzy obiektami, w naszym przypadku znajdujemy się w obrębie jednego obiektu ale oczywiście można się wyobrazić kiedy wykorzystujemy parę obiektów i szukamy sposobu komunikacji między nimi wtedy jest to bardzo wygodne rozwiązanie. Możemy korzystać z wbudowanych slotów i sygnałów,ale możemy także tworzyć własne . Jak to działa? Otóż, Sygnał emitowany gdy wykonamy jakąś czynność np. Klikniemy w przycisk wtedy zostanie wyemitowany sygnał clicked(), przycisk ten będzie za pomocą metody connect połączony z odpowiednim slotem. Ogólnie wygląda to tak:
connect(objekt1,sygnał,obiekt2,slot)
W naszym przypadku jest to:
connect(add_text,SIGNAL(clicked()),this,SLOT(AddText()));
Czyli sygnał z obiektu add_text zostaje połączony z slotem AddText() z obiektu w którym obecnie pracujemy. Możemy sobie wyobrazić że zamiast this wstawiamy jakiś inny obiekt np. Stworzyliśmy obiekt pomarancza (ma on slot AddText() i jest on publiczny tzn. W pliku pomarancza.h powinno być sekcja public slots a nie jak w simpleapp.h private slots), czyli połączenie wyglądało by tak
connect(add_text,SIGNAL(clicked()),pomarancza,SLOT(AddText()));
Może zajść potrzeba wyemitowania sygnału prosto z funkcji. Robi się to np. Tak
//plik pomarancza.h

//jesteśmy w klasie pomarancza

//tworzymy własny slot i sygnał tym razem,nie polegamy na wbudowanych

public slots:
void setval(int val);
signals:
void change(int value);
private:
int myval

//w pliku pomarancza.cpp
void pomarancza::setval(int val){
	myval = val;
	emit change(val);}
następnie tworzymy gdzieś egzemplarze klasy pomarancza:
pomarancza a,b;
connect(&a,SIGNAL(change(int)),&b,SLOT(setval(int)));
a.setval(10);//takie wywołanie ustawi w obiekcie a wartość równą 10 ale także w obiekcie b //ponieważ zostanie wyemitowany sygnał z wartością 10 a zostanie przechwycony przez slot //setval w obiekcie b
Co ciekaw sygnał może być połączony z innym sygnałem:
connect(obiekt1, SIGNAL(//odpowiedni sygnał), this, SIGNAL(//odpowiedni sygnał));
Sygnały i sloty można rozłączać:
disconnect(obiekt1, SIGNAL(//odpowiedni sygnał), obiekt2, SLOT(//odpowiedni sygnał));

Budujemy Dalej

Oto zmodyfikowany simpleapp.cpp:
SimpleApp::SimpleApp(QWidget *parent):QMainWindow(parent){
	widget=new QWidget();//1
	setCentralWidget(widget);

	text=new QTextEdit();//2
	add_text=new QPushButton(tr("Add Text"));
	show_dial= new QPushButton(tr("Show Dial"));
	
	connect(add_text,SIGNAL(clicked()),this,SLOT(AddText()));//3
	connect(show_dial,SIGNAL(clicked()),this,SLOT(ShowDial()));

	QVBoxLayout *mainLayoutt = new QVBoxLayout();//4
	mainLayoutt->addWidget(text);//5
	mainLayoutt->addWidget(add_text);
	mainLayoutt->addWidget(show_dial);
	widget->setLayout(mainLayoutt);//6
}

SimpleApp::~SimpleApp(){}

void SimpleApp::ShowDial(){
	QMessageBox::information(this, tr("jupi"),
                 tr("click ok"));//7
}

void SimpleApp::AddText(){
	text->clear();//8
	text->setText("Simple Text");//9}
1.Tworzymy nowy obiekt QWidget, następnie za pomocą setcentralwidget() ustawiamy nasz obiekt widget jako centralny widget okna(dzięki temu będziemy mogli widzieć efekty naszej pracy,nasz obiekt widget jest w tym przypadku kontenerem dla innych widgetów)
2.Tworzymy pozostałe obiekty
3.Dwa przyciski łączymy z odpowiednimi slotami
4.Tworzymy odpowiedni layout , czym to jest? Różne layouty decydują o ułożeniu innych widgetów(przyciski itp.) na innym widgecie(w naszym przypadku obiekt widget). QVBoxLayout układa nasze widgety pionowo jeden pod drugim.
5.Dodajemy odpowiednie widgety do layoutu
6.ustawiamy naszemu widgetowi odpowiedni layout
7.Tworzymy proste informacyjne okienko które wyskoczy po naciśnięciu przycisku show dial
8.QTextEdit ma slot clear który całkowicie go wyczyszcza z tekstu
9.Teraz dodajemy tekst do naszego obiektu text. Podsumowując po naciśnięciu przycisku Add Text cały tekst w obiekcie text zostaje wyczyszczony a następnie wstawiony inny.
Plik main.cpp jest trywialny:
int main(int argc, char *argv[])
{
      
      QApplication app(argc, argv);
      SimpleApp *aps= new SimpleApp();
      aps->show();
      return app.exec();
}
Tworzymy obiekt SimpleApp i wywołujemy jego metodę show()(odziedziczona po QMainWindow) i wtedy możemy zobaczyć efekty naszej pracy. Po kompilacji ukazuje się naszym oczom o to taki widok.
qtc1

QtDesigner w akcji

QtDesigner działa na zasadzie drag and drop. Po lewej stronie znajduje się panel widżetów. Teraz zrobimy taki sam program jak przedtem ale za pomocą qtdesingera(link do kodu źródłowego przykładu z qtdesignera). Tworzymy nowe okno klikając w Plik(file) następnie opcja nowy(new), z listy wybieramy Main Window. Następnie usuwamy QMnuBar(nie jest on tu potrzebny),czyli na naszej formie klikamy prawym przyciskiem myszki w miejscu gdzie jest napisane wpisz tutaj. Następnie z Panela widżetów przerzucamy na forme wrzucamy(klikamy i przeciągamy na formę wybrany widget) Text Edit, i dwa razy Push Button. Następnie klikamy prawym przyciskiem myszki(w skrócie ppm) na dowolne puste miejsce na formie i wybieramy z listy rozmieść a następnie rozmieść w poziomie. Po tej operacji kilkamy ppm na Text Edit i wybieramy z listy zmień nazwę obiektu, nazwę zmieniamy na text_edit, operacje powtarzamy dla dwóch przycisków Push Button, pierwszy nazywamy add_text , a drugi show_dial. Teraz zmienimy napis na przyciskach ,klikamy ppm na pierwszy i wybieramy zmień tekst wpisujemy Add Text, podobnie postępujemy z drugim przyciskiem teraz wpisujemy Show Dial. Zapisujemy teraz w folderze z naszym kodem źródłowym aplikacji (plik nazywamy simple.ui). Po tym musimy dodać do qmake nasz stworzony plik formatki. Jak? Cóż do zależy od środowiska IDE, w moim linuksowym kdevelop jest to w zasadzie robione automatycznie a konkretniej tworze nowy plik z listy wybieram qt4 Main Window wtedy zostaje automatycznie uruchomiony qtdesigner i dodany plik do qmake(w nowym IDE do qt4 od twórców qt4 jak się orientuje procedura jest podobna ale warto wspomnieć że ich środowisko jest cross-platformowe). Przechodzimy do kodowania, choć QtDesigner posiada wiele opcji ,m.in edytor slotów itp. My jednak nie skorzystamy z tych opcji. W zasadzie kod będzie podobny do poprzedniego, simpleapp.h:
#include "ui_simple.h"//1



class SimpleApp:public QMainWindow ,public Ui::MainWindow//2
{
      Q_OBJECT

public:
      SimpleApp(QWidget *parent=0);
      ~SimpleApp();


private slots:
     void ShowDial();
     void AddText();


private://3
     	
};
Plik simpleapp.h skrócił się dość mocno. 1.To jest bardzo ważne. Z pliku simple.ui zostanie utworzony plik ui_simple.h , oczywiście zostanie to wykonane automatycznie, mówiąc ogólnie konstrukcja wygląda tak kiedy mamy jakiś plik xxx.ui stworzony w qtdesignerze i dodany w qmake wtedy w pliku w którym ma być wykorzystane okno stworzone w qtdesignerze wystarczy wpisać #include „ui_xxx.h”.
2.dziedziczymy po odpowiedniej klasie z pliku ui_simple.h, Choć w pliku ui_simple.h znajduje się klasa o nazwie Ui_MainWindow to zawsze mimo to trzeba stosować konstrukcję Ui::nazwaklasy
3.W zasadzie private można usunąć ale zostawiłem to po to aby było widać że nie musimy już nic dodawać, wszystko jest w klasie odziedziczonej z ui_simple.h.
Plik simpleapp.cpp wygląda następująco:
SimpleApp::SimpleApp(QWidget *parent):QMainWindow(parent){
	setupUi(this);
	connect(add_text,SIGNAL(clicked()),this,SLOT(AddText()));
	connect(show_dial,SIGNAL(clicked()),this,SLOT(ShowDial()));

	
}

SimpleApp::~SimpleApp(){}

void SimpleApp::ShowDial(){
	QMessageBox::information(this, tr("jupi"),
                 tr("click ok"));
}

void SimpleApp::AddText(){
	text_edit->clear();
	text_edit->setText("Simple Text");
}
Jak widać konstruktor znacznie się skrócił. Funkcja setupUi służy do ustawienia interfejsu użytkownika, jako parametr podajemy this(robi się tak zazwyczaj). Teraz warto zajrzeć to pliku ui_simple.h . Gdy tam zajrzymy zobaczymy że add_text i inne widgety są publiczne. Czyli możemy się do nich nawet z różnych klas odwoływać bezpośrednio(oczywiście jeśli damy taką możliwość innym klasą). Reszta w zasadzie jest taka sama. Mówiąc krótko dzięki qtdesignerowi napisaliśmy mniej kodu.

Źródła

Pobierz źródła

Autor: Radosław 'revcorey' Marek
RkBlog

Qt - Tworzenie aplikacji desktopowych, 29 December 2008

Comment article
Comment article RkBlog main page Search RSS Contact