Przed-wstęp:
Już od dawna miałem zamiar zacząć pisać taki tutorial (obok kursu C++, ale ten chyba zacznę jak wyjdzie C++0x). Głównym powodem jest brak takich materiałów w polskiej sieci. Moux nie napisał nic nowego od 4 lat (i nie sądzę żeby miał ochotę to reaktywować). Z kolei Biblioteka Riklaunima traktuje głównie o wykorzystaniu Qt w Pythonie, czyli PyQt4. Drugim powodem jest fakt, że nie ma lepszego sposobu na podniesienie swojej wiedzy jak uczenie innych. Poza tym ten blog, z założenia, ma być blogiem technicznym (poza moimi własnymi pierdołami, które są zabawne lub ważne dla mnie samego) skupionym wokół programowania w C++, Qt czy pokazujące różne zagadnienia z okolic KDE, Linuksa jako takiego, czy mojego własnego fooaudio (uprzedzając pytania: fooaudio się rozwija, powoli (ze względu na moje ostatnie problemy osobiste oraz nadchodzącą sesję), jednak idzie do przodu. I jak na ironię im wolniej idzie tym lepszy kod powstaje. Jednak już niedługo projekt powinien nabrać sensownego tempa i gdzieś w okolicach połowy lipca o nim napiszę).
Na początku kurs będzie obejmował kilka prostych rzeczy (prezentacja kontrolek, ustawianie ich, tworzenie własnych, sygnały i sloty), później zajmę się bardziej zaawansowanymi rzeczami, niekoniecznie związanymi z GUI (aplikacje sieciowe, wielowątkowość, multimedia). Jest także opcja, że jeżeli interesowałby was jakiś konkretny temat, to postaram się go możliwie szybko opisać. Dajcie mi wtedy znać albo w komentarzach, albo przed jid/e-mail (znajdziecie je w dziale „O mnie„). Miłej lektury, mam nadzieję że komuś to się przyda. ;)
Wstęp:
Qt (wymawiane jak angielskie słowo „cute”) jest wieloplatformową biblioteką programistyczną dla C++ (Qt 4.5 jest ostatnią wersją która wspiera oficjalnie język Java). Może być również wykorzystane (dzięki bindingom) w Adzie, Pythonie, PHP, C#, Pascalu, Perlu, Rubym oraz Haskellu. Pierwotnie (w Qt3) głównie jako toolkit od GUI, od Qt4 rozrósł się o kolejne przydatnych modułów. Mamy dzięki temu jednolitą obsługę, dla różnych platform, aplikacji sieciowych, SQL, Svg, multimediów, Xml, struktur danych i wielu innych. W skład Qt wchodzi również kilka aplikacji wspierających programowanie w nim, jak Qt Designer (edytor GUI), Qt Assistant (system pomocy), Qt Linguist (wspierający tłumaczenie aplikacji na wiele języków) oraz QtCreator (całkiem rozbudowane IDE). Wspiera również kilka głównych platform. Od Linuksa (i całą platformę X11, więc aplikacje napisane w Qt można również uruchamiać na systemach BSD oraz Solaris), Windowsa oraz MacOSX, po wbudowanego Linuksa, Windows CE oraz S60. Początkowo rozwijany przez firmę Trolltech (jako ciekawostkę dodam, że Pure-FTPd bazuje na Troll-FTPd napisanym właśnie w Trolltechu), po przejęciu, w czerwcu 2008, przez Nokię, firma została przemianowana na Qt Software.
Qt jest używany przez takie firmy jak ASUS (w Eee PC), AMD, Google (chociaż od czasu przejęcia przez Nokię widać próbę ucieczki od tej platformy), VW, Volvo, Xerox czy Philips. Jednym z najbardziej znanych projektów używających Qt jest KDE.
Mimo początkowych obaw związanych z przejęciem Trolltech przez Nokię, społeczność Open Source bardzo na tym zyskała. Została dodana możliwość licencjonowania Qt na LGPL (czyli większość komercyjnych i zamkniętych aplikacji może teraz, za darmo, bez przeszkód, wykorzystywać Qt). Niedawno zostały również otworzone repozytoria Qt (nieco później również dla S60).
Podstawy:
Najprostsza aplikacja w Qt wygląda tak:
1 2 3 4 5 6 7 8 | #include <QApplication> int main(int argc, char *argv[]) { QApplication app(argc, argv); return app.exec(); } |
Program kompilujemy wydając kolejno polecenia:
1 2 3 | qmake -project qmake make |
Jedynym zadaniem naszej aplikacji jest uruchomić główną pętlę programu (QApplication ma więcej zadań, ale w tej chwili nie jest nam to specjalnie potrzebne) i czekać na jej zakończenie. A że nie mamy jak jej przerwać (poza przerwaniem wykonywania programu w systemie) to sobie chodzi w kółko.
W 1. linijce załączamy nagłówek QApplication. Klasa ta zarządza całą aplikacją napisaną w Qt. W linijce 5. tworzymy obiekt klasy QApplication oraz przekazujemy jej parametry, które są przekazywane do programu (daje nam to zbiór pewnych argumentów wspólnych dla każdej aplikacji, choć przyznam się że nigdy nie miałem potrzeby z korzystania z tego). W linijce 7. następuje wywołanie funkcji która uruchamia główną pętlę naszego nowego programu.
Qt może się wydawać tylko rozbudowaną biblioteką, ale w rzeczywistości (dzięki dodatkowym programom) rozszerza możliwości C++, np. o foreach (foreach pojawi się również w C++0x) czy mechanizm sygnałów i slotów. Służy do tego program moc (Meta Object Compiler), który jako preprocesor przetwarza źródła naszego programu do takiej postaci, żeby były one zrozumiałem dla naszego kompilatora C++. Dodatkowo są jest uic (User Interface Compiler) oraz qmake. Pierwszy pozwala na kompilowanie plików interfejsu (*.ui) a drugi przygotowuje pliki Makefile na podstawie plików projektu (*.pro).
Teraz napiszemy typowy Hello World:
1 2 3 4 5 6 7 8 9 10 11 12 | #include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label("Hello World!"); label.show(); return app.exec(); } |
W 2. linijce dodaliśmy nagłówek z klasą etykiety. W linii 7. utworzyliśmy obiekt naszej etykiety, za argument podając jej napis jaki ma wyświetlać. Natomiast w 9. wywołujemy metodę, która wyświetli nam naszą etykietę. Ktoś mógłby się zdziwić gdzie jest główne okno programu. Każdy widget GUI w Qt dziedziczy po klasie QWidget, przez co, każdy z nich może być traktowany jako osobne okno. O ile nie wskażemy mu jego rodzica oraz wywołamy na nim metodę show() (polecam wykomentować linijkę 9., rekompilować program i zobaczyć co się stanie).
Kompilacja jest taka sama jak w pierwszy przykładzie. Po uruchomieniu naszej aplikacji pojawia nam się okienko z napisem „Hello World!”. Mamy również możliwość zamknięcia naszego programu.
Oczywiście co to by była za etykieta, której nie da się zmienić czcionki:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <QApplication> #include <QLabel> #include <QFont> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label("Hello World!"); QFont font("Verdana", 16, QFont::Bold); label.setFont(font); label.show(); return app.exec(); } |
Załączamy kolejny nagłówek z klasą QFont. W 9. linijce tworzymy obiekt naszej klasy z parametrami (od lewej) nazwy czcionki, jej wielkości oraz czy ma być pogrubiona. Jest możliwość dodania jeszcze jednego parametru, o typie bool, oznaczającego kursywę. W linijce 11. ustawiamy font dla naszej etykiety. Możemy teraz skompilować i uruchomić nasz program. Jak widzimy zmieniła się czcionka naszego napisu.
W sumie to by było na tyle. Następnym razem pobawimy się przyciskami, tworzeniem własnym widgetów oraz slotami i sygnałami.

Zastanawiam sie w jaki sposob sa powiazane widgety label i app? Dlaczego sam label nie dziala jako osobne okno ?:)
Zapomnialem dodac ze kurs wyglada obiecujaco, dzieki z góry za niego ;)
@kali: ależ działa jako osobne okno. W zasadzie każde widget, który nie dziedziczy po innym, może pełnić rolę osobnego okna. A app (obiekt klasy QApplication) pełni (w skrócie) rolę, pętli głównej aplikacji. Obsługuje również wszelakie eventy (jak event zamknięcia okna itp) które pojawiają się w czasie działania aplikacji.
Mialem na mysli ze bez QApplication app(argc, argv); sam label sie nie pokaze r8 ?:)
Nie jestem pewien, czy dobrze mówię, ale to QApplication chyba tworzy proces programu, natomiast QLabel tworzy okno…
Ale nie o tym chciałem pisać – Czemu w tym „typowym programie Hello World” załączamy coś takiego:
#include
??
Ehh, potraktowało chyba te nawiasy kwadratowe jako jakieś tagi…
W każdym razie, czemu w pierwszym include oprócz ‘qapplication’ jest też jakieś ‘/qapplication’??
@kali: a nie mógłbyś sam to przetestować? ;>
Raz, że QApplication jest wymagany do aplikacji graficznych Qt i nie ma sensu się z tym spierać czy kombinować jak by to obejść. A dwa, jak napisałem wcześniej, QApplication dostarcza pętli głównej programu, bez której jedyne co by zrobił to odpalenie się i zamknięcie.
I tak faktycznie się dzieje, tylko w znacznie bardziej brutalny sposób:
QWidget: Must construct a QApplication before a QPaintDevice
Program nieoczekiwanie przerwał pracę.
@Zamro: jest to efekt przenoszenia się na WordPressa, gdzie WP próbowało być mądrzejsze ode mnie i naprawiać mi to co uważało za niezamknięte tagi. Kiedyś toto poprawię.
> Dodatkowo są jest uic (User Interface Compiler)
Mały błąd się wkradł (są jest).
Nie wiem, ja tworzę nowy projekt i niezależnie jaką opcję wybieram to, gdy kopiuję np. ten pierwszy najprostszy program, wklejam go do okna edycji i próbuję skompilować to wyskakują mi błędy i w rezultacie program nie działa:( Proszę o pomoc
Proszę napisać konkretną ścieżkę, co i jak trzeba wybrać, włączyć żeby ten program zaczął działać. Wiecie, taki szczegółowy algorytm jaki pisze student I roku.)
W drugim programie wyskakuje mi blad przy tworzeniu QLabel :<
[code]g++ -c -pipe -g -Wall -W -O2 -D_REENTRANT -DQT_NO_DEBUG -DQT_THREAD_SUPPORT -DQT_SHARED -DQT_TABLET_SUPPORT -I/usr/share/qt3/mkspecs/default -I. -I. -I/usr/include/qt3 -o program.o program.cpp
program.cpp: In function ‘int main(int, char**)’:
program.cpp:7: error: no matching function for call to ‘QLabel::QLabel(const char [13])’
/usr/include/qt3/qlabel.h:166: note: candidates are: QLabel::QLabel(const QLabel&)
/usr/include/qt3/qlabel.h:68: note: QLabel::QLabel(QWidget*, const QString&, QWidget*, const char*, uint)
/usr/include/qt3/qlabel.h:66: note: QLabel::QLabel(const QString&, QWidget*, const char*, uint)
/usr/include/qt3/qlabel.h:65: note: QLabel::QLabel(QWidget*, const char*, uint)
make: *** [program.o] Błąd 1
[/code]
Szukalem tez troche na google i probowalem stworzysz wskaznik: QLabel *label = new QLabel("test");
Ale nic to nie dalo bo znowu jakis blad sie wkradl :<
Moglby ktos mi pomoc?
Wielkie dzięki za napisanie tego kursu. Naprawdę zainteresował mnie tematyką programowania z użyciem Qt.
Witam próbuje kompilować programy z kursu w QT creator i w żaden sposób mi sie to nie udaje. Jestem zielony w temacie moze coś robie źle a nie wiem ?
Wojtek, stwierdzając „nie udaje się” nie umożliwiasz komuś pomocy Tobie. Sprecyzuj, o co Ci chodzi.
Wielkie dzięki za napisanie tego kursu!
Na prawdę, jest super i aż chce się uczyć :)
Mam jednak jedno… bardzo głupie pytanie. Chciałbym wypisać dane w funkcji, normalnie zrobiłbym to za pomocą printf, ale w Qt tak nie idzie zrobić chyba… jak więc to uczynić?
Szukałem, ale jakoś zawsze są jakieś problemy, więc byłbym wdzięczny za poprowadzenie tym razem za rączkę i przykład takiej linijki, którą mogę tak umieścić w funkcji :)
Też nie do końca rozumiem sposób kompilowania przedstawiony w artykule (Też jestem świeżutki w programowaniu). Na przykład kompilując w innym środowisku (typu Dev czy Code::Blocks) kompilator był podpięty pod jedno kliknięcie. Tutaj oczywiście też jest Build and Run…
Jednakże – rozumiem, że sekwencja ‘qmake -project;qmake;make’ jest również odpowiedzialna za kompilację. Gdzie się ją wprowadza?
Drugie pytanie odnośnie kompilacji – czy taka możliwość na surowym pliku *.cpp istnieje? Czy zawsze kompiluje się cały projekt?
Fajnie, że piszesz kurs Qt. Tylko przeoczyłeś bardzo ważną rzecz. W tutorialach dla początkujących w jakiejś kategorii najlepiej jest nie tylko opisywać kod ale i to, w czym on jest pisany i jak jest pisany. Wątpię, że ktoś kto zaczyna w Qt, będzie mieć dobrze opanowany Qt Creator. Miło by było, gdybyś również go opisał. Chyba, że do pisania programów używasz innej aplikacji, to mógłbyś opisać w jaki sposób ty to robisz. Nie napisałeś też nic o instalacji Qt. Wiem, że to proste, ale na pewno kurs stałby się lepszy, gdyby coś takiego miał opisane. Chociażby pobieżnie.
To się nie kompiluje w Qt4:
1.cpp:1:25: error: qapplication: Nie ma takiego pliku ani katalogu
1.cpp: In function ‘int main(int, char**)’:
1.cpp:5: error: ‘QApplication’ was not declared in this scope
1.cpp:5: error: expected ‘;’ before ‘app’
1.cpp:7: error: ‘app’ was not declared in this scope
1.cpp: At global scope:
1.cpp:3: warning: unused parameter ‘argc’
1.cpp:3: warning: unused parameter ‘argv’