Nowy adres

Zapraszam na mój nowy dwujęzyczny blog: http://adrianlubik.eu/?lang=pl

Czytaj całość...

Aplikacje Qt4 i mechanizm tłumaczenia

Wstęp

Wiele aplikacji, które używamy na codzień mają interfejs dostępny w języku polskim, choć domyślnie nie zostały w nim napisane. Dzisiaj zajmiemy się mechanizmem tłumaczeń w aplikacjach korzystających z biblioteki Qt4, co - jak się przekonamy - nie jest wcale takie trudne.

Jak to działa?

Metoda działania jest bardzo prosta i można ją podzielić na kilka punktów:

  1. Programista umieszcza wszystkie napisy, które mają być przetłumaczalne w specjalnej metodzie tr().

  2. Programista dodaje kod odpowiedzialny za ładowanie tłumaczeń w funkcji main().

  3. Programista dodaje odpowiednie wpisy dla tłumaczeń w pliku projektu aplikacji.

  4. Programista generuje pliki źródłowe tłumaczeń (.ts).

  5. Osoba tłumacząca uzupełnia plik źródłowy (.ts) przetłumaczonymi komunikatami.

Tajemnicze tr()

Każda klasa, która dziedziczy pośrednio lub bezpośrednio po QObject posiada zaimplementowaną metodę tr() (skrót od translate). Posiada ona następujący prototyp:


QString tr( const char *tekstŹródłowy, const char *komentarz = 0, int n = -1 )


Pierwszy argument jest obowiązkowy i jest nim tekst, który chcemy przetłumaczyć. Drugi to komentarz, który będzie wyświetlany osobie tłumaczącej. Komentarze są bardzo przydatne, ponieważ wiele języków, w tym język polski, posiadają różne formy np. przymiotnika. Jeśli mielibyśmy do przetłumaczenia napis "blue", bylibyśmy zdezorientowani, ponieważ możemy go przetłumaczyć na różne sposoby - np. "niebieski", ale też "niebieska", czy "niebieskie". Dzięki komentarzowi możemy poznać kontekst, w jakim został użyty wyraz oraz czego dotyczy, dzięki czemu możemy jednoznacznie przetłumaczyć komunikat:


tr("blue", "colour of an eye");


Ostatni argument (n) jest liczbą całkowitą dodatnią (n >= 0). Każde wystąpienie w tekście napisu %n zostanie zastąpione przez wartość podanego argumentu n. Na przykład, gdy chcemy uzyskać komunikat informujący o ilości wysłanych wiadomości:


int ileWiadomosci = 3;
tr("Messages sent: %n.", "%n is number of sent messages", ileWiadomosci);

Powyższy komunikat po przetłumaczeniu na język polski będzie wyglądał następująco: Wysłano wiadomości: 3.


Jeśli nasza klasa nie dziedziczy po QObject lub używamy tekstu, który ma być przetłumaczalny np. w funkcji main(), możemy użyć metody tr() poprzedzając ją akcesorem dostępu do klasy QObject, ponieważ ta metoda jest jedną z metod statycznych klasy QObject:


int main(int argc. char *argv[])
{
// Część kodu pominięta

QString napis = QObject::tr("A string");

// Część kodu pominięta
}


Klasa QString

Klasa QString jest podstawową klasą Qt4 do reprezentacji i zarządzania napisami. Posiada wiele przydatnych metod do łatwego manipulowania napisami. Dokładniejszym jej opisem zajmiemy się w kolejnych częściach.



Ładowanie tłumaczeń

Aby załadować tłumaczenia dla odpowiedniego języka będziemu musieli posłużyć się dodatkowymi klasami: QLocale odpowiedzialną za ustawienia językowe oraz QTranslator odpowiedzialną za odszukiwanie przetłumaczonych napisów. Oto niezbędny kod do załadowania pliku z tłumaczeniami:


#include <QApplication>
#include <QLocale>
#include <QTranslator>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QString kodJezyka = QLocale::system().name(); // 1.

QTranslator tlumacz; // 2.
tlumacz.load(QString("NazwaAplikacji_") + kodJezyka); // 3.

app.installTranslator(&tlumacz); // 4.

// Dalsza część kodu...
}

  1. Statyczna metoda system() klasy QLocale zwraca jej instancję (obiekt) zawierający konfigurację językową systemu, zaś metoda name() zwraca kod języka jako napis (QString), czyli dla polskiego będzie to pl_PL

  2. Tworzymy obiekt odpowiedzialny za załadowane tłumaczenia.

  3. Ładujemy plik z tłumaczeniami. Metoda load() jako pierwszy i obowiązkowy argument przyjmuje nazwę pliku do załadowania. Domyślnie plik jest wyszukiwany w katalogu z aplikacją, jednak można podać inną lokację, jako drugi argument metody. Jeśli używanym przez nas językiem byłby polski, to obiekt tlumacz próbowałby załadować plik NazwaAplikacji_pl_PL.qm. Rozszerzenie .qm jest automatycznie dodawane (pliki .qm są binarnymi plikami z tłumaczeniami).

  4. Metoda installTranslator instaluje obiekt tłumacza dla aplikacji. Od tego momentu, jeśli plik z tłumaczeniami został poprawnie wczytany, wszystkie przetłumaczalne napisy będą zastępowane tymi z pliku tłumaczeń. Wspomniana metoda przyjmuje jako argument wskaźnik do obiektu QTranslator.


Modyfikacja pliku projektu


Aby można było automatycznie wygenerować pliki źródłowe tłumaczeń, niezbędna jest modyfikacja pliku projektu naszej aplikacji. Należy w nim dodać zmienną TRANSLATIONS:


TRANSLATIONS += translations/MojaAplikacja_pl.ts \
translations/MojaAplikacja_fr.ts

W powyższym przypadku będziemy mogli wygenerować pliki tłumaczeń dla dwóch języków - polskiego i francuskiego, a pliki tłumaczeń znajdą się w folderze translations (można podać dowolny inny folder, jak również można nie podawać żadnego - wtedy tłumaczenia zostaną wygenerowane w folderze, gdzie znajduje się plik projektu).


Przy okazji możemy zobaczyć, jak można rozdzielać na wiele linii listę argumentów zmiennej - po ostatnim argumencie w linii należy dodać spację i ukośnik, po czym kolejny argument podajemy już w kolejnej linii. Po ostatnim argumencie nie stawiamy już spacji i ukośnika.



Generowanie tłumaczeń

Do generowania tłumaczeń służy narzędzie lupdate, dla którego, jako argument podajemy ścieżkę pliku projektu, dla którego chcemy wygenerować tłumaczenia. Jeśli pliki z tłumaczeniami już istnieją, zostają one zaktualizowane, przy czym stare tłumaczenia nie są usuwane. Tak więc, by wygenerować pliki źródłowe tłumaczeń dla przykładowego projektu MojaAplikacja, przy założeniu, że znajdujemy się w terminalu w folderze tego projektu, wydajemy polecenie:


lupdate ./MojaAplikacja.pro



Tłumaczenie komunikatów

Do przetłumaczenia komunikatów zawarych w pliku źródłowym tłumaczeń służy aplikacja QtLinguist dostarczana razem z Qt4. Dla przykładu posłużymy się prostą aplikacją pobierającą od użytkownika liczbę od 0 do 10, następnie wyświetlającą komunikat z podaną liczbą:


// Plik main.cpp:
#include <QApplication>
#include <QLocale>
#include <QTranslator>
#include <QInputDialog>
#include <QMessageBox>

int main(int argc, char *argv[])
{
QApplication aplikacja(argc, argv);

// Załadowanie tłumaczenia:
QString kodJezyka = QLocale::system().name();
QTranslator tlumacz;
tlumacz.load(QString("Translations_") + kodJezyka);

// Instalacja obiektu tłumacza:
aplikacja.installTranslator(&tlumacz);

// Pobranie danych od użytkownika:
int integer = QInputDialog::getInteger(0, QObject::tr("Books", "Dialog title"),
QObject::tr("How many books have you read last month?"), 0, 0, 10);
// Wyświetlenie komunikatu:
QMessageBox::information(0, QObject::tr("Result"),
QObject::tr("You have read %n book(s) last week.", 0, integer));

return 0;
}

# Plik projektu dla aplikacji Translations:

TEMPLATE = app
TARGET = Translations
CONFIG += qt
QT += gui

SOURCES += main.cpp

# Dodajemy wpis dla polskiego tłumaczenia:
TRANSLATIONS += Translations_pl.ts


Przy założeniu, że projekt nazwaliśmy i zapisaliśmy w folderze Translations, generujemy plik źródłowy tłumaczenia dla naszej aplikacji - będąc w terminalu w folderze projektu:


lupdate ./Translations.pro


Po wygenerowaniu tłumaczenia i uruchomieniu aplikacji QtLinguist (linguist lub linguist-qt4 - w zależności od systemu) otwieramy w niej wygenerowany plik Translations_pl.ts:



  1. Dokowalne okno z listą kontekstów tłumaczeń - kontekst jest nazwą klasy, w której tłumaczenie zostało użyte.

  2. Lista tłumaczeń wybranego kontekstu.

  3. Tekst źródłowy i tekst przetłumaczony.

  4. Okno, w którym zależnie od wybranej zakładki pokazywane są ostrzeżenia o błędach, podgląd kodu źródłowego aktualnego tłumaczenia lub podpowiedzi.


QtLinguist automatycznie sprawdza, czy użyte znaczniki kodu html, klawiszy skrótów, znaki interpunkcyjne na końcu linii się zgadzają. W przypadku, gdy przetłumaczyliśmy komunikat i wszystko się zgadza, obok tłumaczenia na liście pojawia się żółty znak zapytania, który, gdy klikniemy zatwierdza tłumaczenie, jako gotowe. Jeśli coś się nie zgadza, obok tłumaczenia pojawi się czerwony wykrzyknik (jak na zrzucie) - informacja o tym, co się nie zgadza dostępna jest w zakładce ostrzeżenia, lub w podpowiedzi po najechaniu kursorem myszy na tłumaczenie na liście. Walidację poszczególnych rzeczy można wyłączyć, i tak oto po wyłączeniu sprawdzania znaków interpunkcyjnych na końcu linii (poprzez menu Walidacja), wykrzyknik zamieniłby się w znak zapytania i moglibyśmy zatwierdzić tłumaczenie.



Jeśli w napisie, który ma być przetłumaczalny programista dodałby komentarz, byłby on widoczny zaraz pod tekstem źródłowym na niebieskim tle (w naszej przykładowej aplikacji pojawia się jeden komentarz, więc można to łatwo sprawdzić).



Obsługa Lingwisty Qt (QtLinguist) jest bardzo intuicyjna i nie ma potrzeby szczegółowo opisywać wszystkich funkcji. Zainteresowani mogą przejrzeć tutorial Lingwisty Qt po wybraniu odpowiedniej opcji spod menu Pomoc. Należy jeszcze wspomnieć o tłumaczeniach z argumentem liczbowym: Gdy komunikat zawiera liczbę jako argument - w naszym przypadku You have read %n book(s) last week. - Lingwista Qt daje nam możliwość podania różnych form przetłumaczonego tekstu w zależności od wybranego języka. Aby zmienić język dla tłumaczenia na polski wystarczy udać się do pozycji Ustawienia pliku z tłumaczeniami... z menu Edycja. W naszym tłumaczeniu będziemy mogli podać trzy różne formy:


  1. Forma liczby pojedynczej.

  2. Pierwsza forma liczby mnogiej (dla 2, 3, 4 w liczbach, np. dla: 2, 24, 33).

  3. Druga forma liczby mnogiej (pozostałe przypadki, np. dla: 0, 5, 6, 30).


Gotowy plik z tłumaczeniem możemy wydać w postaci binarnego pliku .qm z menu Plik:


  • Wydaj - tworzy finalny plik tłumaczeń w tym samym folderze, w którym znajduje się plik źródłowy

  • Wydaj jako... - tworzy finalny plik tłumaczeń w wybranym przez nas folderze


Po wydaniu tłumaczenia dla naszej przykładowej aplikacji i po jej uruchomieniu, zobaczymy interfejs w języku polskim:

Czytaj całość...

Podstawowe narzędzia Qt4 - qmake.

Wstęp

W poprzedniej części przedstawiłem mechanizm sygnałów i slotów, który bez wątpienia jest jedną z najlepszych cech Qt4. Zanim jednak na dobre przystąpimy do programowania, musimy zapoznać się z podstawowymi narzędziami Qt4, jak na przykład systemem budowania qmake, dzięki któremu będziemy mogli łatwo zarządzać naszymi projektami.



Plik projektu .pro

Qt posiada własny system budowania qmake, który na podstawie plików projektów potrafi wygenerować niezbędne pliki potrzebne do kompilacji na danej platformie, np. w przypadku Linuksa będą to pliki Makefile. Pliki projektów qmake posiadają rozszerzenie .pro, a ich składnia jest bardzo prosta i nikt nie powinien mieć problemów z jej zapamiętaniem. Najlepiej będzie, jeśli posłużymy się przykładem. Załóżmy, że nasz projekt składa się z pięciu plików z kodem źródłowym: PlikNaglowkowy1.h, PlikNaglowkowy2.h, Implementacja1.cpp, Implementacja1.cpp oraz main.cpp. Plik projektu dla nich będzie wyglądał następująco:


# Mój pierwszy projekt "aplikacja.pro".

TEMPLATE = app
TARGET = aplikacja.bin
CONFIG += qt
QT += gui network

HEADERS += PlikNaglowkowy1.h PlikNaglowkowy2.h
SOURCES += Implementacja1.cpp Implementacja2.cpp main.cpp

Jak możemy zobaczyć w pierwszej linijce, komentarze rozpoczynamy znakiem kratki. Komentarz obowiązuje aż do końca linii.



TEMPLATE = app

Słowo kluczowe TEMPLATE służy do wyboru szablonu projektu. Do wyboru mamy:


  • app - szablon dla aplikacji (domyślny)

  • lib - szablon dla biblioteki

  • subdirs - szablon dla projektu zawierającego podprojekty (każdy folder z podprojektem musi zawierać własny plik .pro)


Wybór szablonu jest bardzo ważny, ponieważ w przypadku gdybyśmy chcieli stworzyć bibliotekę, a jako szablon wybralibyśmy szablon dla aplikacji, to podczas kompilacji linker zgłosiłby błąd o braku funkcji main(), która nie występuje w bibliotece.


TARGET = aplikacja.bin



Słowo kluczowe TARGET określa nazwę wynikowego pliku binarnego, czyli w naszym przykładzie plik ze skompilowaną aplikacją będzie nosił nazwę aplikacja.bin. Jeśli podalibyśmy np. bin/aplikacja.bin, wtedy plik wynikowy zostałby utworzony w podfolderze bin




CONFIG += qt
QT += gui network



W tym miejscu określamy dodatkowe moduły biblioteki Qt4, z jakich korzysta nasza aplikacja, a co za tym idzie, z jakimi ma być zlinkowana. W powyższym przykładzie są to odpowiednio QtGui i QtNetwork. Linia CONFIG += qt jest niezbędna w projektach korzystających z Qt4.



Zwróćmy uwagę na operatory = i +=. Pierwszy z nich przypisuje nową wartość do danej zmiennej, drugi natomiast dodaje ją, nie usuwając starych wartości. Spójrzmy na przykład



QT += gui
QT += network


Jak widzimy, dzięki temu jedną instrujcję możemy rozłożyć na dwie oddzielne linie.



HEADERS += PlikNaglowkowy1.h PlikNaglowkowy2.h
SOURCES += Implementacja1.cpp Implementacja2.cpp main.cpp


HEADERS jako wartości przyjmuje nazwy plików nagłówkowych projektu, natomiast SOURCES nazwy plików z implementacją.



Istnieje oczywiście wiele więcej zmiennych dla plików projektów, jednakże nie są one często używane w małych projektach. Zainteresowanych odsyłam do dokumentacji Qt4 (W indeksie: qmake).


Instrukcje warunkowe w plikach projektów

Może zajść taka sytuacja, że dla systemu Mac OS X będziemy posiadali inny plik z implementacją, niż dla Windowsa, czy Linuksa. Z pomocą przychodzą bloki z instrukcjami warunkowymi, dzięki którym możemy zamieścić specjalne instrukcje dla poszczególnych platform.

Na przykład musimy zaimplementować klasę SuperKlasa, jednak implementacja dla systemu Linux będzie się znacznie różniła, niż dla Mac OS X i Windowsa. Tworzymy więc odpowiednie bloki w pliku projektu:


#Instrukcje dla platformy Windows:
win32 {
SOURCES += SuperKlasa_win32.cpp
}

#Instrukcje dla Mac OS X:
macx {
SOURCES += SuperKlasa_osx.cpp
}

#Instrukcje dla Linuksa:
linux* {
SOURCES += SuperKlasa_linux.cpp
}


W zależności od tego na której z platworm będzie budowany projekt, odpowiednie instrukcje zostaną wykonane.


Załóżmy inną sytuację - chcemy sprawdzić, czy w folderze z naszym projektem znajduje się plik main.cpp. W przypadku gdy go nie ma, zgłaszamy błąd. Do wykonania tych operacji posłużą nam funkcje exists() i error():


!exists( main.cpp ) {
error( "Nie odnaleziono wymaganego pliku main.cpp!" )
}


Jak łatwo się domyśleć, wykrzyknik (!) neguje wartość wyrażenia, czyli nasz blok zostanie wykonany, gdy funkcja exists() nie zwróci prawdy. Jeśli chcielibyśmy zgłosić tylko komunikat o braku pliku main.cpp i nie przerywać działania qmake, możemy zamiast funkcji error() użyć funkcję message(). Więcej funkcji zostało opisane w dokumentacji Qt4.


Ready, set, go!

Gdy mamy gotowy plik projektu i chcemy zbudować naszą aplikację, wystarczy w terminalu przejść do folderu zawierającego nasz projekt i wykonać polecenie qmake z pełną nazwą pliku projektu jako argument, np.:



qmake ./aplikacja.pro



Zależnie od platformy zostaną wygenerowane odpowiednie pliki niezbędne do kompilacji naszego programu. Np. na Linuksie zostaną wygenerowane odpowiednie pliki Makefile, dzięki czemu do szczęścia brakuje nam tylko wydanie polecenia make, które rozpocznie kompilację projektu.



Zakończenie

Dzisiaj przedstawiłem najbardziej podstawowe informacje potrzebne do samodzielnego zarządzania projektami. Jutro zajmiemy się mechanizmem tłumaczenia aplikacji, a w kolenjnej części nareszcie rozpoczniemy zabawę z QtCreatorem i już właściwym programowaniem ;)


Czytaj całość...

Wprowadzenie do programowania w C++ z użyciem biblioteki Qt4.

Wstęp

Zaczynając swoją przygodę z programowaniem byłem bardzo rozczarowany tym, że w książce o podstawach C++ są opisywane takie rzeczy, jak proste działania matematyczne – dziwiłem się, jak można tworzyć skomplikowane programy graficzne, jak tu uczą od nowa działań arytmetycznych i logicznych i to na prostych funkcjach. Frajda zaczęła się po poznaniu klas i zakończeniu książki. Słyszałem wiele dobrego o bibliotece Qt, więc chciałem spróbować swoich sił. Próżno szukałem polskich artykułów o programowaniu przy użyciu Qt4, o książkach już nie wspomnę. W ostatnim czasie na naszym rynku pojawiła się jedna pozycja traktująca o WxWidgets i Qt4 – z ciekawości ją kupiłem, ale tyle, co w niej jest, to niestety, a może i stety, zdążyłem się nauczyć sam korzystając z dokumentacji biblioteki oraz z jednego rozdziału jakiejś anglojęzycznej książki. Głównie z powodu niedostatku literatury na ten temat, postanowiłem rozpocząć serię tych artykułów.



Dlaczego Qt4?

Qt4 to zestaw bibliotek, dzięki którym programista może stworzyć aplikacje działające na Linuksie, Mac OS X, Windowsie i innych systemach osbsługiwanych przez Qt bez pisania oddzielnego kodu dla poszczególnych systemów – wystarczy napisać jeden kod i skompilować go pod danym systemem. Dzięki Qt można tworzyć zarówno aplikacje konsolowe, jak i graficzne. Aplikacje graficzne posidają obsługę styli, dzięki czemu można łatwo zmieniać ich wygląd. W Qt znajdziemy moduły odpowiadające za poszczególne funkcje. Poniżej zestawienie ważniejszych modułów w formie tabeli:


Nazwa modułuZastosowanieUwagi
QtCorePodstawowa biblioteka do tworzenia aplikacji konsolowych, zawiera podstawowe klasy Qt.Brak.
QtGuiBiblioteka do tworzenia aplikacji z graficznym interfejsem użytkownika. Zawiera klasy odpowiedzialne za różne elementy interfejsu oraz ich rysowanie.Brak.
QtNetworkBiblioteka implementująca obsługę protokołów sieciowych oraz informacji o interfejsach i adresach sieciowych.Brak.
QtOpenGLBiblioteka odpowiedzialna za obsługę OpenGL. Pozwala na tworzenie elementów interfejsu korzystających z OpenGL.Brak.
QtDBusBiblioteka pozwalająca na komunikowanie się aplikacji z Dbus – systemem komunikacji międyprocesowej, dzięki czemu nasza aplikacja może komunikować się z innymi, jak również odwrotnie.Dbus działa na systemach uniksowych, jednakże powstaje także port na system Windows.
QtSvgBiblioteka odpowiedzialna za wyświetlanie wektorowej grafiki SVG.Brak.
PhononBiblioteka odpowiedzialna za obsługę multimediów.Rodzaje obsługiwanych typów plików zależą od zainstaowanego silnika multimedialnego w systemie (w Linuksie Qt4 domyślnie używa Gstreamera).

Wymienione moduły to tylko część z tych, które oferuje Qt. Niewątpliwą dużą zaletą zestawu bibliotek Qt4 jest dobra i szczegółowa dokumentacja, zawierająca wiele przykładów wykorzystania poszczególnych klas oraz graficzne narzędzia takie jak QtDesigner do intuicyjnego tworzenia interfejsu użytkownika, czy QtAssistant służący do wyświetlania wspomnianej dokumentacji. Kolejnym atutem jest kompilator metaobiektów – to ten mechanizm odpowiada za połączenia sygnałów i slotów (gniazd).


Wymagania od użytkownika

Użytkownik powinien znać podstawy (składnię i podstawowe pojęcia) języka C++ oraz podstawy języka angielskiego, ponieważ dokumentacja, jak i środowisko programistyczne, z którego będziemy korzystać dostępne są tylko w tym języku.



Instalacja

W większości dystrybucji Linuksa, Qt4 znajduje się w repozytoriach, tak więc w menedżerze oprogramowania należy wyszukać qt4 i zainstalować pakiet z przyrostkiem dev lub devel (w zależności od dystrybucji). Należy także mieć zainstalowany kompilator języka C++, zwykle GCC (g++). W przypadku Ubuntu i jego pochodnych wystarczy zainstalować pakiety libqt4-dev i build-essential.



O sygnałach i slotach

Cóż to takiego? To bardzo proste – slot (inaczej gniazdo), to metoda klasy, która może odbierać sygnały. Na przykład: Mamy obiekt oknoGlowne, który jest instancją klasy QMainWindow, a w oknie obiekt przyciskZamknik, który jest instancją klasy QPushButton, a który będziemy używać do zamykania okna. Przycisk po kliknięciu emituje sygnał clicked() (ang. kliknięty). Sygnał ten połączymy ze slotem close() (ang. zamknij) obiektu oknoGlowne. Definiowanie połączenia wygląda następująco:

connect( obiektWysyłającySygnał, SIGNAL(nazwaSygnału(argumenty sygnału)), obiektDocelowy, SLOT(nazwaSlotuObiektuDocelowego(argumenty slotu)) );


Tak więc w naszym przypadku połączenie będzie wyglądało następująco:


connect( przyciskZamknik, SIGNAL(clicked()), oknoGlowne, SLOT(close()) );


Proste, nieprawdaż? Przejdźmy jednak do tego, co można, a co nie można:

  1. Jeden sygnał można połączyć z wieloma slotami.

  2. Sygnał można połączyć z innym sygnałem (ten drugi zostanie wtedy natychmiastowo wyemitowany).

  3. Sygnał może posiadać więcej argumentów, niż slot, który ma odebrać sygnał.

  4. Argumenty sygnału i slotu muszą być tego samego typu.

  5. Nie można połączyć dwóch slotów ze sobą.

  6. Sygnał może mieć więcej argumentów, niż slot (lub sygnał) z którym go łączymy.

  7. Nie można przekazać przez sygnał mniej argumentów, niż wymaga ich slot do którego chcemy połączyć ten sygnał – nie jest to możliwe, bo nie wiadomo, jak wywołać slot (lub inny sygnał) nie podając mu argumentu, który jest wymagany.

  8. Nie można zaimplementować ciała sygnału, jak np. metody – sygnał nie jest metodą, jak slot.


Jak definiować sygnały i sloty?

Aby nasza klasa mogła obsługiwać sygnały i sloty, musi ona dziedziczyć po klasie

QObject (lub innej dziedziczącej po QObject) oraz zawierać makro Q_OBJECT. Slot jest zwykłą metodą klasy, którą musimy zaimplementować. Jednak przy modyfikatorze dostępu danej metody należy dopisać magiczne słowo slots. Na przykład:


class MojaKlasa: public QObject
{
Q_OBJECT //niezbędne, by korzystać z sygnałów i slotów
public:
MojaKlasa() {}; //konstruktor

public slots:
void mojSlot(int x)
{
qDebug() << x; // -wypisuje w oknie terminala
wartość argumentu x

emit mojSygnal1(); // -emituje sygnał mojSygnal1

emit mojSygnal2(x); // -emituje sygnał mojSygnal2
z argumentem x
}

signals:
void mojSygnal1();
void mojSygnal2(int jakasLiczba);
};


Rozgrzewka

Dla rozgrzewki stworzymy pierwszy prosty program, a z tej okazji, że dziś Sylwester, nie będzie to klasyczny Hello world, a Happy New Year ;) Do tego wystarczy nam zwykły edytor tekstu. Tak więc do dzieła – tworzymy plik main.cpp o następującej zawartości:


#include <QtGui> // [1]

int main( int argc, char *argv[] )
{
QApplication aplikacja( argc, argv ); // [2]
QPushButton przycisk( "Happy New Year!" ); // [3]

aplikacja.connect( &przycisk, SIGNAL(clicked()),
&aplikacja, SLOT(quit()) ); // [4]
przycisk.show(); // [5]

return aplikacja.exec(); // [6]
}


Objaśnienia (nawiasy kwadratowe w przykładzie):

  1. Załączamy plik nagłówkowy modułu QtGui. Zamiast dołączać nagłówek całego modułu, moglibyśmy dać nagłówki dla QApplication i QPushButton, bo tylko z tych dwóch klas korzystamy.

  2. Tworzymy obiekt aplikacji. Należy zawsze tworzyć ten obiekt, ponieważ bez niego niektóre klasy Qt nie mogą działać, co może skutkować nieokreślonym zachowaniem aplikacji.

  3. Tworzymy obiekt przycisk, który jest instancją klasy QPushButton. Klasa ta ma kilka konstruktorów, w tym jednym z nich jest użyty przez nas, który pobiera jako argument łańcuch znaków (napis), który ma zostać wyświetlony na przycisku.

  4. Wywołaliśmy aplikacja.connect(), ponieważ connect jest metodą klasy QObject, a QApplication po niej dziedziczy. Jeśli chcielibyśmy połączyć sygnały/sloty w naszej klasie, która dziedziczy po QObject, to wtedy używamy bezpośredniego wywołania metody connect(). Metoda ta pobiera adresy do obiektów, a nie same obiekty, dlatego musieliśmy nazwy naszych obiektów poprzedzić znakiem & - jeśli tworzyli byśmy obiekt na stercie (QPushButton *przycisk = new QPushButton( "Happy New Year" );), zmienna przycisk byłaby wskaźnikiem do tego obiektu i wtedy symbol & jest zbędny (oznaczałby wtedy uzyskanie obiektu znajdującego się pod adresem wskazywanym przez wskaźnik).

  5. Metoda show() wyświetla przycisk na ekranie. QPushButton dziedziczy klasie bazowej dla wszystkich widgetów (inaczej kontrolek) – QWidget. To właśnie w klasie QWidget jest zdefiniowana ta metoda.

  6. Zwracamy wartość, która zostanie zwrócona przez metodę exec() naszej aplikacji. Metoda ta uruchamia główną pętlę zdarzeń aplikacji, dzięki czemu program nie zostaje od razu zakończony tak, jak w przypadku gdybyśmy podali wartość np. 0 zamiast wywołać tę metodę klasy QApplication. Pętla ta jest przerywana przez slot quit(), z którym połączyliśmy sygnał kliknięcia przycisku.

Po zapisaniu pliku w nowym folderze, np. MojaAplikacja, otwieramy terminal, w którym przechodzimy do folderu z zapisanym plikiem main.cpp:


cd /sciezka/do/folderu/MojaAplikacja

Po czym wykonujemy kolejno trzy polecenia (qmake-qt4 w niektórych systemach może występować jako qmake – polecenie z przyrostkiem qt4 występuje w Ubuntu i jego pochodnych):


qmake-qt4 -project
qmake
make

Po pomyślnym skompilowaniu powinien pojawić się plik wykonywalny MojaAplikacja, który możemy uruchomić jak zwykły program poprzez podwójne kliknięcie myszą, lub z terminala, będąc w folderze aplikacji poprzez:


./MojaAplikacja


Zakończenie

Mam nadzieję, że wprowadziłem Was w dość przystępny sposób do programowania obiektowego w C++ z użyciem biblioteki Qt4. W następnej części rozpocznę od wprowadzenia do środowiska programistycznego QtCreator oraz kilku prostych przykładów. W kolejnych częściach będziemy się zagłębiać coraz bardziej w tajniki Qt4.

Czytaj całość...

No i w końcu...

Tak, tak - po wielu miesiącach i podejściach postanowiłem w końcu ruszyć z moim blogiem. Będę się starał pisać językiem przystępnym i poprawnym pod względem gramatycznym, bo choć polonistą nie jestem, to uważam, że język (nie tylko ojczysty) należy szanować, bo jest on narzędziem potężnym, choć wielu z Was może sobie nie zdawać z tego sprawy.

No dobra, ale o czym to będzie? - Trochę o wszystkim, a trochę o niczym ;) Głównie jednak podejmował będę tematykę programowania, czyli tego, co lubię najbardziej. Postaram się nie zaśmiecać prywatnymi wpisami, choć nie mogę obiecać, że takie nie będą się pojawiać wcale.

Czytaj całość...