| |
Programowanie w Qt - kurs
Qt4 intro
Śledziłem uważnie i z pewnym niepokojem zmiany jakie zachodziły w czwartej odsłonie
biblioteki Qt. Początkowo byłem dość niechętnie nastawiony do proponowanych zmian, które wyglądały z
początku dość dziwacznie. Jakkolwiek teraz po napisaniu pierwszej aplikacji zostałem przekonany i w pewnym
sensie zachwycony.
Zanim przejdę do opisywania tego jak tu spłodzić prosty program, chciałbym napomknąć
o drastycznych zmianach jakie zaszły w Qt. Przede wszystkim Trolltech w nowej odłonie biblioteki wycofał
się z edytora kodu w designerze, a co za tym idzie z plików ui.h. Takie posunięcie niesie za sobą w
konsekwencji większą przejrzystość kodu, przynajmniej jeśli chodzi o dziedziczenie klas i relacje pomiędzy
kodem a plikiem ui definiującym wygląd formatki.
Tak więc ogółna koncepcja jeśli chodzi o pliki, projekty i wygląd formatek przedstawia się następująco:
- Oczywiście plik main.cpp, który generuje wszystko.
- Plik ui_<nazwa>.h, generowany przez program uic na podstawie <nazwa>.ui
- Pliki <nazwa>.h i <nazwa>.cpp, które mogą sobie dziedziczyć po czymkolwiek, a dzieki funkcji setupUi przyjmą dowolny wygląd zdefiniowany w designerze.
- Na koniec powstają pliki moc_<nazwa>.cpp i moc_<nazwa>.h, w których siedzi wszystko co jest odpowiedzialne za sygnały i sloty, a pliki te są generowane przez qmake o czym wcale nie musimy wiedziec.
- No i oczywiście z tego wszystkiego powstaje nasza "aplikacja full wypas".
Fajnie prawda ??
Ok, teraz troszke o kompliacji i instalacja, bo są to dość ważne sprawy jeśli w systemie mamy juz jakąś wersję Qt no i do tego jest ona naszą główną. Więc tak: kompilacja trwa... długo. Odpala się ją standardowo ./configure, make, make install. Można tutaj sobie poszaleć, użyć flag procka, dodać prefix, czy też skorzystać z tego co oferuje "./configure --help". Warto wspomieć, że jeśli chcemy korzystać z baz danych to mysimy skompilować sobie odpowiedni plugin. Podaje się tą informację jako parametr wywołania ./configure. Po skompilowaniu pozostaje pytanie: jak to zrobić żeby można było komilować na dwóch wersjach i żeby się one nie gryzły? Można to zrobić na milion sposobów, ja zaprezentuję dwa:
- Tworzymy linki symbliczne w katalogu ~/bin do pliku qmake z Qt4 i nazywamy go q4make. Dzięki temu, polecenie q4make będzie działało tak jakby było zwykłym poleceniem qmake, z tą tylko różnicą, że będzie działało na qt4.
- Tworzymy skrypt do komilacji w qt4, który może wyglądać następująco:
moux@ubuntu:~/bin$ cat ./total
make clean
/usr/share/qt4/bin/qmake -project
/usr/share/qt4/bin/qmake
make
moux@ubuntu:~/bin$
Ok, mamy qt4, designer działa możemy startować z programem...
Designer 4 i tworzenie interfejsu
Uruchamiamy oczywiście designera (tego właściwego, czwartego) i w okienku z wyborem typu okna wybieramy widget. W następnym kroku, żeby nie komplikować sobie tak od razu życia dodamy malutki guziczek (button) do formatki. Opcja drag & drop, czyli przenosimy Push Button z panelu designera na formatkę. Kolejny krok to zapisanie pliku formatki. Dobrym pomysłem będzie zapisanie tego pliku w osobnym folderze przeznaczonym do tego projektu, np. pod nazwą form1.ui.
Kod programu
Omawiany poniżej kod jest absolutnie szkieletowy i skalowalny. Zawiera wszystko to co jest potrzebne, żeby program uruchamiał się, działał i mówił do nas ludzkim głosem.
Plik main.cpp
Absolutny szablon
// main.cpp
#include "form1.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Form1 *window = new Form1(0,0);
window->show();
return window->exec();
}
Zawartość tego pliku doda do naszej aplikacji piekne okienko Form1, którego funkcje i cała mechanikia są zdefiniowane w klasie Form1 w pliku form1.h. Całe wywołanie tej funkcjonalności zawarte w 3 liniach:
- Tworzy obiekt
- Wywołuje funkcje show()
- "Łączy" stan okna z pętlą główną programu
W powyższym kodzie widać także dwie zastanawiające rzeczy "#include <QApplication>" i "#include "form1.h"". Całe to QApplication, pisane z wielkiej litery na początku i bez ".h" na końcu oznacza to samo co "#include <qapplication.h>". Plik QApplication zawiera w sobie taką właśnie linijkę, jakkolwiek wszystkie przykłady podawane przez Qt piszą includy w takiej właśnie formie więc niech tak będzie. Druga linijka w kolejności includuje nam plik, który za chwilę stworzymy.
Pliki form1.cpp i form1.h
W tej części tworzenia aplikacji w Qt4 zajmiemy się tworzeniem mechaniki w jaką wyposarzymy nasz program.
// form1.h
#include "ui_form1.h"
#include <QDialog>
using namespace Ui;
class Form1: public QDialog
{
Q_OBJECT
public:
Form ui;
Form1(QWidget * parent = 0, Qt::WFlags f = 0 );
~Form1(){};
public slots:
void funkcja_przycisku();
};
W zasadzie zwykła definicja klasy dziedziczącej po QDialog, co jest w tym niezwykłego. Po pierwsze linia "#include ui_form1.h". Pisałem wcześniej o tym pliku, teraz przytoczę jego zawartość:
#ifndef UI_FORM1_H
#define UI_FORM1_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QPushButton>
#include <QtGui/QWidget>
class Ui_Form
{
public:
QPushButton *pushButton;
void setupUi(QWidget *Form)
{
Form->setObjectName(QString::fromUtf8("Form"));
Form->resize(QSize(400, 300).expandedTo(Form->minimumSizeHint()));
pushButton = new QPushButton(Form);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setGeometry(QRect(110, 110, 85, 26));
retranslateUi(Form);
QMetaObject::connectSlotsByName(Form);
} // setupUi
void retranslateUi(QWidget *Form)
{
Form->setWindowTitle(QApplication::translate("Form", "Form"));
pushButton->setText(QApplication::translate("Form", "PushButton"));
Q_UNUSED(Form);
} // retranslateUi
};
namespace Ui {
class Form: public Ui_Form {};
} // namespace Ui
#endif // UI_FORM1_H
Dziwny?? Skomplikowany?? Nie ważne, plik ten jest generowany przez Qt i nie musimy znać jego treści ani koncepcji. Jakkolwiek widać, że cały wygląd formatki będzie generowany na podstawie tego co sie stworzyło tutaj. Myślę, że teraz będzie bardziej zrozumiałe to co uczyniłem w linii using namespace UI. Chodzi po prostu o to, aby za każdym razem nie pisać Ui::costam, Ui::costam_innego, Ui::jakas_metoda. Linijka Form ui jest mniej wiecej konsekwencją takiego zastosowania, bez niego wyglądała by tak: Ui::Form ui;.
// form1.cpp
#include "form1.h"
Form1::Form1(QWidget * parent, Qt::WFlags f):QDialog(parent, f)
{
ui.setupUi(this);
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(funkcja_przycisku()));
}
void Form1::funkcja_przycisku()
{
qDebug("void funkcja_przycisku() works fine");
};
I tym sposobem doszliśmy w końcu do sedna sprawy. Mamy tu wszystko to co wcześniej można było pisać w Qt Designerze i jego świętej pamięci edytorze kodu. Cała mechanika programu, a nawet coś więcej. Funkcja ui.setupUi(this) w magiczny sposob z naszego dialogu uczyni dialog designerowy. No, a connect połączy nam sygnał clicked ze slotem maksymalnie prostym funkcja_przycisku(). Jeśli mamy "skrypt" prezentowany powyżej to możemy skompilować całość wydając polecenie total, jeśli nie to wszystkie polecenia z tego skryptu musimy wpisać z palca.
Co dalej ??
Nie ma się co czarować program oprócz wypisania jakichś bzdur na ekranie konsoli (bo żeby był z niego jakiś pożytek musi być odpalony z konsoli) nie robi nic. Jakkolwiek prezentuje zasosowanie, użycie i ogolną koncepcję programowania w zajefajnym Qt4.
PS.
Zapraszam do zgłaszania uwag, komentowania i współpracy.
|
|