Programowanie aplikacji okienkowych Windows
•	Wykład i prezentacje kodu

•	© Michał Turek, AGH Kraków
Środowisko
•	Microsoft Visual Studio
•	Starsze wersje: 5.0, 6.0 - C++
•	Nowsze - na platformie .NET, wiele języków, wiele platform dla aplikacji
•	Układ Workspace/Projects
•	W MFC (Microsoft Fundation Classes) popularne wersje projektu:
•	Biblioteka dll
•	Formatka activeX
•	Aplikacja konsoli win32 z MFC
•	Aplikacja graficzna MFC

Visual Studio - zakładki nawigatora
Visual Studio - przykłady edytorów (I)
Visual Studio - przykłady edytorów (II)
•	Wizualne nanoszenie i konfiguracja formatek graficznych
Visual Studio - Class Wizard
•	Dostępny pod skrótem Ctrl-W
•	Generator kodu dotyczącego zarządzania komunikatami, zmiennymi składowymi, implementacją klas.
Podział aplikacji graficznych MFC
•	Dialog - based

•	Single Document Interface  (SDI)

•	Multiple Document (MDI)
Wersja kompilacji
•	Możliwe jest szablonowanie budowy aplikacji wynikowej do różnych wersji.
•	Przeważnie wykorzystywane do tworzenia wersji testowej (Debug) i wynikowej (Release)
•	Wersja testowa posiada wbudowane asercje testujące poprawność wszelkich zmiennych programu. 
Wykonuje się znacznie wolniej, 
bazuje na specjalnej kopii 
bibliotek MFC (z asercjami). 
Nie będzie funkcjonowała 
na maszynie nie posiadającej 
zainstalowanego środowiska.
Aplikacja 1 (I)
•	Aplikacja wygenerowana jako Dialog-based. Po utworzeniu klas do aplikacji dołączono zasoby.
•	Główne okno aplikacji jest tworzone jako okno modalne. Zostało wyposażone w formatki. Do klasy aplikacji dołączono zmienne skojarzone z formatkami.
•	Dołączono obsługę komunikatów związanych ze zdarzeniami na niektórych formatkach.
•	Zaprezentowano sposób wymiany danych na drodze zmienna-formatka.
•	Prezentacja kodu #1
Aplikacja 1 (II)
•	Rozbudowa poprzedniej aplikacji o obsługę timerów systemowych. Uaktywniony timer generuje komunikat, który może byś przechwycony przez procedurę jego obsługi w aplikacji. Timerów może być wiele - są identyfikowane liczbowo.
•	Kontrola inicjalizacji i zamknięcia aplikacji - przeciążanie metod OnClose(), OnCancel() klasy CDialog;
•	Kontrola zdarzeń związanych z oknem aplikacji
•	Prezentacja kodu #2

Aplikacja 1 (III)
•	Wyświetlanie komunikatów i zapytań do użytkownika: MessageBox(”Napis”,”Tytul”,flagi):
•	Flagi przycisków: MB_ABORTRETRYIGNORE, MB_OK, MB_OKCANCEL,MB_YESNO,MB_YESNOCANCEL
•	Flagi Ikon: MB_ICONINFORMATION, MB_ICONQUESTION, MB_ICONSTOP, MB_ICONEXCLAMATION
•	Wyświetlanie okien modalnych: Tworzona jest nowa klasa okna, następnie przy użyciu metody doModal() jest tworzona instancja klasy.
•	Prezentacja kodu #3
Aplikacja 1 (IV)
•	Tworzenie i wyświetlanie okien niemodalnych: Tworzona jest nowa klasa okna. Konstruktor klasy musi jawnie wywołać metodę Create() dla okna. Sterowanie nie jest blokowane jak poprzednio na wywołaniu metody doModal(), więc możliwe jest otwarcie wielu okien, przełączanie między nimi, w tym między oknem głównym aplikacji.
•	Prezentacja kodu #4
Aplikacja 2 (I)
•	Używanie kontekstu graficznego aplikacji - użycie metody OnPaint()
•	Ładowanie grafiki z plików i wyświetlanie w tle aplikacji
•	Grafiki w zasobach: Tworzenie wewnętrznym edytorem,  przypisywanie statycznie do formatki typu Picture.
•	Prezentacja kodu #5

Aplikacja 2 (II)
•	Zdarzenia myszy - przechwytywanie zdarzeń związanych z ruchem i akcjami myszy.
•	Okna graficzne bez ramek.
•	Programowe ustawianie, przesuwanie okien aplikacji.
•	Regiony okien - tworzenie okien dowolnego kształtu.

•	Prezentacja kodu #6
Aplikacja 2 (III)
•	Konwersja komunikatów do obiektów aplikacji. Możliwe jest przechwycenie komunikatów zanim zostaną skierowane go konkretnego komponentu aplikacji. Przechwycone komunikaty można modyfikować lub powodować akcje związane z wystąpieniem tych komunikatów.
•	Różnica pomiędzy kontekstami urządzeń CPaintCD i CClientCD.
•	Malowanie w oknie rodzica okna aplikacji - czyli na ekranie zewnętrznym.
•	Prezentacja kodu #7
Aplikacja 3 (I)
•	Zarządzanie listą drzewiastą. Dodawanie elementów, odczyt i zmiana treści elementów
•	Sterowanie focusem formatek
•	Prezentacja kodu #8

Aplikacja 3 (II)
•	Zarządzanie listami typu ComboBox i ListBox. Dodawanie elementów. Definiowanie danych elementów
•	Prezentacja kodu #9
Linker kodu
•	Procedura linkowania:
•	Podział na pliki nagłówkowe i pliki kodu
•	Kody kompilowane .obj
•	Biblioteki linkera .lib
•	Zasada użycia funkcji bibliotecznych 
•	Biblioteki dynamiczne .dll
Biblioteka dll
•	Tworzenie biblioteki:
•	Kreator bibliotek dll / Win32
•	Definiowanie eksportów dll w postaci:
•	atrybutów
•	klas
•	metod
•	Generowanie biblioteki. Użycie plików nagłówkowych i bibliotek linkera jako materiałów do kompilacji i linkowania klientów dll.
•	Prezentacja kodu #10
Użycie biblioteki dll 
- Aplikacja 4
•	Przygotowanie importu z biblioteki:
•	Dołączenie do projektu nagłówków importowanych zasobów
•	Dołączenie bibliotek do linkera
•	Wstawienie (#include) nagłówka do pliku w którym będą wywołania importowanych zasobów
•	Użycie importowanej klasy, metody, atrybutu.
•	Dostarczenie biblioteki dll do tworzonej aplikacji.
•	Prezentacja kodu #11
Biblioteka MFC dll
•	Tworzenie biblioteki:
•	Kreator bibliotek dll / Win32
•	Definiowanie zasobów  analogicznie jak w przypadku aplikacji
•	Definiowanie klasy dialogu identycznie jak w przypadku aplikacji
•	Definiowanie eksportów funkcji: tworzącej dialog, pobierającej z zasobów łańcuch
•	Prezentacja kodu #12

Użycie biblioteki MFC dll 
- Aplikacja 5
•	Przygotowanie importu z biblioteki - analogicznie jak w poprzednim przypadku
•	Wywołanie metod importowanych
•	Prezentacja kodu #13

Aplikacja 6 (I)
•	Użycie wielu kursorów myszy - ładowanie kursora z zasobów i ustawianie jako bieżącego.
•	Ustalanie kolejności tabulacji formatek
•	Wykorzystywanie “gumowej taśmy” - klasy CRectTracker
•	Klasy CRect, CPoint
•	Pobieranie wskazania na aplikację
•	Prezentacja kodu #14
Aplikacja 6 (II)
•	Rysowanie w kontekście urządzenia poza obsługa zdarzenia paint()
•	Ładowanie i rysowanie ikon systemowych oraz ikon z zasobów. Problem odrysowywania ekranu.

•	Prezentacja kodu #15
Aplikacja 6 (III)
•	Kontrolki ze zintegrowanymi grafikami:
•	Tworzenie listy drzewiastej z własnymi symbolami graficznymi
•	Klasa szeregująca grafiki - CImageList
•	Tablicowanie danych do listy drzewiastej
•	Dynamiczna zmiana parametrów z szablonów formatek - metoda ModifyStyle()
•	Wymuszenie odmalowania widoku (metoda Invalidate()) lub jego fragmentu (metoda InvalidateRect(CRect region)) 
•	Prezentacja kodu #16
Aplikacja 7
•	Używanie formatek ActiveX zarejestrowanych w systemie:
•	Osadzania formatki  
•	Implementacja klasy wywiedzionej z formatki
•	Zdarzenia formatki i wymiana danych
•	Sterowanie formatką
•	Przykłady: osadzona formatka kalendarza i przeglądarki WWW
•	Prezentacja kodu #17
Aplikacja 8 (I)
•	Standardowe dialogi pomocnicze
•	Tworzenie modalnego dialogu
•	Komunikacja 
•	Przykłady: pobieranie pliku od użytkownika, wybieranie koloru przez użytkownika, wybieranie czcionki.
•	Prezentacja kodu #18	
Aplikacja 8 (II)
•	Operacje na plikach:
•	Klasa CFile, CStdioFile
•	Przechwytywanie wyjątków operacji na plikach
•	Użycie formatek do edycji tekstu w wielu liniach
•	Zapis i odczyt ustawień konfiguracyjnych w systemie Windows:
•	Konfiguracja w plikach .ini
•	Przełączanie na zapis/odczyt w rejestrze systemu
•	Prezentacja kodu #19
Aplikacja 9
•	Tworzenie i dokowanie zakładek z oknami dialogowymi:
•	Przygotowanie klasy wywiedzionej z CPropertySheet
•	Przygotowanie klas zakładek wywiedzionych z CPropertyPage
•	Instalowanie zakładek w obiekcie klasy pochodnej z CPropertySheet
•	Powiązanie klasy z szablonem dialogu (powstające po wywołaniu konstruktora nadklasy)
•	Utworzenie okna zakładki przez wywołanie DoModal()
•	Prezentacja kodu #20

Aplikacja 10
•	Tworzenie obsługa menu
•	Tworzenie menu na bazie zasobów
•	Indywidualne dodawanie komend do menu systemowego oraz przechwytywanie komunikatu WM_SYSCOMMAND. Tworzenie liczbowych identyfikatorów komunikatów.
•	Przechwytywanie komunikatów standardowego menu - komunikat COMMAND (tylko powiadomienie) i UPDATE_COMAND_UI (wskaźnik do komendy modyfikującej menu, dający możliwość wprowadzania zmian)
•	Tworzenie menu typu popup na bazie zasobów i z użyciem klasy CMenu
•	Prezentacja kodu #21
Aplikacja 11 (I)
•	Tworzenie pasków pomocy (tzw. ToolTips):
•	Użycie klasy CToolTipCtrl
•	Dodawanie obszarów śledzonych
•	Ustawianie właściwości ToolTips
•	Prezentacja kodu #22

Aplikacja 11 (II)
•	Specjalizowanie klas formatek MFC
•	Podejście do klasy formatki jako używanego w programie komponentu
•	Ułatwienie realizacji funkcjonalności interfejsu
•	Wielokrotne użycie klasy
•	Łatwość programowania interakcji poprzez przekazywanie komunikatów
•	Modyfikacja szablonu formatki (metodą PreSubclassWindow()) przed utworzeniem jej instancji.
•	Prezentacja kodu #23

Aplikacja 11 (III)
•	Weryfikacja poprawności danych z formatki:
•	Użycie Class Wizard do definiowania kryteriów sprawdzania
•	Funkcje sprawdzające typu Data Validation (DDV)
•	Tworzenie własnych funkcji DDV
•	Stosowanie klas składujących na przykładzie CStringArray i CObArray
•	Funkcje edycji kolekcji. Dostęp przez nazwę i wskaźnik. Konwersje wskaźników
•	Dynamiczne tworzenie obiektów kolekcji
•	Likwidacja kolekcji razem ze wszystkimi obiektami, przeciążanie destruktora klasy zawierającej kolekcję.
•	Prezentacja kodu #24
Aplikacja 12 (I)
•	Generowanie i przechwytywanie wyjątków
•	Zastosowania sieciowe: pobieranie plików przez HTTP, obsługa sesji HTTP, logowania do sesji
•	Użycie klas CInternetSession, CHttpConnection, CHttpFile
•	Tworzenie sesji, połączenia na podstawie sesji, wysyłanie żądań HTTP wraz z własnymi nagłówkami HTTP, analiza statusu operacji HTTP, pobieranie od użytkownika i przekazywanie danych identyfikacyjnych.
•	Prezentacja metody AfxParseURL()
•	Prezentacja kodu #25	

Aplikacja 12 (II)

•	Zastosowania sieciowe: pobieranie plików przez FTP, obsługa logowania do sesji:
•	Użycie klas CInternetSession, CFtpConnection
•	Tworzenie sesji, połączenia na podstawie sesji, otwieranie plików zdalnych FTP do odczytu/zapisu sekwencyjnego, pobieranie plików na dysk.

•	Prezentacja kodu #26
Aplikacja 12 (III)
•	Połączenia z użyciem socket’ów:
•	Klasa CSocket
•	Konieczność inicjalizacji CSocket w aplikacji - AfxSocketInit()
•	Tworzenie obiektu Csocket
•	Otwieranie połączenia
•	Buforowane czytanie z pliku (bez stosowania znaków końca linii)
•	Tworzenie bufora
•	Kontrola ilości przeczytanych bajtów
•	“Wypychanie” wpisanych danych
•	Prezentacja kodu #27

Aplikacja 13 (I)
•	Przetwarzanie współbieżne
•	Metoda tworząca wątek: AfxBeginThread
•	Tworzenie wątku na podstawie klasy
•	Definiowanie klasy wywiedzionej z CWinThread
•	Przeciążanie odpowiednich metod w klasie
•	Tworzenie wątku na podstawie metody
•	Kryteria definiowania metody: UINT Metoda( LPVOID pParam )
•	Metody sterujące wątkiem
•	Ustawianie priorytetów wątków
•	Prezentacja kodu #28
Aplikacja 14 (I)
•	Architektura Dokument/Widok:
•	Wybór odpowiedniej klasy bazowej dla dokumentu (CEditView, CScrollView, CListView itp.)
•	Dostęp do dokumentu z widoku
•	Ustalanie wielkości widoku
•	Okna z paskami przewijania, wymiary widoku graficznego:
•	Metody: SetScrollSizes - ustawienie obszaru przewijanego, GetScrollPosition - pobranie ustawienia widoku, GetTotalSize - pobranie wielkości obszaru przewijanego, GetScrollLimit - pobranie liczbowego limitu konkretnego paska (SB_HORZ lub SB_VERT)
•	Zdarzenie przewijania: OnScroll, OnHScroll, OnVScroll

Aplikacja 14 (II)
•	Modyfikacja standardowych metod realizujących przewijanie widoku:
•	Menu w aplikacji z dokumentem
•	Dynamiczna zmiana wyglądu menu
•	Możliwość przechwytywania komunikatów menu w klasie ramki, widoku lub dokumentu
•	Definiowanie rejestrowanego typu dokumentu - generator pliku .reg dołączanego do projektu
•	Prezentacja kodu #29
Aplikacja 14 (III)
•	Paski narzędzi:
•	Dokowanie:
•	Metoda EnableDocking - umożliwienie dokowania paska, zgodnie z flagami: CBRS_ALIGN_ANY,  CBRS_ALIGN_TOP, CBRS_ALIGN_BOTTOM itd.
•	Metoda klasy CFrameWnd::DockControlBar(adr_obiektu, położenie) - dokowanie paska
•	Modyfikacja przycisków:
•	Zapamiętanie stanu wciśnięcia przycisku
•	Wpływ na przyciski inne niż wciskany
•	Prezentacja kodu #30
Aplikacja 14 (IV)
•	Paski statusu:
•	Tworzenie paska statusu
•	Metoda SetIndicators ustawiająca pola paska
•	Dynamiczne dodawanie pól paska
•	Dynamiczne wpisywanie tekstu do pól paska
•	Prezentacja kodu #31

Aplikacja 15 (I)
•	Paski dialogowe
•	Są specjalną wersją dialogów, posiadającą własne formatki lecz przystosowaną do dokowania wewnątrz ramek (CFrameWnd) 
•	Tworzone dynamicznie jako instancje klasy CDialogBar na podstawie szablonu dialogu
•	Prosta obsługa komunikatów (komend) z paska polega na ręcznym uzupełnieniu mapy komunikatów:
•	ON_COMMAND(ID_FORMATKI_W_SZABONIE,Metoda)
•	Brak możliwości rozróżnienia danych z dwóch zadokowanych pasków stworzonych na podstawie tego samego szablonu
•	Prezentacja kodu #32
Aplikacja 15 (II)
•	Paski dialogowe - wymiana danych:
•	przetwarzanie przeważnie następuje w klasie widoku. Tam przydatne są funkcje pobierające wskaźniki:
•	GetDocument() - w dokumencie są dane do przetwarzania
•	GetParentFrame() - ramka przechowuje formatki i obiekty zadokowane
•	W przypadku konieczności obsługi wymiany danych (poza odbiorem komend) konieczne jest:
•	Użycie metody GetDlgItem klasy CWnd, dającej wskaźnik na formatkę a pobierającą identyfikator z szablonu-wzorca. 
•	Pobranie wartości danych formatki z użyciem stosownej funkcji (nie ma zmiennej powiązanej z tą wartością)
•	Prezentacja kodu #33

Aplikacja 15 (III)
•	Dzielenie widoku okna
•	Klasa CSplitterWnd
•	Metoda do tworzenia podziału CreateStatic lub Create, tworzenia widoków: CreateView
•	Przeciążenie metody OnCreateClient i wyeliminowanie standardowego tworzenia widoku na bazie np. klasy CAplikacjaView( na bazie szablonu SDI/MDI)
•	Możliwość przypisania różnych klas widoku do fragmentów okna. Zdefiniowane klasy pobieramy dyrektywą RUNTIME_CLASS(nazwa)
•	Podział w kierunku pionowym, poziomym lub obydwu jednocześnie
•	Prezentacja kodu #34

Aplikacja 16 (I)
•	Przechowywanie danych w klasie dokumentu, często w obiektach specjalnie przygotowanych do tego klas:
•	konstrukcja obiektu w konstruktorze klasy
•	ewentualne własna metoda odmalowująca obiekt na ekranie
•	Użycie standardowych zdarzeń obsługiwanych przez klasę CSingleDocTemplate
•	OnNewDocument() - wymaga dodania procedury kasującej zawartość obiektów dokumentu

Aplikacja 16 (II)
•	Czynności edycyjne przejmuje klasa widoku, wywierając wpływ na zawartość dokumentu - np. przechwytując zdarzenia myszy czy klawiatury. W kodzie dodatkowo: użycie generatora liczb losowych /metoda int rand()/, przesunięcie generatora liczb losowych /int srand()/.
•	Odmalowywanie ekranu (wyglądu graficznego dokumentu) leży także po stronie (ta klasa otrzymuje komunikaty i ma kontekst graficzny (metoda OnDraw)
•	Prezentacja kodu #35
Aplikacja 16 (III)
•	Serializacja danych (I):
•	Metody serializacji w klasach obiektów przechowujących dane dokumentu
•	Hierarchiczne wywoływanie serializacji
•	Makra DECLARE_SERIAL(Klasa) i IMPLEMENT_SERIAL(Klasa,Nadklasa,int wersja) dostarczają cały kod korzystający z Serialize() i potrzebny do realizacji zapisu do pliku
•	Format pliku - dane binarne
•	Kontrola wersji pliku z udostępnieniem jej w metodzie Serialize()

Aplikacja 16 (IV)
•	Serializacja danych (II): 
•	Tworzenie obiektu CArchive, w niej narzędzia do modyfikacji procesu zapisu/odczytu. Klasa dostarcza metody, umożliwiające:
•	Pobranie wersji i przeprowadzenie procedury zgodnie z nią - UINT GetObjectSchema()
•	Pobranie wskaźnika na przetwarzany plik -  CFile* GetFile()
•	Pobranie informacji o kierunku procedury - IsLoading( ) IsStoring( ) 
•	Bezpośrednie wymuszenie serializacji konkretnego obiektu - ReadObject(klasa), WriteObject(klasa) 
•	Prezentacja kodu #36
Aplikacja 17 (I)
•	Dostęp do baz danych (I)
•	Klasy CRecordset (dla ODBC)
•	Konieczność definiowania mechanizmu DataExchange
•	Technika wykonania: wywiedzenie klasy potomnej z jednej z powyższych i przeciążanie metod:
•	Inicjalizacji składowych: konstruktor
•	Zwracających łańcuch połączenie z bazą: GetDefaultConnect 
•	Wymieniających dane ze zmiennymi prywatnymi naszej klasy:DoFieldExchange 
•	Definiujących tabele w źródle danych: GetDefaultSQL
•	Mechanizm wymiany danych obsługiwany identycznie jak w przypadku wymiany danych formatek: makra wymieniające określony typ na drodze pole tabeli - sprzężona zmienna składowa
Aplikacja 17 (II)
•	Dostęp do baz danych (II)
•	Konieczność ręcznego dołączenia plików nagłówkowych w stdafx.h: afxdb.h dla CRecordset 
•	Poruszanie się po tabelach bazy za pośrednictwem Recordsetów
•	Podstawowe metody: AddNew, Update, Edit, Requery, MoveFirst, Movelast, MovePrev, MoveNext, IsBOF, IsEOF
•	Filtrowanie danych - z użyciem składni SQL, komendta filtra zapisywana w SQL do składowych m_strFilter i m_strSort
•	Wercja ODBC (prezentowana obecnie) wymaga konfigurowania źródła danych ODBC
•	Operacje w przypadku błędów generują wyjątek CDBException
•	Prezentacja kodu #37

Aplikacja 17 (III)
•	Dostęp do baz danych poprzez DAO:
•	Zastosowanie klasy CDaoRecordset (dla DAO) zamiast CRecordset 
•	Plik nagłówkowy klas MFC: afxdao.h dla CDaoRecordset zamiast afxdb.h
•	Generowany wyjątek operacji: CDaoException zamiast CDBException
•	Połączenie bezpośrednio ze źródłem plikowym - metoda GetDefaultDBName (zamiast poprzednio: GetDefaultConnect) zwraca nazwę pliku bazy danych
•	Prezentacja kodu #38

Aplikacja DirectX
•	Prezentacja interfejsu DirectDraw
•	Tworzenie buforów, powierzchni do renderowania
•	Ładowanie grafik
•	Konfigurowanie wyświetlania DirectDraw - tryb pełnoekranowy
•	Cykl realizacji wyświetlania: kasowanie bufora, renderowanie warstw w buforze, kopiowanie na ekran
•	Prezentacja kodu #39