Laboratorium Podstaw Informatyki
Kierunek Elektrotechnika
Ćwiczenie 7.2
Podstawy programowania aplikacji
w środowisku Visual C++
Część I
Application Wizard, Class Wizard, Zasoby aplikacji
Zakład Metrologii AGH
Kraków 1998
Wprowadzenie
Środowisko programowania Visual C++ nie jest już tylko kompilatorem połączonym z edytorem tekstu. Twórcy tego narzędzia starali się opanować złożoność programowania dużych aplikacji, zawierających rozbudowany interfejs użytkownika i posiadających zdolność wymiany danych z innymi aplikacjami. Z jednej strony narzucono obiektowy styl programowania aplikacji Windows z użyciem biblioteki MFC (Microsoft Foundation Classes). Z drugiej strony dano programiście narzędzia wspomagające go w tworzeniu kodu aplikacji. Narzędzia te to Application Wizard, Class Wizard i Application Studio.
Application Wizard to generator szkieletów aplikacji, korzystający z faktu, że większość aplikacji ma w istocie podobną zasadę działania. Sprowadza się ona do tego, że aplikacja przetwarza dokumenty, będące plikami dyskowymi. Dokumenty są prezentowane użytkownikowi aplikacji w szczególny sposób, np. jako tekst w edytorze MS Word czy rysunek w programie PaintBrush. Wynika z tego naturalny podział na klasę obsługującą dokument (odczyt i zapis do pliku, przechowywanie danych) i klasę widoku prezentującą dane dokumentu użytkownikowi. W MFC są to klasy CDocument i CView. Stanowią one główne składniki aplikacji Visual C++.
Class Wizard to narzędzie rozwijania szkieletu aplikacji stworzonego przez AppWizard do w pełni funkcjonalnej aplikacji. Umożliwia on modyfikację reakcji na określone zdarzenia (np. naciśnięcie klawisza myszki w oknie aplikacji), generowanie nowych klas pochodnych od klas MFC, dodawanie nowych składowych klas.
Application Studio to edytor zasobów aplikacji, czyli elementów interfejsu użytkownika zgromadzonych w pliku zasobów w celu łatwej wymiany np. przy zmianie wersji językowej. Za pomocą tego narzędzia możemy modyfikować i tworzyć okna dialogowe, menu aplikacji, mapy bitowe i napisy.
W trakcie ćwiczenia zastosujemy wymienione narzędzia do stworzenia prostej aplikacji graficznej z możliwością odczytu i zapisu plików oraz z opcją drukowania dokumentów.
Zadanie 1 - Application Wizard
Szkielet aplikacji
Naszym zadaniem jest utworzenie aplikacji z możliwością otwarcia wielu dokumentów jednocześnie. Nie będziemy wykorzystywać możliwości OLE (Object Linking and Embedding). Nie będziemy również łączyli aplikacji z bazą danych.
Według przyjętych założeń utworzymy szkielet aplikacji z wykorzystaniem narzędzia AppWizard.
W środowisku Visual C++ wybierz opcję Project/AppWizard. Wybierz nazwę aplikacji (używane poniżej nazwy dotyczą nazwy test) i katalog, w którym projekt zostanie utworzony. Przeglądnij dostępne opcje generowania aplikacji. Po naciśnieciu klawisza OK zaakceptuj tworzenie szkieletu, jeśli posumowanie wybranych opcji odpowiada przyjętym założeniom. |
Wynikiem wykonanej operacji tworzenia szkieletu jest kilkanaście plików, z których połowa jest dla nas na razie nieistotna. W dalszej części ćwiczenia modyfikować będziemy jedynie klasę dokumentu CTestDoc pochodną od CDocument i opisaną w plikach testdoc.cpp i testdoc.h, oraz klasę widoku CTestView pochodną od CView i opisaną w plikach testview.cpp i testview.h.
Skompiluj i uruchom wygenerowaną aplikację. Zwróć uwagę na ilość dostępnych opcji i zakres funkcjonalny aplikacji, uzyskane bez wpisania ani jednej linijki kodu. |
Zadanie 2 - edytor zasobów aplikacji
Modyfikacja interfejsu użytkownika
Zacznijmy od podpisu pod dziełem. Zmodyfikujemy informację wyświetlaną po wybraniu opcji Help/About.
Wybierz opcję Tools/App Studio. W oknie dialogowym Application Studio wybierz typ Dialog i zasób IDD_ABOUTBOX. Wpisz wybraną informację o autorach aplikacji. Zmodyfikuj napis na klawiszu akceptacji OK. Sprawdź efekt modyfikacji po skompilowaniu i uruchomieniu aplikacji. |
Budowana aplikacja ma umożliwić tworzenie rysunków z prostych figur. Musimy więc dać użytkownikowi możliwość wyboru jaką figurę chce w danym momencie wykorzystać. Utworzymy w tym celu nowe opcje menu. Aplikacja posiada już dwa zdefiniowane menu, IDR_MAINFRAME dla okna głównego bez wczytanego dokumentu i IDR_TESTTYPE aktywne dla otwartego dokumentu.
Dodaj do menu IDR_TESTTYPE opcję Shape z podopcjami Rectangle, Circle, Triangle. Zapamiętaj identyfikatory nadane tym opcjom przez AppStudio. Sprawdź efekt wprowadzonych zmian. |
Zadanie 3 - Class Wizard
Dodajemy cechy funkcjonalne aplikacji
Aplikacja posiada już pożądany interfejs użytkownika, ale nie reaguje na większość wybieranych opcji. Zacznijmy od rysowania prostokąta w punkcie wskazanym myszką po naciśnięciu jej lewego klawisza. Naciśnięcie klawisza myszki w oknie aplikacji powoduje wysłanie przez system do aplikacji komunikatu powiadamiającego o tym fakcie. Zmienimy domyślną obsługę tego komunikatu.
Wybierz z głównego okna środowiska opcję Browse/ClassWizard. W oknie dialogowym wybierz zestaw opcji Message Maps. Upewnij się czy do modyfikacji wybrana jest klasa CTestView. Wybierz ID obiektu CTestView i komunikat WM_LBUTTONDOWN. Wybierz dodawanie funkcji i potwierdź jej nazwę OnLButtonDown. Zmień kod funkcji (Edit function) do postaci:
void CTestView::OnLButtonDown(UINT nFlags, CPoint point) Sprawdź działanie aplikacji po wprowadzonych zmianach. |
Aplikacja pozwala na rysowanie w oknie dokumentu ale nie odświeża rysunku np. po zmianie rozmiarów okna. Nie można również zapisać ani odczytać dokumentu z pliku. Do wykonania jakichkolwiek operacji na dokumencie trzeba określić sposób jego przechowywania w aplikacji i zdefiniować postać zapisywanych i odczytywanych danych w pliku.
Założyliśmy stały rozmiar rysowanych figur, więc do ich rysowania wystarczą dane o położeniu punktu odniesienia. Zapamiętamy współrzędne x i y rysowanych figur w dwóch tablicach. MFC dostarcza gotową klasę tablicy ze sprawdzaniem indeksowania i automatycznym rozszerzaniem rozmiaru. Spośród różnych wersji tych tablic wybierzemy klasę tablicy słów (wartości szesnastobitowych) CWordArray.
Dodaj do definicji klasy CTestDoc w pliku testdoc.h omówione struktury jak w liniach poniżej.
// Attributes - część przeznaczona na dane publiczne
|
Reakcją na wciśnięcie klawisza (funkcja CTestView::OnLButtonDown()) powinno być narysowanie figury i zapamiętanie jej położenia. Zmodyfikować należy rownież funkcję rysowania dokumentu OnDraw() wołaną przy zmianie rozmiarów okna, po jego odsłonięciu i po wczytaniu nowego dokumentu. Pożądaną postać tych metod przedstawia poniższy wydruk.
Funkcja reakcji na naciśnięcie lewego klawisza myszy zawarta w pliku testview.cpp:
void CTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this); // Utworzenie kontekstu urządzenia
CTestDoc *pDoc=GetDocument(); // Pobranie wskaźnika do dokumentu
ASSERT_VALID(pDoc);
dc.Rectangle(point.x, point.y, point.x+20, point.y+20);
pDoc->x.Add(point.x);
pDoc->y.Add(point.y);
pDoc->SetModifiedFlag(); // Ustawienie flagi modyfikacji dokumentu
CView::OnLButtonDown(nFlags, point);
}
Funkcja prezentacji dokumentu w pliku testview.cpp:
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
int i;
for(i=0;i<pDoc->x.GetSize();i++)
pDC->Rectangle(pDoc->x[i], pDoc->y[i],
pDoc->x[i]+20, pDoc->y[i]+20);
}
Dodaj do aplikacji opisane elementy i przetestuj jej działanie. |
Ostatni problem do rozwiązania to zapis i odczyt dokumentu z pliku dyskowego. Twórcy MFC rozwiązali ten problem za nas dostarczając dla każdej klasy MFC, począwszy od podstawowej klasy tej biblioteki CObject, funkcję serializacji czyli wspólną funkcję zapisu i odczytu wykonującą odpowiednią operację zależnie od wartości parametru wywołania. Dodajmy więc funkcję serializacji dla klasy naszego dokumentu.
Zmodyfikuj funkcję serializacji w pliku testdoc.cpp do postaci:
void CTestDoc::Serialize(CArchive& ar) |
Pozostaje wprowadzić do aplikacji reakcję na wybór rodzaju figury do rysowania i pamiętanie rodzaju figury w danej pozycji. Rodzaje figur możemy kodować liczbowo (1-prostokąt, 2-kółko, itd.), a w celu roszerzenia zakresu informacji o figurze w dokumencie, możemy dodać nową strukturę do pamiętania rodzaju każdej figury (np. klasy CByteArray). Inne rozwiązanie to zmiana struktury pamiętającej dane na przechowującą wskaźniki do figur (rozwiązanie z polimorfizmem jak w ćwiczeniu dot. programowania obiektowego), ale wiąże się to z koniecznością zdefiniowania serializacji dla nowego obiektu.
Uzupełnij aplikację o reakcję na wybór figury i przetestuj jej działanie. |
Dla tych, którzy chcą wiedzieć więcej - informacje dodatkowe
Mapy komunikatów
W systemie MS Windows przyjęto sposób komunikacji między systemem i aplikacją oraz między aplikacjami za pomocą komunikatów. Komunikat posiada identyfikator, który informuje o rodzaju zdarzenia i parametry, które niosą dodatkowe informacje o zdarzeniu. Takim zdarzeniem może być np. naciśnięcie klawisza myszki przez użytkownika lub zamknięcie aplikacji przez wybór opcji menu. Obsługa komunikatów w programach pisanych w języku C polegała na tworzeniu dużej instrukcji warunkowej switch, której parametrem był identyfikator komunikatu i dodawanie funkcji reakcji przy wykryciu odpowiedniego identyfikatora. Środowisko Visual C++ programowania obiektowego z użyciem biblioteki MFC ukryło przed programistą szczegóły wywoływania reakcji na zdarzenie reprezentowane przez komunikat przez wprowadzenie tzw. map komunikatów generowanych automatycznie i obsługiwanych za pomocą narzędzia ClassWizard. Programista widzi tylko funkcję reakcji na dane zdarzenie. Jeśli użytkownik nie definiuje własnej reakcji na zdarzenie to przyjmowana jest domyślna reakcja klasy bazowej. W zadaniach tego ćwiczenia modyfikowaliśmy reakcję na naciśnięcie klawisza myszki, ale nie modyfikowaliśmy reakcji na wybór przez użytkownika opcji zamknięcia aplikacji. Szczegóły konstrukcji mapy komunikatów można poznać oglądając pliki źródłowe definicji klas i czytając dokumentację środowiska dostępna na płycie CD.
Dla tych, którzy chcą być najlepsi - zadania dodatkowe
Udoskonalona wersja aplikacji testowej
Możliwości aplikacji tworzonej w trakcie ćwiczenia są ograniczone. Raz umiejsowiona figura nie może być przemieszczana. Nie można również zmieniać wymiarów figury. Nie można umieszczać na rysunku tekstów opisu. Nie można zmieniać grubości ani wzoru rysowanych linii.
Dodaj potrzebne według Ciebie elementy tej aplikacji. |
Literatura
Marshall B.: Understanding the AppWizard and ClassWizard in Visual C++ ver. 2.x; Interface Technologies 1997, opis dostępny w sieci Internet pod adresem http://www.iftech.com
Marshall B.: Introduction to MFC Programming with Visual C++ ver. 1.5; Interface Technologies 1997, opis dostępny w sieci Internet pod adresem http://www.iftech.com
Perry P., Corry C. i inni: Visual C++2.x Podręcznik programisty; LT&P, Warszawa 1996
Każda inna dokumentacja lub podręcznik programisty Visual C++
Laboratorium Podstaw Informatyki Strona 9
Zakład Metrologii AGH