PROGRAMOWANIE W QT. KURS by moux 2004/2005



Podobne dokumenty
znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

Rys. 1. Główne okno programu QT Creator. Na rysunku 2 oznaczone zostały cztery przyciski, odpowiadają kolejno następującym funkcjom:

Cel: Przypisujemy przyciskom określone funkcje panel górny (Panel1)

Informatyka II. Laboratorium Aplikacja okienkowa

1 Podstawy c++ w pigułce.

Warsztaty AVR. Instalacja i konfiguracja środowiska Eclipse dla mikrokontrolerów AVR. Dariusz Wika

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Tak przygotowane pliki należy umieścić w głównym folderze naszego programu. Klub IKS

5.4. Tworzymy formularze

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

Zacznijmy więc pracę z repozytorium. Pierwsza konieczna rzecz do rozpoczęcia pracy z repozytorium, to zalogowanie się w serwisie:

5.2. Pierwsze kroki z bazami danych

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Czym są właściwości. Poprawne projektowanie klas

Szybka instrukcja tworzenia testów dla E-SPRAWDZIAN-2 programem e_kreator_2

Zadanie 11. Przygotowanie publikacji do wydrukowania

Jak zainstalować i skonfigurować komunikator MIRANDA, aby wyglądał i funkcjonował jak Gadu Gadu Tutorial by t800.

Rozdział 4 KLASY, OBIEKTY, METODY

Utworzenie pliku. Dowiesz się:

Jak przygotować pokaz album w Logomocji

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE

Jak posługiwać się edytorem treści

Programowanie w języku Python. Grażyna Koba

Tworzenie prezentacji w MS PowerPoint

Wybieramy File->New->Project Wybieramy aplikację MFC->MFC Application jak na rysunku poniżej:

Przed rozpoczęciem pracy otwórz nowy plik (Ctrl +N) wykorzystując szablon acadiso.dwt

Temat: Organizacja skoroszytów i arkuszy

5. Kliknij teraz na ten prostokąt. Powinieneś w jego miejsce otrzymać napis. Jednocześnie została wywołana kolejna pozycja menu.

Laboratorium 8 ( Android -pierwsza aplikacja)

KROK 17 i 18. Cel: Tworzymy oddzielne okno - O autorze. 1. Otwórz swój program. 2. Skompiluj i sprawdź, czy działa prawidłowo.

Programowanie obiektowe

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Lista środków trwałych - Środki trwałe. 3 Środki trwałe. 3.1 Lista środków trwałych.

DOKUMENTY I GRAFIKI. Zarządzanie zawartością Tworzenie folderu Dodawanie dokumentu / grafiki Wersje plików... 7

Budowa aplikacji z graficznym interfejsem użytkownika - GUI (Graphic User Interface)

Zaawansowane aplikacje internetowe - laboratorium

WPROWADZENIE DO JĘZYKA JAVA

Wprowadzenie do programowania w języku Visual Basic. Podstawowe instrukcje języka

1. Dockbar, CMS + wyszukiwarka aplikacji Dodawanie portletów Widok zawartości stron... 3

Podstawy Programowania 2

I - Microsoft Visual Studio C++

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Gdy z poziomu programu Delphi otworzysz folder pierwszy program, zauważysz tylko dwa pliki [rys.1]:

CZĘŚĆ A PIERWSZE KROKI Z KOMPUTEREM

Programowanie w środowisku graficznym GUI

Nawigacja po długim dokumencie może być męcząca, dlatego warto poznać następujące skróty klawiszowe

Makropolecenia w Excelu

Zastanawiałeś się może, dlaczego Twój współpracownik,

Przypisy i przypisy końcowe

Arkusz kalkulacyjny EXCEL

Ćwiczenia nr 2. Edycja tekstu (Microsoft Word)

Kalkulator. Programowanie komputerów. Kalkulator możliwe udoskonalenia. Kalkulator. Kalkulator. Kalkulator możliwe udoskonalenia

Tworzenie menu i authoring w programie DVDStyler

Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach?

e-sprawdzian instrukcja programu do sprawdzania wiedzy ucznia przy pomocy komputera (WINDOWS & LINUX)

1 Podstawy c++ w pigułce.

Nagrywamy podcasty program Audacity

Cwiczenie nr 1 Pierwszy program w języku C na mikrokontroler AVR

Stosowanie, tworzenie i modyfikowanie stylów.

Informatyka I : Tworzenie projektu

Wykład 8: klasy cz. 4

Nazwa implementacji: Nauka języka Python wyrażenia warunkowe. Autor: Piotr Fiorek. Opis implementacji: Poznanie wyrażeń warunkowych if elif - else.

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Celem tego projektu jest stworzenie

CLARION 2 - część II Tworzenie aplikacji

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Wprowadzenie do projektu QualitySpy

Zadanie Wstaw wykres i dokonaj jego edycji dla poniższych danych. 8a 3,54 8b 5,25 8c 4,21 8d 4,85

Rozdział 5: Style tekstu

1. Przypisy, indeks i spisy.

Dodawanie grafiki i obiektów

xmlns:prism= c. <ContentControl prism:regionmanager.regionname="mainregion" />

Krótki kurs obsługi środowiska programistycznego Turbo Pascal z 12 Opracował Jan T. Biernat. Wstęp

Forex PitCalculator INSTRUKCJA UŻYTKOWNIKA

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Stawiamy pierwsze kroki

Java pierwszy program w Eclipse «Grzegorz Góralski strona własna

Qt sygnały i designer

Sposoby tworzenia projektu zawierającego aplet w środowisku NetBeans. Metody zabezpieczenia komputera użytkownika przed działaniem apletu.

Galileo v10 pierwszy program

Formatowanie tekstu za pomocą zdefiniowanych stylów. Włączanie okna stylów. 1. zaznaczyć tekst, który chcemy formatować

VinCent Administrator

Ćwiczenie 1 Galeria zdjęć

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

ApSIC Xbench: Szybki start wydanie Mariusz Stępień

SZYBKI START. Tworzenie nowego połączenia w celu zaszyfrowania/odszyfrowania danych lub tekstu 2. Szyfrowanie/odszyfrowanie danych 4

Jak zainstalować szablon allegro?

OPERACJE NA PLIKACH I FOLDERACH

Przykładowa dostępna aplikacja w Visual Studio - krok po kroku

16) Wprowadzenie do raportowania Rave

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Podstawy technologii WWW

Laboratorium 1 - Programowanie proceduralne i obiektowe

Maple i wykresy. 1.1 Najpierw należy się zalogować. Jak to zrobić zostało opisane w moim poprzednim tutorialu.

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Tworzenie szablonów użytkownika

Włączanie/wyłączanie paska menu

Transkrypt:

PROGRAMOWANIE W QT KURS by moux 2004/2005

Wstęp: Dla kogo jest ten kurs??? Podstawowe pytanie i prosta odpowiedź. Kurs ten jest dla wszystkich, którzy "wychowali się" na Windowsie, Delphi albo VBasic'u. Celem autora w wiekszym stopniu jest przekonanie do programowania w Qt, a co za tym idzie na Linuxa niż nauczanie z punktu widzenia merytorycznego. Dlaczego warto?? Dlaczego Qt?? Czy nie wydaje się wam, że windows walczy ze śmiercią?? Czy nie macie przypadkiem, głęboko zakorzenionego przeświadczenia, że system microsoftu jest już totalnie skompromitowany?? Przede wszystkim wirusami (blaster, czarnobyl, dialery), ale także całą tą kampanią przeszukiwania mieszkań (chowaj Windows Do Piwnicy :)))). Czy nie macie przypadkiem takiego gorącego marzenia żeby któregoś dnia przyjść do domu z pracy, czy szkoły, włączyć komputer i nie bać się niespodzianek tylko mieć pewność, że komputer się włączy i będzie działał, aż do wyłączenia?? Czy nie przerażają was ceny komercyjnego oprogramowania, nie mówię tu o windowsie bo 400 zł to nie majątek, ale o Visual Studio, Office czy Photoshopie chodzi o oprogramowanie, bez którego komputer jest tylko kurzącym się meblem?? Jeśli odpowiedź na którekolwiek z postawionych tu pytań brzmi twierdząco to najwyższy czas zaopatrzyć się w system operacyjny LINUX. Co dalej?? Mając linuxa na pewno dojdziesz w końcu do punktu, w którym powiesz: "przydał by mi się program x". No ale niestety nikt jeszcze nie wpadł na to aby napisać x pod linuxa. Powód do załamania nerwowego?? Powrót do windowsa?? Ależ skąd moje panie, czas wziąść się za programowanie... A jeśli chodzi o Qt, no cóż. KDE powstało na bazie Qt. Wszystkie KMaile, Konquerory czy Quanty to Qt. Olbrzymią zaletą Qt jest masa komponentów/klas, które sprawiają, że pisząc program nie musimy myśleć o pewnych podstawowych rzeczach. Nie musimy odkrywać ameryki, ani wywarzać otwartych drzwi. Czytając ten kurs przekonasz się, że Qt posiada wszystko czego można potrzebować do napisania programu i że jedynym zadaniem programisty jest umiejętne połączenie tego wszystkiego. Forma kursu Ponieważ biblioteka Qt bazuje na języku C++ wypadało by ten język znać. Jednak ponieważ autor nie jest zbyt biegły w tym języku, każda lekcja będzie zawierała szczegółowy opis każdego wpisywanego z palca kawałka kodu.

Przygotowanie Przygotowanie rozpoczynamy od zaparzenia mocnej kawy Maxwell House :)))). Ponieważ ten kurs dotyczy programowania w Qt pod linuxem nalezało by się więc zaopatrzyć w ten system operacyjny. Qt jest dostępne również pod wina jednak pisanie w Qt pod ten system operacyjny nie jest zbyt dobrym pomysłem. Na wina jest VB albo Delphi, które nadają się do tego o wiele lepiej. Wracając do tematu: przygotowanie powinno w normalnych przypadkach polegać na zainstalowaniu Linuxa z podstawowym pakietem narzędzi programistycznych włączając w to Qt Designer. Niezbędne będzie więc pakiet qt devel, przynajmniej na początek. Narzędzia Jak już wspomniałem kod będziemy tworzyć w środowisku programistycznym qt designer. Oprócz tego podstawowym wręcz narzędziem będzie program qmake, który służy do generowania skryptu umożliwiającego łatwą kompilację programu. Oczywiście niezbędny będzie również kompilator gcc. Instalacja wszystkich tych rzeczy w dzisiejszych wersjach Linuxa jest dziecinnie prosta więc nie będę się (póki co) nad nią rozpisywał. Dodam tylko, że: "damy radę". Instalacja Są przypadki, gdzie będziemy musieli coś dograć. Zassać z sieci i doinstalować. Opiszę więc dwie zasady jakie należy znać żeby przez to przebrnąc. Instalacja pakietu rpm Jeśli zassany przez nas plik np. qt designer będzie pakietem rpm to, żeby móc go używac należy sobie instalnąć. Jak?? rpm Uvh nazwa_pakietu.rpm Tips: Jeśli instalujemy z Midnight Commandera to mamy do wyboru dwa skróty: Do pakietu rpm można wchodzić tak jak do katalogu. Po wejściu pokaże nam się plik *INSTALL wystarczy go odpalić by rozpocząć instalację. Jeśli plik rpm jest aktualnie podświetlonym plikiem to można z linii poleceń wpisac początek polecenia instalacyjnego rpm Uvh, a następnie użyć kombinacji klawiszy CRTL+J żeby mc automatycznie uzupełnił to czego brakuje w poleceniu. Jeśli instalacja przebiegnie pomyślnie to OK, ale jeśli nie to program rpm wyświetli nam to czego brakuje. Niestety trzeba będzie to doinstalować według juz opisanego sposobu.

Kompilacja i instalacja ze źródeł Bardziej hardkorowa opcja, ale wszystko jest dla ludzi. Źródła programu lub biblioteki przeważnie są rozpowszechniane w postaci pliku *.gz, czyli po prostu spakowanej. Do rozpakowywania słuźy polecenie tar zxf nazwa_pliku.gz. Jednak o wiele prostsze jest uzycie Midnight Commandera. Do pliku *.gz wchodzimy jak do katalogu i jego zawartość możamy skopiowac w dowolne miejsce (F5). Potem według bezproblemowego scenariusza postępujemy tak: polecenia:./configure,./make,./make install... a jeśli będą problemy z instalacją znaczy to, że zostaliśmy wybrani do zgłębienia tajemnicy kompilacji i wogóle budowy systemu operacyjnego Linux TYLKO SIĘ CIESZYĆ. Wymagania Nie będę obwijał w gazete wymagania są... zależne od cierpliwości tego kto będzie się z tymi wymaganiami zmagał. U mnie na PIII600, 256MB z Riva16MB chodzi to wszystko w miarę, więc wszystko koło tego będzie dobre. W dziedzinie softwaru to polecam Linuxa w wersji bardziej idiotoodpornej tj. Aurox może PLD. Chodzi po prostu o to aby czynności związane z przygotowaniem środowiska nie trwały zbyt długo i nie były zbyt skomplikowane. Dobry system opracyjny to taki, który pozwoli użytkownikowi zapomnieć o swoim istnieniu :)))))))). Autor korzysta obecnie (w chwili powstawania kursu) z systemu Aurox 9.4 z kernelem 2.4.22

Qt Designer (3) filozofia pracy Żeby nie błądzić musimy poznać krok po kroku obsługę tego środowiska tj. np. jak od formatki przejść do oprogramowania jakiegoś zdarzenia. Nie jest to trudne, ale "trzeba umieć". Ponadto w lekcji tej napiszemy pierwszy program w Qt Nieśmiertelne "Hello World". Tips Opis postępowania zamieszczony poniżej należy wydrukować i powiesić na ścianie, ewewntualnie nauczyć się na pamięć. Zawiera on opis "krok po kroku" co trzeba zrobić aby powstał program. "Krok po kroku" 1. Odpalamy Qt Designera np. poleceniem "designer". 2. W oknie "Qt Designer New/Open" wybieramy C++ Projekt i "OK" 3. W oknie "Project Setting", klikamy "...", tworzymy nowy folder w katalogu domowym o nazwie takiej jak program, np. helloworld. Jako nazwę pliku tez wpisujemy hellowolrd.pro. 4. Wybieramy "File" > "New" > "Dialog" 5. Klikamy kombinację klawiszy CTRL+E czyli przełączamy widok na edycję kodu źródłowego. Na pytanie czy chcesz storzyć plik ui.h odpowiadamy "YES". 6. Wybieramy "File" > "Save All" i zapisujemy plik opisujący wygląd formatki (form1.ui) w folderze przeznaczonym na projekt np. o nazwie "helloworld" 7. Wybieramy "File" > "New" > "C++ Main". "OK". 8. Wybieramy "File" > "Save All". W tym momencie zapisujemy plik "main.cpp". 9. Uruchamiamy terminal w katalogu z programem i wpisujemy z palca po kolei qmake, make,./helloworld Jeśli po wpisaniu tej ostatniej komendy naszym oczkom ukaże się pusta forma znaczy, że jesteśmy w domu i możemy iść na piwo. Jeśli natomiast polecenie make pokaże jakieś błędy to najpierw krzyczymy na cały głos, a potem piszemy obraźliwego emaila do autora. Opanowanie powyższych kroków jest absolutnie najważniejsze, tak więc jeśli jakiś krok jest niezrozumiały piszcie do mnie postaram się odpowiadać jak najszybciej. Jeśli polecenie qmake zwórci błędy oznaczać to będzie, że albo nie jesteśmy w katalogu z programem albo nie ma tam pliku "main.cpp". Normalnie pusty projekt przed kompilacją powinien się składać z trzech plików: form1.ui, helloworld.pro, main.cpp. Modyfikacja programu dodajemy bajery Wybieramy menu "Edit" > "Slots" i w okienku, które sie pojawi klikamy "New function". Opis wypełnienia okna znajduje się na obrazku:

Jako kolejny krok dodajemy przycisk do formy. Jest to stosunkowo proste więc pomijam zagłębianie się w szczegóły. Następnie: "Edit" > "Connections" > "New": wypełniamy według następującej kolejości. Sender: pushbutton1 Signal: clicked() Receiver: Form1 Slot: saycheese()

Jeszcze przed kompilacją mała kosmetyka. Klikamy dwukrotnie na przycisku i wpisujemy w oknie, które się pojawi np. say cheese. Przechodzimy teraz do edycji kodu. Window > "Edit Form1". W oknie, które się pojawi powinna już być implementacja funkcji saycheese (jeśli nie ma wróć do początku). Całość kodu powinna wyglądać następująco: #include <qmessagebox.h> void Form1::saycheese() QMessageBox sch ( "My name is first progz", "I say cheese for you", QMessageBox::NoIcon, QMessageBox::Ok, 0, 0 ); sch.exec(); Po skompilowaniu "make" i odpaleniu "./helloworld" powinien pokazac nam się potworek w stylu poniższego.

Zabawa ze stringami Zanim zaczniesz czytać ten rozdział upewnij się, że opanowałeś do perfekcji procedury związane z przygotowaniem programu, tj. stworzenie projektu, pliku głównego programu oraz kompilowanie stworzonego kodu. Rozdział ten pomija już te fragmenty tworzenia oprogramowania przy pomocy Qt Designera. Każdy programista na pewno stanie kiedyś lub już stanął przed trudnym problemem analizy, zarządzania, rozbijania, scalania i mówiąc bardziej ogólnie modyfikowania stringów. Czym wobec tego są stringi? Są to ciągi znaków, które najczęściej są do programu wprowadzane czy to z palca czy z pliku tekstowego. Cały problem ze stringami polega na tym, że należy je konwertować często wielokrotnie. Po za tym jest to jeden z najbardziej popularnych formatów danych. Do obsługi stringów w Qt służą dwie klasy QChar i Qstring, które obudowują standardowy typ języka C++ char i tablice znakowe. Klasy te zawierają w sobie wiele przydatnych funkcji, dzięki którym możemy zapomnieć o takich elementach modyfikowania stringów jak wyciągnięcie jakiegoś znaku/znaków czy też obliczenia długości itd. Dla prostego przećwiczenia tego co napisałem powyżej proponuję stworzyć nowy projekt według przepisu z lekcji drugiej i umieścić na nim jedno pole textedit, jedno pole lineedit oraz przycisk pushbutton. Następnie stworzyć slota o nazwie np. obliczrozm(). W następnej kolejności podpinamy tegoż slota do zdarzenia wciśnięcia przycisku i przełączamy widok do edycji kodu CTRL+E. W edytorze kodu wystarczy wkleić poniższy kod aby obliczyć ilość znaków w polu tekstowym: void Form4::napiszcos() QString dl = textedit3 >text(); lineedit3 >settext( QString::number( dl.length() ) ); Krótkie wyjaśnienie powyższego kodu: QString dl = textedit3 >text(); Jak można się domyślić jest to przypisanie do nowo utworzonej zmiennej zawartości pola textedit3. Przy okazji wtrącę małą dygresję. Poniższy kod można było z takim samym powodzeniem umieścić w jednej linii jednak podejście takie utrudnia znajdowanie błędów w programach. lineedit3 >settext ( QString::number ( dl.length() );

Po pierwsze za pomocą funkcji settext ładujemy do zmiennej text obiektu lineedit3 to co jest w nawiasie. W nawiasie mamy użytą funkcję length() pochodzącą z klasy QString, ponieważ funkcja ta zwraca wartość liczbową int musimy ją skonwertować do postaci znakowej co umożliwia nam funkcja numer. Dociekliwy czytelnik powinien w tym miejscu spytać O CO CHODZI z tymi zmiennymi funkcjami i z tym zapisem raz ::, a innym razem.. Zapis z podwójnym dwukropkiem jest dość prosty do zrozumienia gdyż wskazuje nam na to, że odwołujemy się bezpośrednio do funkcji znajdującej się wewnątrz klasy w tym przypadku QString. Zapis z jedną kropką mówi natomiast, że wywołujemy funkcję z wewnątrz klasy w której się aktualnie znajdujemy. Jednak program, który oblicza długość pola tekstowego to było by trochę mało musimy więc go trochę rozbudować. Ponieważ jest to dopiero początek kursu, a szkoda by było pisać kolejnego hello worlda, proponuję zrobić programik, który zakoduje nasz adres e mail, tak abyśmy mogli go stosunkowo bezpiecznie umieszczać na naszych stronach WWW (chodzi tu o zabezpieczenie antyspamowe). Idea programu została zaczerpnięta ze strony internetowej www.nospam pl.net polega ona na tym, że znaki adresu internetowego są konwertowane na swoje reprezentacje heksadecymalne co nie robi różnicy przeglądarce, a jedynie programom skanującym sieć w poszukiwaniu zbłąkanych adresów e mail, na które (i z których) można wysyłać SPAM. Do programu będziemy potrzebować znów dwóch pól tekstowych jednego textedit'a i jednego lineedit'a no i oczywiście jakiegoś ładnego pushbutton'a. Po dodaniu komponentów musimy utworzyć slota, a następnie podpiąć go no zdarzenia clicked(). Po tym wszystkim proponuję użyć poniższego kodu: void Form2::doitnow() textedit4 >settext( doitnow2(lineedit4 >text()) ); // linia ta do pola tekstowego textedit4 wstawia // tekst przetworzony przez funkcję doitnow2() QString Form2::doitnow2(const QString & input) const // pierwsze QString mówi o typie zwracanym przez funkcję QString r = input; // do zmiennej r przypisujemy wartość podaną jako // parametr wywołania funkcji int i, x = r.length(); // deklarujemy zmienne i oraz x // do zmiennej x przypisujemy długość zmiennej r // czyli stringa podanego w parametrze wywołania funkcji

r = ""; // zerujemy zmienną r, tj. przypisujemy do niej pusty string for (i=0;i<=x;i++) if (!(int)input[i] == 0) // jeśli znak o numerze [i] ze stringa input jest // różny od 0, to wykonujemy poniższe r.append ( "&#" ); // dodajemy do stringa r początek htmlowy r.append( QString::number( (int)input[i] ) ); // dodajemy do tegoż stringa numeryczną reprezentację znaku r.append ( ";" ); // zakańczamy stringa return r; // wartość zwracana przez tą funkcję trafia do pola tekstowego. Całość powinna wyglądać tak: Tekst znajdujący się w polu opisanym jako crypted można skopiować i wstawić do strony WWW. Przeglądarki zinterpretują to prawidłowo jednak programy spamerskie nie dadzą rady.

Program bardziej złożony kalkulator Za pomocą tego tekstu będzemy mogli przećwiczyć ponownie sposób tworzenia aplikacji w Qt Designerze, a także przećwiczymy tworzenie GUI. W tym tekście stworzymy sobie prosty kalkulatorek. Pierwsze kroki po raz drugi Opiszę jeszcze raz sposób tworzenia projektu, szerszy opis znajduje się w poprzednim artykule, tutaj rozpiszę to tylko dla przypomnienia. 1. Gdy Qt Designer się uruchomi w Oknie "New" wybieramy "C++ project" 2. Zapisujemy projekt do osobnego katalogu "kalk", po nazwą "kalk.pro". 3. Wybieramy menu "New" i z okienka wskazujemy Widget 4. Zapisujemy formatkę pod nazwą mfrmcalc.ui 5. Ponownie wybieramy menu New lecz tym razem wskazujemy main.cpp 6. Zapisujemy wszystko i jak na razie wystarczy. Tworzenie GUI Aby nasz kalkulator wyglądał jakoś po ludzku, musimy na wstawiać na niego przyciski z cyferkami. Wykonuje się to w prosty sposób, klikając najpierw na przycisk w Toolboxie Common Widget, a następnie na formatce. Sugerowany wygląd zamieszczam ponieżej: Przyciski oznaczone cyframi mają ustawiony parametr width na 50, cała reszta jest ustawiona na oko. Proponuję jeszcze ustawić parametr ReadOnly komponentu lineedit na TRUE. Ponadto ustawimy jeszcze tekst tego komponentu na "0", tak aby zaraz po uruchomieniu nasz kalkulator się wyzerował. Ustawimy też właściwość halign na AlignRight, dla lepszego efektu. To co przed chwilą stworzyliśmy nie jest jeszcze zbyt dobrym punktem wyjścia do rozpoczęcia pisania kodu. Musimy jeszcze nadać imiona naszym dzieciom czyli przyciskom, tak aby nie zginąć zbyt szybko w gąszczu pushbuttonx. Nasze przyciski numeryczne nazwiemy według poniższego klucza przycisk 9 pb9, przycisk 8 pb8 itd. Przyciski działań: podzielić pbdiv, pomnożyć pbmulti, dodać pbadd, odjąć pbta. Przycisk kropki pbdot, zmiany znaku pbchar, potęga pbpote, pierwiastek pbpierw, no a wynik niech się nazywa pbwynik. Kasowanie niech się nazywa pbc. Tworzenie slotów Jak widać mamy tutaj 19 przycisków, będziemy więc potrzebować 19 slotów. Każdy z nich

będzie odpowiadać za kliknięcie wybranego przycisku. Można to oczywiście wykonamy prościej np. jednym slotem ale dla przećwiczenia lepiej użyć 19. W tym celu wchodzimy w menu edit i wybieramy slots. W okienku, które sie pojawi dodajemy funkcje i jako nazwy wpisujemy np. pb1click(). Powtarzamy tą czynność, aż wszystkie przyciski będą miały swojego slota. Gdy już wszystkie sloty będziemy mieć potworzone, możemy zabawić się w tworzenie połączeń między wciśnięciem przycisku, a wywołaniem funkcji slota. W tym celu wykorzystujemy okienko edit connections. Przy tworzeniu wszystkich połączeń będzie trochę klikologii, aczkolwiek powyższy sposób jest chyba najszybszym na oprogramowanie takiej ilości funkcji. Gdy uda nam się stworzyć te połączenia możemy przystąpić do etapu kodowania. Kodowanie Na początek zajmiemy się funkcjami do wstawiania cyferek do naszego edita. Posłuży nam do tego następujący kod, który będzie jednakowy dla wszystkich przycisków oznaczonych cyferkami: void Form1::pb9Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "9" ); else lineedit1 >settext( "9" ); Z powyższego kodu widać, że dopisanie nowej cyferki nastąpi tylko wówczas gdy zawartość pola będzie równa zero, w przeciwnym wypadku cyfra zostanie dopisana do tego co już w tym polu się znajduje. Funkcja przycisku kropki będzie za to wyglądać w ten sposób: void Form1::pbDotClick() QString string( lineedit1 >text() ); int n = string.contains( '.', FALSE ); if (n < 1 ) lineedit1 >settext( lineedit1 >text() + "." );

W pierwszych dwóch linijkach sprawdzamy czy nasz lineedit1 posiada już wpisaną kropę, a następnie jeśli liczba kropek będzie mniejsza od 1 to dopisujemy nam naszą kropę. Kasowanie lineedit1'a W tym miejscu dochodzimy do zmiennych, o których wcześniej nie wspominałem. Otóż nasz program będzie sie posługiwał trzema zmiennymi typu float. Deklarację tych zmiennych proponuję umieścić na samej górze programu, jeszcze przed deklaracją pierwszego slota. Wyglądać to powinno mniej więcej w ten sposób: float a,b,c; Zmienne te będziemy wykorzystywali do operacji matematycznych tj. dzielenie, czy pierwiastkowanie. Dlatego tez funkcja kasowania musi również wyzerować te zmienne. Wyglądać to będzie tak: void Form1::pbCClick() lineedit1 >settext( "0" ); a = 0; b = 0; c = 0; Funkcja dodawania znaku void Form1::pbCharClick() if (lineedit1 >text()!= "0") QString string( lineedit1 >text() ); int n = string.contains( ' ', FALSE ); if (n < 1) lineedit1 >settext( " " + lineedit1 >text() ); else int a = string.length(); QString t = string.right( a 1 ); lineedit1 >settext( t );

Najpierw sprawdzamy czy nasze pole jest czymś innym niż zero, a jeśli jest to musimy się umieć zachować w zależności od tego czy do pola już został znak zapisany. Jeśli został to musimy go wykasować, a jeśli jeszcze go tam nie ma to go dodajemy. Zaczynamy działać Pierwsze działanie jakie dodamy do naszego programu będzie podnosić liczę z pola edycyjnego do potęgi. Będzie to wymagało od nas dodania dwóch plików nagłówkowych: stdlib.h i math.h. Gdy je dodamy wykorzystamy poniższy kod: // potęgowanie void Form1::pbPotClick() a = atof(lineedit1 >text()); b = a; c = a*b; lineedit1 >settext( QString::number(c) ); // no i od razu przy okazji pierwiastkowanie void Form1::pbPierwClick() a = atof(lineedit1 >text()); c = sqrt(a); lineedit1 >settext( QString::number(c) ); Funkcje bardziej skomplikowane np. Dodawanie Komplikacje związane z dodawaniem polegają na tym, iż dodawana liczba trafia jakby do pamięci i czeka na swój dodajnik. Po zapisaniu do programu liczby dodawanej użytkownik wprowadza rodzaj działania jaki chce wykonać. Gdy te dwie informacje juz mamy potrzebujemy już tylko drugiej liczby do dodania i możemy zaprezentować wynik. Aby to wszystko miało ręce i nogi posłużymy się zmienną np. int, która będzie przechowywała typ działania jakie wykonujemy. Deklaracja tej zmiennej powinna mieć miejsce tuż pod zmiennymi a,b,c. Wszystkie funkcje tj. dodawanie, odejmowanie, mnożenie i dzielenie będą się odbywać w funkcji pbwynikclick, natomiast w funkcjach przypisanych do przycisków np. dodawania będą tylko instrukcje służące zapisaniu wartości pola do zmiennej float. Całość wyglądać będzie tak: //dodawanie

void Form1::pbAddClick() a = atof(lineedit1 >text()); funkcja = 1; lineedit1 >settext( "0" ); // mnożenie void Form1::pbMultiClick() a = atof(lineedit1 >text()); funkcja = 3; lineedit1 >settext( "0" ); // odejmowanie void Form1::pbTaClick() a = atof(lineedit1 >text()); funkcja = 2; lineedit1 >settext( "0" ); // dzielenie void Form1::pbDivClick() a = atof(lineedit1 >text()); funkcja = 4; lineedit1 >settext( "0" ); // wynik void Form1::pbWynikClick() b = atof(lineedit1 >text()); switch( funkcja ) case 1: c = a + b; break; case 2: c = a b; break; case 3: c = a * b; break; case 4: c = a / b;

break; lineedit1 >settext( QString::number(c) ); jak widać wszystko jest proste i czytelne. Proponuję dla wprawy dodać obsługę błędu dzielenia przez zero. Na koniec zamieszczam cały kod programu: #include <stdlib.h> #include <math.h> float a, b, c; int funkcja; void Form1::Init() pbcclick(); a = 0; b = 0; c = 0; funkcja = 0; void Form1::pb0Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "0" ); else lineedit1 >settext( "0" ); void Form1::pb1Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "1" ); else lineedit1 >settext( "1" ); void Form1::pb2Click() if (lineedit1 >text()!= "0")

lineedit1 >settext( lineedit1 >text() + "2" ); else lineedit1 >settext( "2" ); void Form1::pb3Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "3" ); else lineedit1 >settext( "3" ); void Form1::pb4Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "4" ); else lineedit1 >settext( "4" ); void Form1::pb5Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "5" ); else lineedit1 >settext( "5" ); void Form1::pb6Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "6" ); else lineedit1 >settext( "6" ); void Form1::pb7Click()

if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "7" ); else lineedit1 >settext( "7" ); void Form1::pb8Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "8" ); else lineedit1 >settext( "8" ); void Form1::pb9Click() if (lineedit1 >text()!= "0") lineedit1 >settext( lineedit1 >text() + "9" ); else lineedit1 >settext( "9" ); void Form1::pbDotClick() QString string( lineedit1 >text() ); int n = string.contains( '.', FALSE ); if (n < 1 ) lineedit1 >settext( lineedit1 >text() + "." ); void Form1::pbPotClick() a = atof(lineedit1 >text()); b = a; c = a*b; lineedit1 >settext( QString::number(c) );

void Form1::pbPierwClick() a = atof(lineedit1 >text()); c = sqrt(a); lineedit1 >settext( QString::number(c) ); void Form1::pbAddClick() a = atof(lineedit1 >text()); funkcja = 1; lineedit1 >settext( "0" ); void Form1::pbMultiClick() a = atof(lineedit1 >text()); funkcja = 3; lineedit1 >settext( "0" ); void Form1::pbTaClick() a = atof(lineedit1 >text()); funkcja = 2; lineedit1 >settext( "0" ); void Form1::pbDivClick() a = atof(lineedit1 >text()); funkcja = 4; lineedit1 >settext( "0" ); void Form1::pbWynikClick() b = atof(lineedit1 >text()); switch( funkcja ) case 1: c = a + b; break; case 2: c = a b; break;

case 3: c = a * b; break; case 4: c = a / b; break; lineedit1 >settext( QString::number(c) ); void Form1::pbCharClick() if (lineedit1 >text()!= "0") QString string( lineedit1 >text() ); int n = string.contains( ' ', FALSE ); if (n < 1) lineedit1 >settext( " " + lineedit1 >text() ); else int a = string.length(); QString t = string.right( a 1 ); lineedit1 >settext( t ); void Form1::pbCClick() lineedit1 >settext( "0" ); a = 0; b = 0; c = 0;

Pliki graficzne Najprostsza wersja przeglądarki graficznej 1. Tworzymy nowy projekt ( patrz Qt Designer filozofia pracy ) 2. Układamy na formatce pixmaplabel w zakładce Display i przycisk pushbutton 3. Tworzymy slota np. o nazwie load 4. Tworzymy połączenie między klinięciem przycisku i slotem Do stworzenia programu wykorzystamy kod, który będzie wykorzystywał okienko dialogowe Otórz/Zapisz. Za pomocą tego okieka pobierzemy nazwę pliku jaki chcemy załadować do programu. Funkcja tego okna będzie wyglądała tak: #include <qfiledialog.h> void Form1::load() QString s = QFileDialog::getOpenFileName( "/home", "Pliki graficzne ( *.jpg *.gif *.png )", this, "Otworz plik" "Wybierz plik" ); pixmaplabel2 >setpixmap( s ); Chociaż powyższy kod działa powinniśmy jednak wyposażyć go w obsługę błędów: #include <qfiledialog.h> void Form1::load() QString s = QFileDialog::getOpenFileName( "/home", "Pliki graficzne ( *.jpg *.gif *.png )", this, "Otworz plik" "Wybierz plik" ); if ( s!= NULL ) pixmaplabel2 >setpixmap( s );

Pliki: zapis, odczyt, QFileDialog. Chyba najbardziej pocieszną rzeczą jaką można wykonać w każdym języku programowania jest notatnik. Zanim jednak wykonamy prawdziwy notatnik, taki z prawdziwego zdarzenia musimy poznać dwie klasy przydatne przy obsłudze plików: QFile i QFileDialog. W najprostszym przykładzie zaczytanie pliku tekstowego będzie wyglądało tak: #include <qfile.h> void Form1::zapis() QFile fp("/home/moux/plik.txt"); fp.open( IO_WriteOnly ); fp.writeblock( textedit1 >text(), qstrlen(textedit1 >text()) ); fp.close(); void Form1::odczyt() QFile fp("/home/moux/plik.txt"); char buff[255]; fp.open( IO_ReadOnly ); textedit1 >clear(); while (!fp.atend() ) fp.readline(buff, sizeof(buff)); textedit1 >append(buff); fp.close(); Oczywiście funkcje odczyt i zapis są slotami połączonymi z przyciskami, tekstedit1 jest więc komponentem do przechowywania tekstu. Podobieństwo ze standardowym użyciem jest wiele jednek widać, że wszystkie funkcje użyte do obsługi plików są metodami klasy QFile. W tym przykładzie zaczytujemy i zapisujemy cały plik za jednym zamachem. Funkcja writeblock (uwaga na wielkości znaków muszą być zachowane) zapisuje tekst z komponentu textedit1, uzyskany przy pomocy funkcji text(). Długość tego tekstu jest obliczna za pomocą funkcji qstrlen. Do odczytania danych używamy funkcji readline, ponieważ nie wiemy ile znaków ma tekst zapisany w pliku. Zaczytujemy te dane tak długo jak funkcja atend (informująca o tym czy osiągnęliśmy koniec pliku) zwaraca wartość FALSE (definicja tej funkcji bool QFile::atEnd()). Każda odczytaną linię zapisujemy do bufora buff, a następnie doklejamy do textedita.

Innym ciekawym sposobem na dostęp do pliku są strumienie, klasy QTextStream i QDataStream. Odczyt i zapis tego samego tekstu jak w pierwszym przykładzie przy użyciu QTextStream miałby taką postać: void Form1::zapis2() QFile fp( "/home/moux/plik.txt" ); fp.open( IO_WriteOnly ); QTextStream stream( &fp ); stream >> textedit1 >text(); fp.close(); void Form1::odczyt2() QFile fp( "/home/moux/plik.txt" ); fp.open( IO_ReadOnly ); QTextStream stream( &fp ); textedit1 >settext( stream.read() ); fp.close(); Znaczącą różnicą podczas odczytu, w przypadku tych dwóch zastosowań jest to, iż w drugim przypadku przy odczycie i zapisie tekstów stosowane jest kodowanie lokalne 8 bitowe. Dla nas polskich polaków oznacza to nasze ulubione ISO 8859 2, czyli odczytany plik będzie miał krzaczki. QFileDialog Gdy w obojętnie jakim edytorze napisanym przy użyciu Qt klikamy "Otwórz" albo "Zapisz jako". Pokazuje się nam okienko, które nie jest niczym innym jak klasą QFileDialog. Do czego to okienko jest wykorzystywane z punktu widzenia programisty?? Przede wszystkim do tego, aby dać użytkownikowi możliwość wskazania pliku (a więc uzyskania jego ścieżki i nazwy) do zapisania lub otwarcia. Wszystkie metody tej klasy pozwalają sterować wyglądem tego okienka i jego zawartością. Aby móc korzystać z tej klasy musimy dołączyć plik nagłówkowy qfiledialog.h. W naszym przykładzie wykorzystanie tej klasy będzie sie przedstawiać następująco: void Form1::zapis2() QString fname = QFileDialog::getSaveFileName(

"/home", "Pliki tekstowe (*.txt)", this, "", "Zapisz jako" ); if ( fname!= NULL) QFile fp( fname ); fp.open( IO_WriteOnly ); QTextStream stream( &fp ); stream << textedit1 >text(); fp.close(); void Form1::odczyt2() QString fname = QFileDialog::getOpenFileName( "/home", "Pliki tekstowe (*.txt)", this, "" "Otwórz plik" ); if ( fname!= NULL) QFile fp( fname ); fp.open( IO_ReadOnly ); QTextStream stream( &fp ); textedit1 >settext( stream.read() ); fp.close(); Zaprezentowane powyżej zastosowanie może być użyte wszędzie tam gdzie konieczne jest szybkie wykorzystanie tego okienka dialogowego. Gdybyśmy jednak chcieli mieć większą nad nim kontrolę powinniśmy zadeklarować to okno jako osobną zmienną i wykorzystywać jej właściwości tak jak to robimy w przypadku textedit'a. Przykład takiego wykorzystania: void Form1::odczyt3() QFileDialog *openfd = new QFileDialog( this, "", TRUE ); openfd >setmode( QFileDialog::ExistingFile ); openfd >addfilter( "Pliki tekstowe (*.txt)" ); openfd >setshowhiddenfiles( TRUE );

openfd >setdir("/home"); openfd >show(); if ( openfd >selectedfile()!= NULL ) // jakies operacje Jak widać takie zastosowanie pozwoliło nam dodać opcję otwierania plików ukrytych. Pondto widać tutaj dość ciekawą opcję setmode. Pozwala ona zdecydować o tym w jakim trybie ma pracować nasze okienko. Do wyboru mamy: QFileDialog::AnyFile Pozwala wskazanie pliku, który może lecz nie musi istnieć. Ten tryb jest najbardziej dostosowany do operacji zapisu plików. QFileDialog::ExistingFile Pozwala na wskazanie pliku juz istniejącego. QFileDialog::Directory Pozwala na wskazanie katalogu. Wyświetlane są zarówno pliki jak i katalogi. QFileDialog::DirectoryOnly Wyświetlane sa tylko katalogi. QFileDialog::ExistingFiles Pozwala na wskazanie wielu plików. Opcje te są porównywalne do funkcji operacji, które wykorzystywaliśmy w pierwszym przykładzie. Warto jeszcze wspomnieć o tym, iż w funkcji addfiler (podobnie jak w funkcjach do pobierenia nazw plików) możemy definiowac wiele masek rozszerzeń. Kolejne maski podaje sie w sposób następujący np.: ("Pliki png (*.png);;pliki jpg (*.jpg)"), oddzielając je jak widać dwoma średnikami.

Komponenty wyboru, checkbox i radiobutton Zanim przejdziemy do utworzenia projektu słowo wstępu. Co to są komponenty wyboru i jak z nich korzystać?? Generalnie w programowaniu okienkowym mamy trzy klasy/komponenty, które są z tym związane: CheckBox, RadioButton i ButtonGroup. Komponent ButtonGroup organizuje komponenty jakby w jedną całość. Posiada on zmienną typu integer, która przechowuje numer ostatniego wciśniętego komponentu. W przypadku gdy na ButtonGroup umieścimy komponenty RadioButton będziemy dzięki temu mogli w prosty sposób określić, który z nich jest włączony, a który nie. Komponenty CheckBox pozwalają nam natomiast włączać/wyłączać kilka opcji. Do grupowania CheckBox'ów lepiej użyć komponentu GroupBox, który jest jedynie ramką z tytułem. Do pracy rodacy Jak zwykle rozpoczynamy od stworzenia projektu, qtcheckb, dodaniu formatki QDialog i pliku main.cpp. Następnie dodamy komponenty: QButtonGroup, QGroupBox, 3 x QRadioButton, które umieszczamy na komponencie buttongroup. Do tego wszystkiego dodamy jeszcze 3 sztuki QCheckBox, które wcipolimy na QGroupBox. Kod programu W tym tekście wykonamy program, który będzie potrafił zmienić kolor swojego tła. Na początek obsługa QRadioButton. Klasa ta ma w swojej budowie zdefiniowany sygnał clicked(int). Zmienna int podana przy wywołaniu tej funkcji przechowuje numer wciskanego radiobuttona. Funkcja/slot, którego możemy używać z tą funkcja wygląda tak: void Form1::rbClick( int x ) switch ( x ) case 0: setbackgroundcolor( "#FF0000" ); break; case 1: setbackgroundcolor( "#00FF00" ); break; case 2: setbackgroundcolor( "#0000FF" ); break; setcaption( backgroundcolor().name() ); checkbox1 >setchecked(false); // zerujemy chceckboxy, checkbox2 >setchecked(false);

checkbox3 >setchecked(false); Połączenie tej funkcji z sygnałem, oczywiście dokonujemy w okienku Connections. Z powyższego kodu widać moc wykonawczą zmienne x. Obsługa CheckBox W przypadku checkbox nie jest juz tak prosto. Komponenty te mogą pracować oddzielnie, a co za tym idzie ilość wszystkich kombinacji w przypadku 3 sztuk wynosi 9. Jak dotąd nie spotkałem się z komponentem grupującym checkbox'y dlatego do ich obsługi wymyśliłem funkcję: void Form1::edColor() QColor cl( backgroundcolor() ); int r, g, b; r = cl.red(); g = cl.green(); b = cl.blue(); int x = buttongroup1 >selectedid(); if ( checkbox1 >ischecked() ) r = 127; else if ( x == 0 ) r = 255; else r = 0; if ( checkbox2 >ischecked() ) g = 127; else if ( x == 1 ) g = 255; else g = 0; if ( checkbox3 >ischecked() ) b = 127; else if ( x == 2 ) b = 255; else b = 0; setbackgroundcolor( QColor( r, g, b ) ); setcaption( QColor( r, g, b ).name() );

Funkcja ta najpierw rozdziela kolory na rgb, a następnie zmniejsza lub zwiększa kolor o połowę :))). Funkcję tą musimy podpiąć do każdego checkbox'a do sygnału clicked(). Generalnie sposób działania tej funkcji najlepiej będzie analizować na podstawie działania programu.

Wywołanie programu z parametrem Do uruchamiania programu w Qt przygotowano, spejalną świetną funkcję. Sprawia ona, że obsłużenie programu wywołanego z parametrami to naprawde bajka i frajdziowcha :)) Pierwszą i zasadniczą rzeczą od jakiej zaczniemy jest tzw. help. Normalnie jak program uruchomimy z parametrem help to pojawi nam się pomoc. Jak to zrobić w Qt? Zaczniemy od stworzenia projektu, z dwoma formami form1 i form2. Nastepnie zajmiemy się edycją pliku main.cpp: #include <qapplication.h> #include "form1.h" #include "form2.h" int main( int argc, char ** argv ) QApplication a( argc, argv ); QString opcja = " normal"; if ( argc > 1 ) opcja = argv[1]; if ( qstrcmp(opcja, " normal") == 0 ) Form1 w; w.show(); a.connect( &a, SIGNAL( lastwindowclosed() ), &a, SLOT( quit() ) ); return a.exec(); else if ( qstrcmp(opcja, " settings") == 0 ) Form2 w2; w2.show(); a.connect( &a, SIGNAL( lastwindowclosed() ), &a, SLOT( quit() ) ); return a.exec(); else if ( qstrcmp(opcja, " help") == 0 ) qwarning( "Uzycie \n" "param [opcja]\n" " normal \t Uruchamia program w trybie normalnym.\n" " settings \t Uruchamia program w trybie ustawien.\n" " help \t\t Wyswietla pomoc." ); else qwarning( "Nieznana opcja: " + opcja + "\n Sprobuj help" ); return 0;

Jak widać z tego przykładu program posiada cztery możliwości uruchomienia: w trybie normalnym, gdzie uruchamiane jest normalne okienko programu, w trybie ustawień gdzie wyświetlane jest okienko form2 z ustawieniami, w trybie pomocy konslowej, dzie wyświetlane sa wszystkie dostępne opcje oraz w trybie informujacym o złej komendzie. Pobranie parametrów odbywa się poprzez standardowe argv. Porównanie natomiast jest wykonywane przy pomocy funkcji porównującej stringi. Warto zwrócić uwagę na zastosowanie qwarning. Za pomocą tej funkcji wyświetlamy tekst na konsoli. Oprócz tej funkcji w Qt mamy jeszcze dwie wykonujące podobne operacje. Są to qdebug, która nie różni się niczym od qwarning i prawie niczym od qfatal, która po wywołaniu od razu zamyka program. Gdybyśmy chcieli teraz wykorzystać parametr wywołania programu w jakimś pliku formatki możemy to zrobić w następujący sposób: #include <qapplication.h> void Form1::init() if (qstrcmp(qapp >argv()[2], " kill") == 0 ) qfatal( "Koniec zabawy... \n" ); Aby przetestować działanie tego programu należy uruchomić go z konsoli wpisając jego nazwę poprzedzoną "./".

Programik wieloformatkowy Treść tego rozdziału nie jest zbyt skomplikowana, omówione tutaj sposoby wykorzystania Qt pozwolą na wykorzystywanie w programach kilku form/dialogów. Przedstawione tutaj zostaną dwa sposoby podejścia do tematu. Pierwszy to tworzenie nowych form przygotowanych wcześniej w QtDesingerze. Drugi sposób to tworzenie formatek całkowicie w kodzie programu. Ten drugi sposób z pewnością będzie później przydatny przy innych komponentach takich jak np. buttony. Na koniec zaprezentuję sposób na przekazywanie danych, zmiennych i funkcji pomiędzy formatkami. Zaczynamy. Jak zwykle nowy projekt np. o nazwie "2form". Po zapisaniu projektu tworzymy dwie formatki jedną wyposażamy w dwa SpinBoxy i dwa buttony. Drugą pozostawiamy pustą, z tym że tworzymy jej pusty plik z kodem, którym zajmiemy sie później. Po utworzeniu formaki form1, tworzymy slota np. o nazwie frm2show_s(). Slota tego podpinamy do pierwszego buttona. Do slota wklejamy następujący kod: #include "form2.h" void Form1::frm2show_s() Form2 frm2; frm2.exec(); Jak widać nic skomplikowanego. Tworzone w ten sposób okienko jest okienkiem modalnym co znaczy, że blokuje wykonywanie programu i dostęp do formatki głównej. Teraz pokażę sposób na tworzenie okienka w sposób dynamiczny. Sposób ten polega na tym, że okienko jest tworzone w trakcie działania programu po wywołaniu funkcji tworzącej. Takie podejście pozwala na stworzenie formy na podstawie parametrów, które mogą być różne w różnych momentach działania programu. Innymi słowy dynamiczne tworzenie obiektów pozwala na dodanie funkcji do programu, która nie będzie musiała być do niego wkompilowana. W ten sposób działa np. Quanta gdzie użytkownik ma możliwość dodania własnego przycisku np. wstawiającego jakiś kod lub wywołującego funkcję do wyboru koloru. Aby to wszystko uczynić możliwym musimy jak zwykle utworzyć slota frm3show_d() i podpiąć go do buttona "show dynamic". Funkcja frm3show_d() powinna mieć mniej więcej taki kod: void Form1::frm3show_d() QDialog *frm3 = new QDialog ( this, "", TRUE, 0); frm3 >resize(sbwidth >value(), sbheight >value());

frm3 >exec(); delete frm3; Dwa fragmenty tego kodu z pewnością wymagają wytłumaczenia: QDialog *frm3 = new QDialog ( this, "", TRUE, 0 ); to konstruktor klasy QDialog o nazwie *frm. Parametry podane przy wywołaniu konstruktora to po kolei: rodzic (parent), nazwa, czy okienko ma być modalne, oraz typ formatki. Ponieważ dialog jest formatką raczej uproszczoną może istnieć tylko jako okienko modalne. Jako typ formatki mamy do wyboru: WStyle_Customize WStyle_NormalBorder WStyle_Title WStyle_SysMenu. Testowanie poszczególnych opcji pozostawiam czytelnikowi. Słówko this podane jako parametr rodzica odwołuje się do programu czyli klasy QApplication. Funkcja resize jest chyba zrozumiała, jedyne co należy wiedzieć to to, że jest ona funkcją klasy QWidget, która jest przodkiem klasy QDialog. Szczegółowe omówienie dziedziczenia w Qt będzie omówione w innym rozdziale. Wskazuję jedynie na istnienie tegoż. Kolejnym bardzo ważnym elementem tej funkcji jest linia: delete frm3; niszczy ona cały obiekt, po zamknięciu okna. Oszczędza to pamięć.

Singleton pattern Nie wiem czy określenie zawarte w tytule ma swój polski odpowiednik, jakkolwiek jest to jeden z ważniejszych elementów programowania w języku C++ po linuxem. Na czym rzecz polega?? Singleton Pattern jest to pewien sposób na stosowanie zmiennych globalnych, czyli takich widocznych do odczytu i zapisu w całym programie, w każdym jego miejscu. Używanie klas Qt dość znacznie ogranicza możliwości używania klasycznych zmiennych globalnych. W dodatku mechanizmy działania Qt Designera nie dają nam zbyt wielkiego pola do manewrów w tym zakresie. Dlatego też będziemy używać czegoś co po amerykańsku nazywane jest Singleton Pattern. Określenie pochodzi z książki "Effective C++" Scotta Meyersa. W internecie można znaleźć setki przykładów użycia tego czegoś, nie ma jednak zbyt wiele na temat użycia Singletona w Qt. Dlatego też w poniższej części opiszę do bólu prosty przykład. Zanim to nastąpi przydało by się małe wprowadzenie do tego całego Singletonu. Co to w ogóle jest i takie tam?? Więc singleton to klasa, której podstawową cechą jest posiadanie tylko jednej instancji. W ten sposób jeśli raz zapiszemy tam jakąś wartość będziemy ją mogli zawsze odczytać. Tak więc pojedynczość tej klasy sprawia, że jest ona idealnie dostosowana do przechowywania różnych wartości i zmiennych. W bardziej rozbudowanych programach za pomocą singletonu można zapisywać i odczytywać konfigurację programu. Wytężamy mózgownice i startujemy: 1.Utwórz projekt o nazwie 2form2.pro 2.Utwórz dwie formatki QDialog o nazwie form1 i form2 3.Utwórz plik main.cpp według opisywanego wielokrotnie wzoru. 4.Utwórz nowy plik nagłówkowy o nazwie zmienne.h 5.Utwórz nowy plik źródłowy o nazwie zmienne.cpp Zaczniemy od pliku zmienne.h co powinien on zawierać?? Z pewnością definicję klasy oraz spis zmiennych jakie będziemy użytkowali. W naszym przykładowym programie wykorzystamy tylko jedną zmienna, żeby sposób użytkowania singletonów był bardziej widoczny. Zmienna będzie typu QString więc musimy dodać plik nagłówkowy: qstring.h. Całość kodu tego pliku będzie wyglądała tak: #include <qstring.h> class Singleton // definicja klasy o nazwie Singleton jest // to nazwa wlasna :) public: QString ciapek; // definicja zminnej QString o nazwie ciapek

private: Singleton(); Singleton(const Singleton&); // konstruktor klasy friend Singleton& Zmienne(); ; Singleton& Zmienne(); Słówko friend może się wydać dosyć dziwne. Oznacza ono, ze funkcja Zmienne() będzie miała dostęp do części prywatnej (private) klasy Singleton. Do dostępu do zmiennych będziemy używać funkcji Zmienne(). Plik zmienne.cpp: #include "zmienne.h" Singleton::Singleton() // konstruktor klasy nie używany :)) ; Singleton& Zmienne() // funkcja glowna singletonu static Singleton zmienne; return zmienne; ; I na tym praktycznie kończy się cała sztuczka niesamowicie sprytna. Pokażę jeszcze tylko z czym to się wszystko je. Aby to się dało jeść będziemy potrzebowali kilku komponentów wizualnych, paru slotów i kilku sygnałów wg. poniższej specyfikacji: Formatka główna form1: trzy przyciski (QPushButton) o nazwach pb1, pb2 i pb3 jedno pole edycyjne (QLineEdit) o nazwie leciapek :) no i jedna labelka (QLabel), która nam powie co znajduje się w leciapku :))) Formaka druga form2: dwie labelki (QLabel) o nazwach: tlciapek i tlopisle jeden przycisk pb1 i jedno pole edycyjne (QLineEdit) o nazwie leciapek

Koncepcja działania programiku polega na wielokrotnym zapisywaniu różnych wartości do zmiennej ciapek. Wartości te będziemy pobierać z pól edycyjnych dwóch różnych formatek. Wybrałem ten sposób na opisanie tematu, ponieważ przy dwóch formatkach mamy do czynienia z dwoma różnymi klasami. W ten sposób można będzie dość łatwo zauważyć, że zmienna z singletonu jest ponad klasami. form1.ui.h #include "form2.h" #include "zmienne.h" void form1::init() Zmienne().ciapek = "1st Step = progz run"; // w ten sposób zapisujemy wartości do zmiennej // ciapek singletonu leciapek >settext( Zmienne().ciapek ); // w ten sposób odczytujemy wartości ze zmiennej // ciapek singletonu void form1::load_form2() form2 f2; f2.exec(); void form1::ciapek_save() if ( leciapek >text()!= "" ) Zmienne().ciapek = leciapek >text(); else Zmienne().ciapek = "Ciapek byl pusty"; void form1::ciapek_refresh() leciapek >settext( Zmienne().ciapek ); form2.ui.h

#include "zmienne.h" void form2::init() tlciapek >settext( "Zmienna globalna ciapek :) wyglada tak: " + Zmienne().ciapek ); void form2::ciapek_save() if ( leciapek >text()!= "" ) Zmienne().ciapek = leciapek >text(); else Zmienne().ciapek = "Ciapek byl pusty"; tlciapek >settext( "Zmienna ciapek :) wyglada tak: " + Zmienne().ciapek ); close(); Jak widać w ten sam sposób możemy się bawić ciapkiem w zupełnie innej klasie. PS: Instrukcja obsługi do programu: 1. W polu edycyjnym wpisz dowolny tekst, np. "My name is tom", wciśnij przycisk zapisz a następnie nowe okienko 2. Jak widać treść ciapka została zapisana i zaprezentowana na labelce możesz teraz zmienić jej treść wpisując w biale pole i zapisując :)))

Menu, popupmenu Jak do tej pory tworzone przez nas aplikacje miały raczej charakter małych programików lub raczej części składowych jakiegoś większego programu. Wszystkie okienka i formatki były budowane przy użyciu klasy QDialog co ma pewne ograniczenia: nie pozwala na tworzenie menu. Dlatego też teraz do stworzenia okienka wykorzystamy klasę QMainWindow. Po uruchomieniu Qt Designera i stworzeniu projektu np. o nazwie menus.pro wybieramy "File >New", a następnie Main Window. Spowoduje to uruchomienie dość dziwnego kreatora, który automatycznie utworzy nam edytor tekstu. W omawianym przykładzie wykonamy Menu własnoręcznie dlatego też proponuję zamknąć kreatora za pomocą przycisku Cancel. Następnie zapisujemy wszystko. Teraz trochę klikologii: Klikamy prawym przyciskiem myszy na formie i wybieramy Add Menu Item: Zmienimy teraz nazwę pierwszego menu, nadamy mu niezwykle oryginalną nazwę plik. Aby tego dokonać należy dwukrotnie kliknąć na napis "Menu" i zacząć pisać. Zatwierdzamy enterem. Po zatwierdzeniu menu powinno już działać przynajmniej w fazie projektowania. Możemy teraz dwukrotnie kilknąć na napis new item i wpisać np. zakończ. Będzie to pierwsza opcja jaką damy użytkownikowi programu. Dodanie nowego pola menu zatwierdzamy enterem. Dodanie akcji Jak zapewne niektórzy z was zauważyli po utworzeniu okna QMainWidget pojawiło się nam nowe okienko ActionEditor. Każdy element końcowy naszego menu będzie tu widoczny jako akcja. (Dobrym pomysłem będzie w tym miejscu zmiana nazw, akcji na pozbawione polskich krzaczków.) Za pomocą znanego już nam przycisku (tu czerwona strzałka), który wywoła okienko z połączeniami (connections) dodamy do naszego menusa akcję. Proponuję na sam początek przypisać funkcję, która bez żadnego "ale" zamknie nasz program. W okienku połączeń wybierzemy sygnał activated() i slota close(). Dodajemy plik main.cpp i możemy kompilować (qmake > make). Za pomocą opisanych powyżej metod i kodu z lekcji 5 możemy w prosty sposób utworzyc edytor tekstu. W tym celu upuszczamy na formę pole textedit (i zmienimy nazwe na teedytor) oraz dodamy do menu Plik opcje otwórz, zapisz i np. nowy. Utworzymy również menu edycja i tu wstawimy: wytnij, kopiuj, wklej i wstaw date. Aby program wygladał jakoś po ludzku dodamy również menu pomoc z opcją o programie. Jeśli wszystkie akcje w edytorze akcji mają poprawne (bez polskich znaków) nazwy to przechodzimy dalej. Po pierwsze dodamy pliki nagłówkowe: qfiledialog.h, qmessagebox.h oraz qdatetime.h. Następnie przejdziemy do pisania kodu. Pierwszą akcją jaką mamy w menu plik powinien być

nowy. Normalnie funkcja ta tworzy nowy projekt/plik w pamięci, pod warunkiem, że zawartość pola edycyjnego nie zmieniła się. Tak więc musimy to sprawdzić: void Form2::nowy() if ( teedytor >ismodified() && (QMessageBox::question( this, "Informacja", "Plik zostal zmieniony. Czy chcesz zapisac??", "&Tak", "&Nie", QString::null, 0, 1 )) == 1 ) teedytor >settext( "" ); teedytor >setmodified(false); Akcje (sygnały) otwórz i zapisz proponuję skopiować z lekcji czwartej, aby się za dużo nie mędzyć. Dobrym pomysłem byłoby dodanie sprawdzania czy zawartość pola edycyjnego się zmieniła od czasu zapisania, otworzenia lub utworzenia nowego pliku. Ma to olbrzymie znaczenie gdyż jeśli tego nie zrobimy nasz biedny użytkownik może przez przypadek skasować sobie cały dzień pracy. Nie będę tutaj opisywał tego z punktu widzenia kodu. Napiszę tylko krótki algorytm działania naszego programu. 1. Użytkownik otwiera (lub tworzy nowy) plik. 2. W polu edycyjnym dokonuje jakichś zmian. 3. Program pyta się czy zapisać zmiany zanim wykona cokolwiek. 4. Jeśli user odpowie, że chce to program zapisuje zawartośc pola i wykona wskazaną operację. 5. Jeśli user odpowie, że nie chce to program skasuje zmiany wykonując wybraną operację. 6. Po wszystkim ustawimy wskaźnik modyfikacji pola na FALSE Zabieramy się za menu edycja. Na początek najprostsze: dzisiajsza data: void Form2::date() QDate date = QDate::currentDate(); QString adzis = date.tostring ( Qt::LocalDate ); teedytor >append( adzis ); oczywiście, żeby kod zadziałał musimy tego slota podczepić do sygnału kliked pozycji wstaw datę w menu. Dodanie obsługi copy/paste jest jeszcze prostsze ale polega na wykonaniu czegoś czego

jeszcze nie robiliśmy. Chodzi o to, że do tej pory odbiorcą wszystkich sygnałów w naszych programikach była formartka, tym razem odbiorcą będzie edytor. Okienko ze slotami powinno więc wyglądać mniej więcej tak: Na koniec jeszcze dodamy obsługę about. Wstawimy tam, krótkiego messageboxa o autorze programu: void Form2::about() QMessageBox::information( this, "Informacja", "Autorem programu jestem ja GREAT LINUX PROGRAMMER :)", "&OK", QString::null, 0, 1 ); i nasz programik jest gotowy. Dodamy jeszcze mały bajer polskie znaki :)). Zasada wyświetlania polskich znaków diakrytycznych polega na wskazaniu kodeka jaki ma zostać użyty przy konwertowaniu tablicy znaków *char do QString. Wykonujemy to w funkcji init(): #include <qtextcodec.h> void frm1::init() QTextCodec::setCodecForCStrings( QTextCodec::codecForName("ISO8859 2") );

Toolbar Początki tworzenia toolbara są takie same jak przy menu. W tym przykładzie posłużymy sie programem z lekcji 10. Po otwarciu projektu w Qt Designerze drugi guzik na formie i Add Toolbar. Do wykonania toolbara potrzebne będą nam obrazki na ikonki. Proponuje w tym celu sięgnąc je stąd (images.tar.gz), żeby nie kombinować. Po sciągnięciu należy pliki rozpakować do katalogu z projekt, tak aby w tym katalogu istniał podkatalog o nazwie.images. Kolejną czynnością jaką musimy wykonać jest dodanie obrazków do zasobów programu. Aby to uczynić podświetlamy dowolną akcję w edytorze akcji, najlepiej pliknowyaction i w edytorze właściwości tej akcji wybieramy opcję iconset. Klikamy [...] trzy kropki, następnie add. Wchodzimy do katalogu.images (lub tam gdzie mamy obrazki do akcji toolbara) i zaznaczmy te, które chcemy dodać. Po dodaniu wskazujemy ikonkę, która ma być przypisana do akcji pliknowyaction. Postępujemy w ten sposób tak długo, aż wszystkie akcje, które chcemy umieścić na toolbarze będą miały swoją ikonkę. Gdy wszystkie akcje będą miały ikonki wystarczy przeciągnąć je na toolbar metodą drag&&drop. Nasz notatnik już jest najpiękniejszy na świecie prawda?? Dodamy mu jeszcze dwie opcje: cofnij i powtórz. W tym celu w Action Edytorze tworzymy dwie nowe akcje innecofnijaction oraz innepowtorzaction. Przypisujemy do nich odpowiednie ikonki, a następnie w oknie dialogowym connection przypisujemy do nich akcje cofnij undo, powtórz redo. W sposób analogiczny do tego jaki tworzyliśmy funkcje kopiuj/wklej to jest wskazując jako odbiorcę sygnału pole tekstowe teedytor. Dobrym pomysłem była by jeszcze zmiana właściwości text tych aktionsów na takie, które będą reprezentatywne do pełninoych przez nie funkcji. Mówiąc po polsku cofnij to cofnij.