Słodk… znaczy, Qt: +Blip = QBlip
Programowanie, to stan umysłu – będę zawsze to powtarzał. Da się to poznać już w pierwszych paru minutach rozmowy z kimś uważającym się za kodera. Naprawdę – konstrukcja używanych funkcji zdaniowych wymienianych przez programistów podczas rozmowy „na temat” jest dość specyficzna i pomimo wcale-nie-takich-trudnych zwrotów – dla zwykłego śmiertelnika jest dość dziwna.
Ale nie o tym chcę napisać. Wspomniałem, że programowanie, to stan umysłu. Czyli zgodnie z definicją, osobnik ów posiadający powinien potrafić zrealizować postawione przed nim zadanie niezależnie od języka.
Z własnego doświadczenia – coś w tym jest. Tak się się stało po bliższej przygodzie z C++ i Qt. Notka trochę filozoficzna.
Przedmiot zwany Programowaniem w C++. Jak to zwykle bywa, laborki, do tego projekt. I ten ostatni, przy prawidłowym napisaniu aplikacji, umożliwiał uzyskanie zaliczenia z całego przedmiotu.
PHP-owiec i C++
Przyznam, że wyzwanie było dość ciekawe. Można powiedzieć, że jest dość sporo różnic między językiem typowanym dynamicznie a typowanym statycznie. Choć pozory mylą – jeśli ktoś pisał już parę lat w PHP i operator === nie jest mu obcy, wraz z praktycznym wykorzystaniem, to – w pewnym sensie – pracował z pewnego rodzaju hybrydą.
A jeśli, siadając do C++, się trochę zapominał, to o dobrych manierach natychmiast przypominał mu kompilator. Czasem też i access violation, co się nieraz zdarzało.
Wracając – z mojego punktu widzenia najbardziej dawało popalić tworzenie międzymordzia (GUI) poprzez WinAPI. Litości, dziesiątki funkcji, parametrów, których składnia miała chyba tylko zwiększyć zarobki programistów, nieraz i dziwnych nazw. Arghhh…
No i ogromnym nieporozumieniem byłoby, gdybym nie wspomniał tu o MFC. Nie bardzo pałam chęcią gadania o MFC, bo jak tylko pomyślę o Visual Studio, o tym, jaki śmietnik robi w systemie podczas instalacji… Ech, teraz nie zasnę, na pewno nie. Developerzy MSVS chyba zapomnieli o regule KISS… Dlaczego dobre IDE nie mogą być pisane po ludzku – Eclipse/NetBeans w Javie, VisualStudio też kobyła…
Szukając jakiegoś remedium, przypomniałem sobie, że obiło mi się kiedyś o uszy coś takiego jak Qt. Fani KDE pewnie teraz przetarli oczy.
Co ciekawe, prowadzący w ogóle nie słyszał o Qt, co mnie zdziwiło…
słodkie?
Po moich dotychczasowych przygodach z C/C++ nie podchodziłem do projektu z jakimś szczególnym entuzjazmem. Jednak perspektywa zwolnienia z egzaminu sukcesywnie popychała do rozgrzebania tematu na części pierwsze i kolejnych prób. Poczytałem trochę na temat Qt z nakierowaniem na fakt, że międzymordzie projektowało się prawie jak w Delphi – graficznie.
Ale nie przesadzajmy, to nie może być wyznacznik wyboru biblioteki (choć na pewno to miało jakiś wpływ).
Urzekło mnie, natomiast, dodawanie obiektów oraz widgetów (w windowsowej nomenklaturze – kontrolek). To było dokładnie to, czego szukałem:
QLabel *label = new QLabel(this);
label->setText("zuo");
this->addChild(label);
Nie dość, że bardziej intuicyjnie, to tego typu forma od razu przypomniała mi zasłyszaną refleksję: jednym z najlepszych jest samodokumentujący się kod. I powyższy, moim zdaniem, spełnia to założenie – patrzę i widzę, co kod robi. No to teraz zobaczmy, jak w MFC wygląda kod realizujący podobną funkcję:
CStatic *lblPresent = new CStatic;
lblPresent->Create(L"Present", WS_CHILD | WS_VISIBLE, CRect(20, 20, 100, 40), this);
Im więcej patrzę na ten kod, tym bardziej czuje się głupi. Hmm, rozpracowując to teraz metodą naukową na-zdrowy-chłopski-rozum: no ok, tworzę sobie obiekt zwany CStatic. Hej, ale po kiego Create, skoro konstruktor już wywołałem? Eeee, muszę go dodatkowo pokazywać, skoro w 90% przypadków ten tekst będę chciał wyświetlić od razu? No cóż, każdy ma swoje własne upodobania, ale zdecydowanie wolę tę pierwszą filozofię wstawiania obiektów.
Wracając do Qt. Zanim zabrałem się do pisania czegokolwiek, postanowiłem przejrzeć listę dostarczanych klas. Złapałem się za głowę. Aż tyle? Jest scyzoryk? Nie ma?
Najlepsze jest to, że większości z nich nie trzeba jakoś specjalnie inicjować. Wystarczy zadeklarowanie zmiennej typu danej klasy. Naprawdę nie trzeba stawać na głowie, żeby np. zapisać ustawienia naszego programu. Wystarczy klasa QSettings, a ona wykona całą brudną robotę polegającą na obsłudze kontenera ustawień (czyli dodawanie, kasowanie, pilnowanie formatu, etc), czy zwracaniu odpowiednich danych na potrzeby naszej aplikacji.
Co najważniejsze, Qt pozwala na uniezależnienie aplikacji od systemu operacyjnego.
puść mi sygnał
Coś, co mnie z początku zdziwiło/zaskoczyło/może i zniesmaczyło, to filozofia sygnałów i slotów. A gdybym zamiast tego powiedział event binding, to czy, drogi javascriptowcu, znajdziemy wspólny język? No pewnie, że się dogadamy.
O ile w MFC są osobne metody dla każdego zdarzenia, to w Qt działamy na zasadzie sygnałów i slotów. Nazwa koszmarna, ale w działaniu równie sympatyczne, co podpinanie akcji w JS. Sygnał, to zdarzenie, slot – handler. Czyli trzeba uwzględnić dość istotny aspekt – sposób projektowania naszego programu musimy uzależnić od tego, że kod danej funkcji/metody nie będzie wykonywany synchronicznie.
Czyli np:
connect(this->worker, SIGNAL(finished(QNetworkReply *)), &this, SLOT(workerReply(QNetworkReply *)));
QNetworkReply *reply = this->worker->get(req);
qDebug() << "asdasd";
nie sprawi, że do okienka debugowania tekst zostanie dodany dopiero po zakończeniu żądania sieciowego. Zostatnie dodany wg wywołania w kodzie. Ma to swoje zalety (m.in. możliwość podpięcia kilku slotów do jednego sygnału, łatwość zmiany zdarzeń), ale też i wady, jak konieczność zagnieżdżania wielu funkcji między sobą. Jeśli zgłębiłeś zagadnienie kolejek animacji w jQuery, to pewnie myślisz teraz o queue()/dequeue(). Dobrze myślisz.
QNetworkReply *reply = this->worker->get(req);
// and force it to be synchronous
QEventLoop eventLoop;
QObject::connect(this->worker, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));
eventLoop.exec();
środowisko
Długo się zastanawiałem nad tym, jakiego środowiska użyć. Visual Studio odpada, DevCpp stare i jakieś toporne, Code::Blocks jakoś mnie nie przekonało. Początkowo, człowiek głupi (czytaj: bez wiedzy), ściąga całe SDK. Jak się okazało, pierwotna głupota jednak popłaciła. W paczce jest, bowiem, twór nazwany QtCreator. Słyszałem kiedyś o graficznym narzędziu do projektowania międzymordzia, ale całym IDE już nie. A to miła niespodzianka.
Zaraz po uruchomieniu, środowisko sprawia bardzo dobre wrażenie - jest po prostu estetyczne.
Na pewno nie jest to jakiś wyznacznik - w końcu Photoshop też na początku wydaje się toporny, ale po nauce jego obsługi - staje się bardzo wygodny.
Qt Creator jest po prostu minimalistyczny. W zupełności wystarczające do napisania jakiejś aplikacji. Sprawia wrażenie dość prostego, ale można się doszukać wszystkich niezbędnych opcji. A najbardziej zaskoczyła mnie wbudowana obsługa Doxygen, Git oraz Mercurial. No i można wszystko rozszerzać wtyczkami.
Moim zdaniem, dużo lepiej została tu rozwiązana kwestia zintegrowania dokumentacji. Jest to po prostu kolejny panel w oknie programu. Szkoda tylko, że nie bardzo się da zmienić jego lokalizację.
Oczywiście podpowiadanie i uzupełnianie kodu musi być. Inaczej by nie można było określić Qt Creatora mianem IDE.
Patrząc na listę wtyczek, nie sposób oprzeć się wrażeniu, że Qt Creator jest czymś w stylu Eclipse - tak naprawdę, to platforma dla rozszerzeń obsługujących konkretne języki/środowiska. Choć QTC brakuje jednak popularności. Szkoda, gdyż środowisko jest bardzo przyzwoite i nie zdarzyło mi się, aby "zamulało" (jak to bywało nieraz w przypadku Eclipse/NetBeans).
I na koniec, kosmetyka środowiska. Delikatne animacje interfejsu po prostu cieszą oko. Na dodatek, nie obciążają procesora.
Niech ktoś zrobi plugina do PHP...
aplikacja na projekt
Nosiłem się kiedyś z zamiarem napisania natywnego klienta Blipa. Postanowiłem połączyć oba zadania - zaliczenie projektu oraz napisanie aplikacji dostępowej do tego serwisu. Udało mi się namówić kolegę z roku, Vandervira i tak zaczęliśmy prace nad QBlipem. I nawet coś zaczęło z tego wychodzić. Zapraszam na stronę QBlipa na Google Code. Źródła na licencji Apache.
Więcej nie ma się chyba co rozpisywać w tym miejscu.
nie wszystko złoto...
Pisanie w Qt ma z pewnością sporo zalet. Ale nie ma ideałów, pora na wady.
- W przypadku Windows, konieczność dystrybuowania DLL-i uruchomieniowych Qt, które trochę zajmują. Za to prawie każdy linuksiarz ma zainstalowane Qt w swoim systemie. W przypadku MFC jest dokładnie na odwrót.
- Niektóre - z punktu widzenia programisty - błahostki są czasem ciężkie do zrealizowania. O ile np. obsługa HTTP jest całkiem przyzwoita, to wysłanie pliku przez POST wymaga ręcznego konstruowania żądania. Ale nie są to jakieś szczególnie męczące problemy.
- Było trochę zachodu z uzyskaniem prawidłowo działających polskich diakrytyków. Jedna linijka zdziałała cudo:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
- Na początku przygody z Qt dość mocno dają popalić błędy z rodziny ld exit status. W 99% przypadków wynika to z braku dołączenia odpowiednich bibliotek w pliku projekt.pro, a konkretniej w linijce
QT += core gui script network
- I na koniec - nie miałem wystarczająco determinacji, ale nie udało mi się zmusić debuggera do współpracy.
O Qt napiszę pewnie jeszcze nieraz, ale mogę z pewnością powiedzieć jedno: Delphi właśnie odeszło w odstawkę.
Planujecie dalszy rozwój QBlip’a czy raczej projekt oddany == koniec imprezy?
W końcu zabrałem się za QT jednak ze względu na pewne z góry ustalone zasady dot. pracy grupowej zostałem skazany na VS09. Pomijając moje zdanie o tym IDE trzeba przyznać, że integracja z QT jest wykonana całkiem przyzwoicie, poza pluginami programista do dyspozycji dostaje QTDesigner i QTLinguist co znacznie ułatwia pracę.