Getting Started on the Commandline/pl

From Qt Wiki
Jump to navigation Jump to search

h1. Pierwsze Kroki w Programowaniu za pomocą Qt

Witaj w świecie Qt - międzyplatformowego zestawu narzędzi do tworzenia graficznego interfejsu użytkownika (GUI). W tym krótkim przewodniku zapoznamy Cię z tajnikami Qt poprzez implementacje prostej aplikacji Notatnika. Po przeczytaniu tego przewodnika powinieneś być gotowym do przejrzenia dostępnych API i ich dokumentacji aby następnie samemu móc odszukać informacje, które będą Ci niezbędne przy tworzeniu twoich własnych aplikacji.

Witaj Notatniku

W naszym pierwszym przykładzie stworzymy prosty edytor tekstu w okienku na pulpicie. Będzie to przykład najprostszego z możliwych programu posiadajacego GUI, napisanego przy pomocy Qt.

http://doc.qt.nokia.com/4.7/images/gs1.png

#include <QApplication>
#include <QTextEdit>

int main(int argv, char *'''args)
{
 QApplication app(argv, args);

 QTextEdit textEdit;
 textEdit.show();

 return app.exec();

p. Przeanalizujmy kod linia po linii. W pierwszych dwóch liniach załączamy pliku nagłówkowe dla klas QApplication i QTextEdit, których to użyjemy w naszym przykładzie. Wszystkie klasy w Qt posiadają pliki nagłówkowe o odpowiadajaćej im nazwie.

p. Linia 6 tworzy objekt QApplication. Obiekt ten zarządza zasobami całej aplikacji i jest niezbędny do stworzenia jakiejkolwiek aplikacji Qt posiadającej GUI. Przekazujemy mu dwa argumenty argv i args, ponieważ Qt może również przyjmować argumenty z linii komend.

p. Linia 8 tworzy obiekt QTextEdit. Edytor tekstu jest elementem wizualnym GUI. W Qt elementy te nazywamy widżetami. Przykładem innych widżetów są paski przewijania, etykiety czy też przyciski wielokrotnego wyboru. Widżet może być również kontenerem dla innych widżetów, dialogiem lub głównym oknem aplikacji.

p. Linia 9 pokazuje edytor tekstu na ekranie we nowym oknie. Ponieważ widżety mogą być również kontenerami ( na przykład klasa QMainWindow zawiera paski narzędzi, menu, pasek statusu i parę innych widżetów) jest możliwym pokazanie pojedynczego widżetu w jego własnym oknie. Widżety są domyślnie niewidoczne, po wywołaniu funkcji show() widżet staje się widoczny.

p. Linia 11 wprowadza obiekt QApplication w jego pętlę zdarzeń. W trakcie działania aplikacji Qt generowane są zdarzenia i przesyłane do widżetów aplikacji. Przykładowymi zdarzeniami są naciśnięcia przycisku myszki lub klawiszy klawiatury. Kiedy wpisujesz tekst w widżecie edytora tekstu otrzymuje on zdarzenia naciśnięć klawiszy dzięki którym może wyświetlić odpowiadające im znaki.

Aby uruchomić aplikację otwórz linię poleceń i przejdź do katalogu zawierającego polik .cpp programu. Następujące komendy zbudują program.

 qmake -project
 qmake
 make

h2. Dowiedz się wiecej table{border:1px solid lightgray}. |{background:lightgray}. Temat |{background:lightgray}. Gdzie? | | Widżety i Geometria Okna |"Widżety Dialogu i Okna":http://doc.qt.nokia.com/application-windows.html* | | Zdarzenia i obsługa zdarzeń | "System zdarzeń":http://doc.qt.nokia.com/eventsandfilters.html |

Dodawanie przycisku Zakończ

W prawdziwej aplikacji będziesz przeważnie potrzebował wiecej niż jednego widżetu. Spróbujmy dodać przycisk QPushButton poniżej edytora tekstu. Przycisk będzie służył do zamykania aplikacji Notatnika (np. poprzez jego naciśnięciu za pomocą myszki).

http://doc.qt.nokia.com/4.7/images/gs2.png

Przyjrzyjmy się uzupełnionemu kodowi:

#include <QtGui>

int main(int argv, char *'''args)
{
 QApplication app(argv, args);

 QTextEdit textEdit;
 QPushButton quitButton("Zakończ");

 QObject::connect(&amp;quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));

 QVBoxLayout layout;
 layout.addWidget(&amp;textEdit);
 layout.addWidget(&amp;quitButton);

 QWidget window;
 window.setLayout(&amp;layout);

 window.show();

 return app.exec();
}

p. Linia 1 dołącza QtGui, który zawiera wszystkie klasy GUI z Qt.

p. W linii 10 zastosowano mechanizm Sygnałów i Slotów aby aplikacja ulegała zakończeniu po naciśnięciu przycisku Zakończ. Slot jest rodzajem funkcji, którą można wywołać w trakcie działania programu używając do tego celu jego nazwy (jako dosłownego stringu). Sygnał jest rodzajem funkcji, który wywołuje wszystkie połączone z nim sloty; nazywamy to połączeniem sygnału do slotu i wyemitowaniem sygnału.

p. quit() jest slotem klasy QApplication, który powoduje zakończenie aplikacji. clicked() jest sygnałem emitowanym przez QPushButton w momencie naciśnięcia. Statyczna funkcja QObject::connect() zajmuje się połączeniem slotu do sygnału. Makra SIGNAL () i SLOT(), które łączą sygnał ze slotem za pomocą ich sygnatur. Musimy również dostarczyć wskaźników na obikety, które będą emitowały i odbierały sygnał.

p. Linia 12 tworzy QVBoxLayout. Jak już wspomnieliśmy widżety mogą zawierać inne widżety. Można wyznaczyć granicę (położenie i wielkość) widżetu potomnego bezpośrednio jednak przeważnie prościej jest użyć do tego celu layoutu. Layout zarządza granicami widżetów potomnych. QVBoxLayout, dla przykładu, układa widżety potomne w pionowym rzędzie.

p. Linie 13 i 14 dodają edytor tekstu i przycisk do layoutu. W linii 17 ustawiamy layout na widżecie.

h2. Dowiedz się wiecej table{border:1px solid lightgray}. |{background:lightgray}. Temat |{background:lightgray}. Gdzie? | | Sygnały i Sloty |"Sygnały i Sloty":http://doc.qt.nokia.com/signalsandslots.html* | | Layouty | "Zarządzanie layoutami":http://doc.qt.nokia.com/4.7/layout.html, "Widżety i layouty":http://doc.qt.nokia.com/4.7/widgets-and-layouts.html, "Przykłady Layoutów":http://doc.qt.nokia.com/4.7/examples-layouts.html | | Widżety dostępne w Qt | "Galeria Widżetów":http://doc.qt.nokia.com/gallery.html, "Przykłady Widżetów":http://doc.qt.nokia.com/4.7/examples-widgets.html |

Tworzenie podklasy QWidget

Kiedy użytkownik chce zamknąć aplikację dobrym pomysłem jest wyświetlenie dialogu z pytaniem czy on/ona na pewno chce ją zamknąć. W tym przykładzie tworzymy podklasę klasy "QWidget":http://doc.qt.nokia.com/4.7/qwidget.html i dodajemy do niej slot, który połączymy do przycisku Quit.

http://doc.qt.nokia.com/4.7/images/gs3.png

Spójrzmy na kod:

class Notatnik : public QWidget
{
 Q_OBJECT

public:
 Notatnik();

private slots:
 void quit();

private:
 QTextEdit *textEdit;
 QPushButton *quitButton;
};

Na samym początku definicji klasy musi znajdować się makro Q_OBJECT, które deklaruje naszą klasę jako QObject (Oczywiście musi również dziedziczyć po QObject). QObject dodaje kilka nowych możliwości do normalnych klas C++. Przykładowo nazwy klasy i jej slotów mogą być teraz sprawdzone podczas działania programu. Możliwe jest również sprawdzenie typów parametrów slotów i wywoływanie ich.

Linia 13 zawiera deklarację slotu quit(). W tym celu korzystamy z makra slots. Slot quit() można teraz podłączać do sygnałów z odpowiadajacą im sygnaturą (czyli w naszym przypadku każdy sygnał, który nie przyjmuje parametrów).

Zamiast układania elementów GUI i łączenia slotów w ciele funkcji main() możemy teraz użyć po prostu konstruktora klasy Notatnik.

Notepad::Notepad()
{
 textEdit = new QTextEdit;
 quitButton = new QPushButton(tr("Quit"));

connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));

QVBoxLayout '''layout = new QVBoxLayout;
 layout->addWidget(textEdit);
 layout->addWidget(quitButton);

 setLayout(layout);

 setWindowTitle(tr("Notepad"));
}

p. Jak można zauwazyć w definicji naszej klasy użyliśmy wskaźników do klas QObject (textEdit i quitButton). Ogólna zasada mówi, iż powinieneś zawsze alokować instancje klasy QObject na stercie i nigdy ich nie kopiować.

p. Następnie użyjemy funkcji tr() na wszystkich stringach które będą widoczne dla użytkownika. Funkcja ta jest niezbędna jeśli zamierzasz przetłumaczyć swoją aplikację na wiecej językó (np. na angielski i chiński). Nie będziemy zagłębiali się w szczegóły dotyczące tłumaczeń aplikacji ale jeśli chcesz dowiedzieć się wiecej skorzystaj z odnośnika z tabeli poniżej.

h2. Dowiedz się wiecej table{border:1px solid lightgray}. |{background:lightgray}. Temat |{background:lightgray}. Gdzie? | | tr() i tłumaczenia |"Instrukcja Qt Linguist":http://doc.qt.nokia.com/linguist-manual.html, "Pisanie Kodu Źródłowego dla Tłumaczeń":http://doc.qt.nokia.com/i18n-source-translation.html,* "Przykład Hello tr()":http://doc.qt.nokia.com/linguist-hellotr.html, "Tłumaczenia w Qt":http://doc.qt.nokia.com/internationalization.html | | QObject i model Qt Object (niezbędne do zrozumienia Qt) | "Model Qt Object":http://doc.qt.nokia.com/object.html | | qmake i system budowania w Qt |"Instrukcja qmake":http://doc.qt.nokia.com/qmake-manual.html |

Tworzenie pliku .pro

Zamiast korzystać z polecenia qmake -project do wygenerowania pliku .pro spróbujemy napisać nasz własny

 HEADERS = notepad.h
 SOURCES = notepad.cpp  main.cpp

Następujące polecenia zbudują naszą aplikację

 qmake
 make

Korzystanie z klasy QMainWindow

Wiele aplikacji skorzysta z możliwości jakie daje nam klasa QMianWindow, która posiada swój własny layout i do której można łatwo dodawać pasek menu, widżety dokujące, pasek narzędzi i pasek statusu. Po środku okna wyświetlanego przez QMainWindow znajduje się obszar, który można wypełnić różnymi widżetami. W naszym przypadku będzie to edytor tekstu.

http://doc.qt.nokia.com/4.7/images/gs4.png

Przyjrzyjmy się nowej definicji klasy Notatnik

#include <QtGui>

class Notepad : public QMainWindow
{
 Q_OBJECT

public:
 Notepad();

private slots:
 void open();
 void save();
 void quit();

private:
 QTextEdit *textEdit;

QAction *openAction;
 QAction *saveAction;
 QAction *exitAction;

QMenu '''fileMenu;
};

p. Dodaliśmy również dwa nowe sloty, które pomogą nam otwierać i zapisywać nasze dokumenty. Zaimplementujemy jej w kolejnej sekcji. Często, w głównym oknie, ten sam slot jest wywoływany przez kilka widżetów. Dobrym przykładem są elementy menu i przyciski w pasku narzędzi. Aby ułatwić sprawę Qt udostępnia nam klasę QAction, której pojedyncze instancje mozemy połączyć do slotu i przykazać do wielu widżetów. Na przykład QMenu i QToolbar mogą utworzyć elementy menu i przyciski narzędzi z tych samych objektów QAction. Zobaczmy jak to działa.

p. Tak jak wcześniej użyjemy konstruktora Notatnika aby utworzyć GUI aplikacji.

Notepad::Notepad()
{
 saveAction = new QAction(tr("&amp;Open"), this);
 saveAction = new QAction(tr("&amp;Save"), this);
 exitAction = new QAction(tr("E&amp;amp;xit"), this);

 connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
 connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));
 connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));

 fileMenu = menuBar()->addMenu(tr("&amp;File"));
 fileMenu->addAction(openAction);
 fileMenu->addAction(saveAction);
 fileMenu->addSeparator();
 fileMenu->addAction(exitAction);

 textEdit = new QTextEdit;
 setCentralWidget(textEdit);

 setWindowTitle(tr("Notepad"));
}

p. Do objektów QAction dodawany jest tekst, który będzie je reprezentował w widżetach, do których je dodamy (w naszym wypadku są to elementy menu). Jeśli chcielibyśmy je dodać do paska narzędzi moglibyśmy również dodać ikonę do każdej z akcji.

p. Kiedy element menu zostanie kliknięty uruchomiona zostanie przypisana mu akcja i odpowiadający jej slot zostanie wywołany.

h2. Dowiedz się wiecej table{border:1px solid lightgray}. |{background:lightgray}. Temat |{background:lightgray}. Gdzie? | | Główne okna i klasy głównego okna |"Główne Okno Aplikacji":http://doc.qt.nokia.com/mainwindow.html, "Przykłądy Głownego Okna":http://doc.qt.nokia.com/examples-mainwindow.html* | | Aplikacje MDI | "QMdiArea":http://doc.qt.nokia.com/qmdiarea.html, "Przykłady MDI":http://doc.qt.nokia.com/mainwindows-mdi.html |

Zapisywanie i wczytywanie

W tym przykładzie zaimplementujemy funkcjonalność slotów open() i save() które dodaliśmy w poprzednim przykładzie.

http://doc.qt.nokia.com/4.7/images/gs5.png

Zacznijmy od sloty open():

 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
 tr("Text Files ('''.txt);;C++ Files ('''.cpp '''.h)"));

 if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::ReadOnly)) {
 QMessageBox::critical(this, tr("Error"),
 tr("Could not open file"));
 return;
 }
 QString contents = file.readAll().constData();
 textEdit->setPlainText(contents);
 file.close();
 }

p. W pierwszym kroku pytamy użytkownika o nazwę pliku, który chce otworzyć. Qt udostępnia nam klasę QFileDialog, która jest dialogiem za pomocą, którego użytkownik wybiera plik. Obrazek powyżej pokazuje wygląd takiego dialogu na Kubuntu. Statyczna funkcja getOpenFileName() wyświetla modalny dialog i zatrzymuje wykonywanie slotu do momentu aż użytkownik wybierze plik. Funkcja zwraca ściężkę do wybranego pliku lub pusty string w przypadku gdy użytkownik anulował dialog. W przypadku gdy otrzymaliśmy nazwę pliku próbujemy go otworzyć za pomocą funkcji open(). Funkcja open() zwraca wartość true jeśli operacja się powiedzie lub false w przeciwnym wypadku. Nie będziemy zajmowali się tutaj obsługą błędów, wiecej informacji na ten temat znajdziesz pod odsyłaczami w tabelce Dowiedz się wiecej na dole tej sekcji. Jeśli plik nie został otwarty użyjemy klasy QMessageBox aby wyświetlić dialog z wiadomością o błędzie (aby dowiedzieć się wiecej przeczytaj opis klasy "QMessageBox":http://doc.qt.nokia.com/qmessagebox.html).

p. Aby odczytać dane z otwartego pliku używamy po prostu funkcji readAll(), która zwraca całą zawartość pliku w postaci QByteArray. Funkcja constData() zwraca dane zawarte w tablicy jako const char, którą to możemy przekazać do konstruktora klasy QString. Zawartość możemy wyświetlić w edytorze tekstu. Następnie zamykamy plik za pomocą funkcji close() zwracając deskryptor pliku z powrotem do systemu operacyjnego.

Przejdźmy teraz do slotu save()

 QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "",
 tr("Text Files ('''.txt);;C++ Files ('''.cpp '''.h)"));

 if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::WriteOnly)) {
 // error message
 } else {
 QTextStream stream(&amp;file);
 stream << textEdit->toPlainText();
 stream.flush();
 file.close();
 }
 }

p. Do zapisania zawartości edytora tekstu do pliku skorzystamy z klasy QTextStream opakowującej obiekt QFile. Strumień tekstowy może zapisywać zawartość QString bezpośrednio do pliku; QFile do zapisu posiada jedynie funkcję write z klasy bazowej QIODevice, która to przyjmuje jedynie surowe dane (char).

== Dowiedz się wiecej table{border:1px solid lightgray}. |{background:lightgray}. Temat |{background:lightgray}. Gdzie? | ==