Programowanie w środowisku graficznym Ćwiczenia 01 Wprowadzenie do C++Builder VCL Wstęp C++Builder to środowisko programistyczne posiadające cechy charakterystyczne środowiska typu RAD (ang. Rapid Applications Development błyskawiczne tworzenie aplikacji) z funkcjonalnością ANSI C++. C++Builder pozwala więc tworzyć aplikacje okienkowe przy zastosowaniu metody projektowania typu WYSIWYG (ang. What You See Is What You Get), której ostatecznym wynikiem jest aplikacja wyglądająca identycznie lub prawie identycznie jak forma robocza podczas projektowania. Środowisko korzysta z kompilatora C++ BCC2 w wersji 5.6.0.0. Dokumentacja Obecnie dokumentacja do Broland C++Builder 6 jest dostępna po zarejestrowaniu się na stronie edn.embarcadero.com 1, obejmuje m.in. : C++Buildera Developer s Guide, pomoc do bibliotek: STL, VCL, CLX oraz zawiera kozackie zestawienie hierarchii Obiektów VCL/CLX. Biblioteka komponentów VCL Biblioteka VCL (ang. Visual Component Library) to zbiór komponentów dzięki którym programista w prosty sposób może tworzyć nietrywialne aplikacje graficzne. Biblioteka zawiera m.in. kontrolki takie jak przyciski, okienka tekstowe, listy rozwijane, suwaki itp. Środowisko C++Builder podczas umieszczania komponentów na formatce przez programistę, lub dodawania zdarzeń dla komponentów, automatycznie dodaje odpowiedni kod do projektu, dzięki którym, projekt po skompilowaniu wizualnie przedstawia zaprojektowany interface aplikacji. Zaawansowany programista ma możliwość także tworzenia własnych komponentów oraz tworzenia w sposób dynamiczny dużej liczby komponentów (np. plansza do gry Tetris 2 ). Środowisko C++Builder zostało stworzone jako narzędzie projektowe, więc nie jest to rozwiązanie idelane/dobre do wszystkiego. Z pewnością jest jednym z dobrych i lekkich środowisk do rozpoczęcia przygody z aplikacjami graficznymi w systemach operacyjnych z rodziny Windows. Jak każde środowisko C++Builder ma wady i zalety (wg Hollingworth, Butterfield, Swart, Allsop, 2002) w wersji 5: Elementy C++Builder, które zdobyły największe uznanie programistów to m.in.: niezwykle funkcjonalny projektant formularzy; przydatność zarówno do szybkiego tworzenia aplikacji, jak i tradycyjnego programowania w C++, dzięki umiejętnemu połączeniu zgodnego z najnowszymi standardami kompilatora ze środowiskiem projektowania wizualnego; biblioteka komponentów VCL z możliwością wzbogacania jej o nowe, gotowe komponenty i narzędziami do tworzenia własnych komponentów; rozszerzenia języka wykraczające co prawda poza standardy, lecz dostarczające funkcjonalnych konstrukcji programistycznych; wzorce projektów i repozytorium obiektowe umożliwiające wielokrotne wykorzystanie stworzonego kodu oraz pozwalające na szybkie tworzenie projektów; 1 BCB6 Help Files now available D. Dean : http://edn.embarcadero.com/article/4064 (stan z dnia 29-02-2016) 2 Wikipedia, Tetris, https://pl.wikipedia.org/wiki/tetris (stan z dnia 29-02-2016) Hollingworth, J., Butterfield, D., Swart, B., & Allsop, J. C++ Buider 5.
szeroka obsługa mechanizmów bazodanowych dzięki BDE oraz dedykowanym komponentom; ogromne możliwości w zakresie tworzenia aplikacji internetowych; łatwa migracja z innych środowisk, między innymi z Visual C++; otwarta droga do przenoszenia aplikacji na platformę Linuksa. Najczęściej wymieniane wady lub braki środowiska: łatwość operowania mechanizmami projektanta formularzy może łatwo doprowadzić do chaosu w aplikacji źle zaprojektowanej lub wręcz pozbawionej projektu; ze względu na znaczące zmiany kompilatora w wersji 5. przenoszenie złożonej aplikacji z wersji poprzednich może okazać się nieopłacalne; migracja na platformę Visual C++ jest zazwyczaj bardzo trudna; ze względu na dominującą pozycję Microsoftu na rynku systemów operacyjnych wybór narzędzia programistycznego Borlanda może mieć długofalowe konsekwencje o różnorakim charakterze. Elementy podstawowe Wizualnie środowisko C++Builder składa się z kilku podstawowych okien: panel C++Builder, Inspektor Obiektów oraz Edytor projektu (edytor formularza i kodu). Rysunek 1 Środowisko C++Builder 6. Aplikacja Hello World Za każdym razem gdy tworzymy projekt nowej aplikacji (ang. Application), po uruchomieniu środowiska wybieramy z menu kontekstowego File->Close All, aby zamknąć dla bezpieczeństwa (uniknąć niepotrzebnych błędów) otwarte projekty.
Następnie wybieramy File->New->Application po czym otwiera się nowy projekt aplikacji, jednakże projekt ten nie jest jeszcze zapisany na dysku! Rysunek 2. Nowy projekt. Kolejną ważną rzeczą jest zapisanie projektu na dysku: File->Save Project As. W tym celu tworzymy folder na projekt i tam projekt ten zapisujemy. Struktura plików z domyślną nazwą wygląda następująco: Rysunek. Struktura projektu aplikacji. Plik Project1.bpr to główny plik projektu. Ten plik należy nazwać odpowiednio stosownie do tworzonej aplikacji. Najczęściej, głównie przy ćwiczeniach, nie zmienia się nazwy ze względu na oszczędność czasu. Project1.cpp kody źródłowe powiązane z projektem (ang. project file) Unit1.cpp kody źródłowe głównej formatki projektu (ang. unit file) Unit1.h plik nagłówkowy głównej formatki projektu (ang. unit header file) Unit1.dfm plik z zasobami który przechowuje informacje o głównej formatce projektu (ang. form file)
Dla jasności, każda formatka (form) ma swój zestaw plików.cpp,.h i.dfm. Jeżeli dla powyższego projektu stworzymy dodatkową formatkę to automatycznie przy zapisie środowisko stworzy nam pliki Unit2.cpp, Unit2.h oraz Unit2.dfm. Teraz gdy mamy już zapisany nasz projekt, wyłączamy środowisko i otwieramy nasz projekt z poziomu przeglądarki plików. Proces ten pozwala na uniknięcie błędów związanych z miejscem zapisu i niewłaściwym otwieraniem projektu. Łatwo zauważyć, że C++Builder przy zapisie tworzy kopię plików do których rozszerzenia dopisuje znak ~. Ponadto przy kompilowaniu projektu dodawane są pliki binarne *.obj, *.res i *.tds: Project1.obj, Unit1.obj pliki binarne z obrazem odpowiednich plików projektu, przechowywane w pakiecie Project1.res upakowany plik środowiska systemowego, który może zawierać zdjęcia, ikony itp. A także informacje o wersji projektu, którą można ustawić w Project -> Options -> Application and Project -> Options -> Version Info. Plik te można edytować np. przy pomocy http://www.resedit.net/ Project1.tds przechowuje informację na temat debugowania. Teraz gdy pusty projekt jest już gotowy możemy przyjrzeć się plikom źródłowym Plik z projektem Project1.bpr to w zasadzie plik xml z konfiguracją projektu. Plik Unit1.h: 1 2 4 5 6 7 8 9 10 11 12 1 14 15 16 17 18 19 20 21 #ifndef Unit1H #define Unit1H #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> class TForm1 : public TForm { published: // IDE-managed Components private: // User declarations public: // User declarations fastcall TForm1(TComponent* Owner); }; extern PACKAGE TForm1 *Form1; #endif Tak więc w wierszu rozpoczyna się definicja makro Unit1H. Wiersze 6-9 to załączenie plików źródłowych. Nasza aplikacja jest klasą TForm1 dziedziczącą publicznie po klasie TForm. W chwili obecnej jest obecny tylko konstruktor ze wskaźnikiem na właściciela formy. Jak nie trudno zauważyć metoda jest opatrzona słowem kluczowym fastcall, jest to spowodowane specyfiką programowania
z VCL. Środowisko automatycznie dodaje to słowo przed metodami/funkcjami które przyjmują jako parametr wskaźnik. Jest to informacja dla kompilatora o wywołaniu funkcji i posprzątaniu po funkcji. Wiersz 19 to eksport wskaźnika Form1, dzięki czemu jest on widoczny w całym pakiecie projektu. Plik Unit1.cpp zawiera implementację metod klasy TFrame1: 1 2 4 5 6 7 8 9 10 11 12 1 14 15 16 #include <vcl.h> #pragma hdrstop #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } Wiersz załącza bibliotekę VCL, a wiersz 6 załącza plik nagłówkowy naszej klasy TForm1. Obecnie automatycznie dodana jest tylko jedna metoda, która jest zarazem konstruktorem klasy TForm1. Zawołany został konstruktor TForm(Owner) w konstruktorze naszej klasy TForm1, więc po skompilowaniu pojawi nam się domyślnie skonfigurowane okienko. Teraz, aby zaprogramować aplikację Hello World o której mowa, dodajemy na formatkę przycisk (ang. Button) z zakładki Standard. Następnie klikamy dwa razy na dodany przycisk, aby środowisko automatycznie dodało zdarzenie kliknięcia do przycisku. W metodzie obsługującej zdarzenie kliknięcia, czyli OnClick(), dodajemy komunikat z wiadomością Hello World! : void fastcall TForm1::Button1Click(TObject *Sender) { ShowMessage("Hello World!"); } Wystarczy teraz skonfigurować wg. uznania nowo dodany komponent, skompilować i uruchomić aplikację (F9).
Warto zauważyć, że w pliku nagłówkowym Unit1.h w klasie Form1 pojawił się wskaźnik do komponentu typu TButton oraz metoda obsługująca zdarzenie kliknięcia: TButton *Button1; void fastcall Button1Click(TObject *Sender); Natomiast w pliku źródłowym Unit1.cpp pojawiła się automatycznie pusta implementacja (teraz jest już tam nasz kod) metody Button1Click. Dzięki automatycznemu generowaniu kodu, środowisko C++Builder odciąża programistę od pisania powtarzającego się kodu. Zadania Zad.1. Stwórz aplikację zawierającą przycisk. Następnie: zmień kolor tła aplikacji (Color), zmień czcionkę napisu na przycisku oraz zmień napis na przycisku na Puk, puk, podczep zdarzenie kliknięcia pod przycisk, które będzie powodowało zamykanie aplikacji (Application->Terminated()), dodaj komunikat Kto tam? (ang. Hint, ShowHint), który będzie się pojawiał jak mysz będzie znajdowała się nad przyciskiem, Zad.2. Zmodyfikuj zadanie 1 tak, aby kliknięcie przycisku generowało nowy kolor tła aplikacji a nie zamykało aplikację. Zablokuj możliwość zmiany rozmiaru okienka głównego podczas działania aplikacji (ang. BorderStyle). Następnie zmień komunikat (ang. Hint) dla przycisku na wiadomość Losuj kolor tła. Podpowiedź: Wykorzystaj generator liczb pseudolosowych (rand()) do generowania liczb z zakresu 0-255, a następnie użyj funkcji TColor(RGB(r,g,b)), aby określić nowy kolor tła aplikacji. Zad.. Zaprojektuj grę w zgadywanie liczb z przedziału 1 do 100. Aplikacja powinna być zbudowana z dwóch przycisków (Button), pudełka tekstowego (Edit) oraz dwóch napisów (Label). Użytkownik ma dwie możliwości, może wylosować nową liczbę do zgadywania lub spróbować odgadnąć liczbę wpisując w odpowiednie okienko propozycję i potwierdzając sprawdzenie. Aplikacja w wyniku propozycji liczby zwraca napis informujący o tym, czy podana liczba jest mniejsza czy większa od liczby zgadywanej lub czy jest to liczba odgadnięta, oraz zwiększa licznik prób odgadnięcia. Zadbaj o wygląd stylistyczny aplikacji, podpisz aplikację. Opcjonalnie dodaj półprzezroczystość do aplikacji (ang. AlphaBlend). Podpowiedź: 1. Użyj metody ToInt() lub StrToInt() do konwersji napisu na liczbę całkowitą, jednakże zadbaj o poprawność danych przy wykorzystaniu obsługi wyjątków. Wyświetl odpowiedni komunikat gdy wystąpi problem z konwersją. 2. C++Builder sam obsługuje wyjątki, więc należy wyłączyć tą opcję w środowisku (Tools->Debugger options i odznaczamy Integrated debugging). Zad.4. Zaprojektuj prosty kalkulator umożliwiający: - wprowadzanie liczb, - dodawanie, odejmowanie, mnożenie i dzielenie liczb (double), - zapamiętywanie ostatniego wyniku w pamięci podręcznej, Zadbaj o poprawność danych, błąd dzielenia przez zero i wygląd stylistyczny aplikacji.