P019 - Pierwszy program dla MS-Windows |
---|
Programy uruchomiono w środowisku Bloodshed Dev-C++ 4.9.9.2. |
// I Liceum Ogólnokształcące // im. K. Brodzińskiego // w Tarnowie //-------------------------- // Koło informatyczne 2006/7 //-------------------------- // Program: P019-01 //-------------------------- #include <windows.h> main() { MessageBox(0, "Witaj w świecie okienkowym\nI-LO w Tarnowie", "Pierwszy program dla MS-Windows", MB_OK); ExitProcess(0); } |
Efekt uruchomienia programu
Na kolejnych kilku zajęciach zajmiemy się podstawami programowania systemu MS-Windows. W systemie tym program musi współpracować ze środowiskiem graficznym. Dlatego programowanie MS-Windows wymaga dobrej znajomości sposobu pracy systemu oraz setek procedur, za pomocą których komunikujemy się z różnymi składnikami systemu.
W pierwszym programie wykorzystujemy dwie procedury systemowe, które wykonają za nas "czarną robotę". Ich deklaracje są umieszczone w pliku nagłówkowym windows.h, który bezwarunkowo musi być dołączony do aplikacji tworzonych dla środowiska MS-Windows.
Już w tak prostym programie występuje kilka pojęć, które musimy poznać, aby efektywnie programować okienka:
Proces
System MS-Windows jest wielozadaniowym systemem operacyjnym (ang. multitasking operating system). Oznacza to, iż naraz w pamięci komputera może być uruchomione wiele różnych programów. Jeśli komputer posiada jeden procesor, to oczywiście programy te nie wykonują się jednocześnie. System zarządzania wykonaniem zadań (ang. task scheduler) tworzy tzw. kolejkę procesów, na której umieszcza odwołania do uruchomionych programów lub ich procesów - jeden program może utworzyć kilka równoległych procesów, które nazywamy wątkami (ang. threads).
Programy w kolejce uruchamiane są naprzemiennie co pewien czas. Działają przez krótką chwilę, następnie są zamrażane i z kolejki uruchomiony zostaje kolejny program (proces). Dzięki temu użytkownikowi "wydaje" się, iż jednocześnie pracuje wiele programów.
Gdy proces kończy swoje działanie, musi o tym poinformować system. Do tego celu służy właśnie wywołanie procedury ExitProcess(). Parametrem jest kod wyjścia, czyli 32-bitowa liczba zwracana przez proces przy zakończeniu. Ponieważ procesy mogą być tworzone jako wątki w innych procesach, kod wyjścia służy często jako informacja, czy dany proces zakończył się poprawnie, czy też nie. U nas nie wykorzystujemy kodu wyjścia, zatem procedurę wywołujemy z parametrem 0:
ExitProcess(0);
Uchwyt / dojście
Ponieważ w pamięci może znajdować się kilka programów, nie mogą nawzajem zakłócać się. W tym celu w systemie MS-Windows istnieje mechanizm ochrony pamięci przydzielanej procesom. Mechanizm ten odnosi się również do danych wewnętrznych systemu MS-Windows. Oznacza to, iż procesy nie mogą odwoływać się bezpośrednio do obszarów danych systemu lub innych procesów - muszą to robić za pomocą odpowiednich funkcji systemowych (i bardzo dobrze, inaczej jakiś źle lub złośliwie napisany program mógłby narobić wiele zamieszania).
Problem ten rozwiązano za pomocą tzw. uchwytów lub dojść (ang. handle). Są to liczby całkowite, które jednoznacznie identyfikują wewnętrzne struktury danych Windows. Możemy je traktować jak numery identyfikacyjne. Wiele funkcji systemowych będzie wymagało jako jednego z parametrów właśnie uchwytu np. okienka, kontrolki, urządzenia graficznego itp., na którym dana operacja ma zostać przeprowadzona. Elementy systemu identyfikowane przez uchwyty nazywamy zasobami (ang. resources).
Jeśli uchwyt ma wartość 0, to nie identyfikuje żadnego zasobu.
Funkcja MessageBox()
W systemie MS-Windows jest udostępniona dla programisty biblioteka procedur i funkcji, zwana WinAPI (Windows Application Programming Interface - interfejs programowy aplikacji Windows). W naszym programie wykorzystujemy z WinAPI funkcję MessageBox() (okienko wiadomości), która tworzy proste okienko wyświetlając w nim przekazane w parametrach teksty oraz przyciski. Deklaracja tej funkcji jest następująca:
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
HWND - typ danych dla uchwytów okienek (ang. Handle of WiNDow). LPCTSTR - typ danych oznaczający adres (wskaźnik) tekstu zakończonego znakiem '\0' (ang. Long Pointer of ConstanT STRing) UINT - typ danych oznaczający 32-bitową liczbę całkowitą bez znaku (ang. Unsigned INTeger).
hWnd - określa uchwyt okna procesu, z którego wywołana została funkcja MessageBox(). W naszym programie nie utworzyliśmy żadnego okna, dlatego jako uchwyt przekazaliśmy wartość 0. lpText - wskaźnik tekstu, który zostanie umieszczony w oknie informacyjnym. Tekst może składać się z kilku wierszy zakończonych znakiem '\n'. lpCaption - wskaźnik tekstu, który pojawi się na pasku tytułowym okienka informacyjnego uType - określa rodzaj okna. Głównie chodzi tutaj o zestaw przycisków, które pojawią się w obszarze okna oraz o ikonkę umieszczaną po lewej stronie tekstu. Możliwych wartości jest dużo. My zastosowaliśmy stałą MB_OK, która powoduje wyświetlenie pod tekstem pojedynczego przycisku OK. Kliknięcie w ten przycisk kończy działanie funkcji MessageBox(). Typ okna informacyjnego możemy zestawiać z poniższych grup stałych za pomocą operatora C++ | (suma bitowa):
Grupa stałych określająca wyświetlane przyciski:
MB_ABORTRETRYIGNORE - przyciski Przerwij, Ponów próbę, Ignoruj
MB_HELP - oprócz przycisku OK w okienku pojawi się przycisk Pomoc. Kliknięcie w ten przycisk lub naciśnięcie klawisza F1 spowoduje wysłanie przez Windows do właściciela okna informacyjnego wiadomości WM_HELP. Obsługą takich wiadomości zajmujemy się w dalszych przykładach.
MB_OK - pojawi się jeden przycisk OK. Jest to wartość standardowa.
MB_OKCANCEL - pojawią się przyciski OK i Anuluj.
MB_RETRYCANCEL - pojawią się przyciski Ponów próbę i Anuluj
MB_YESNO - pojawią się przyciski Tak i Nie
MB_YESNOCANCEL - pojawią się przyciski Tak, Nie i Anuluj
Do powyższych wartości możemy dołączyć (operator |) stałe określające rodzaj wyświetlanej ikony w okienku informacyjnym:
MB_ICONEXCLAMATION - pojawi się ikona znaku z wykrzyknikiem.
MB_ICONINFORMATION - pojawi się dymek z małą literką i.
MB_ICONQUESTION - pojawi się dymek z pytajnikiem.
MB_ICONSTOP - system wygeneruje krótki dźwięk i pojawi się ikona stopu.
Kolejna grupa stałych określa, który z przycisków (jeśli jest ich więcej niż 1) okienka będzie przyciskiem standardowym - takim, który jest uaktywniany po naciśnięciu klawisza Enter.
MB_DEFBUTTON1 - pierwszy przycisk okna staje się przyciskiem standardowym. Jest to wartość domyślna.
MB_DEFBUTTON2 - standardowy będzie przycisk drugi.
MB_DEFBUTTON3 - trzeci.
MB_DEFBUTTON4 - czwarty.
Zwróć uwagę, iż funkcja MessageBox() zwraca wartość typu int. Wartość ta zależy od wybranego typu okna (parametr uType) i może być następująca:
IDABORT - wybrano przycisk Przerwij
IDCONTINUE, IDRETRY, IDTRYAGAIN - wybrano przycisk Ponów próbę
IDCANCEL - wybrano przycisk Anuluj
IDIGNORE - wybrano przycisk Ignoruj
IDNO - wybrano przycisk Nie
IDOK - wybrano przycisk OK
IDYES - wybrano przycisk Tak.
Chociaż MessageBox() służy głównie do powiadamiania użytkownika o jakiś zdarzeniach powstałych w trakcie pracy programu (najczęściej są to komunikaty błędów), to poniżej mamy przykładową grę w odgadywanie liczb od 0 do 15 wykorzystującą tą funkcję. Zasady są bardzo proste - użytkownik wymyśla sobie liczbę od 0 do 15, a następnie odpowiada na pytania komputera. Komputer odgadnie liczbę po 4 pytaniach.
// I Liceum Ogólnokształcące // im. K. Brodzińskiego // w Tarnowie //-------------------------- // Koło informatyczne 2006/7 //-------------------------- // Program: P019-02 //-------------------------- #include <windows.h> #include <sstream> using namespace std; main() { char tytul[] = "ZGADYWANKA LICZB (C)2007 I-LO w Tarnowie"; MessageBox(0, "Wymyśl liczbę z zakresu od 0 do 15 i kliknij OK", tytul, MB_OK | MB_ICONINFORMATION); // generujemy tablicę masek bitowych int maski[] = {1,2,4,8}; srand((unsigned)time(NULL)); for(int i = 0; i < 50; i++) { int x = rand() % 4; int y = rand() % 4; int z = maski[x]; maski[x] = maski[y]; maski[y] = z; } // zadajemy 4 pytania, w każdym umieszczamy liczby zawierające // bit z bieżącej maski. Odpowiedź TAK powoduje dodanie maski do // zgadywanej liczby int liczba = 0; for(int i = 0; i < 4; i++) { ostringstream sout; sout << "Pytanie nr " << i + 1 << "\n\nCzy twoja liczba jest jedną z liczb : \n\n"; for(int j = 1; j < 16; j++) if(j & maski[i]) sout << j << " "; if(MessageBox(0, sout.str().c_str(), tytul, MB_YESNO | MB_ICONQUESTION) == IDYES) liczba += maski[i]; } // Wyświetlamy wynik ostringstream sout; sout << "Twoją liczbą jest liczba : " << liczba; MessageBox(0, sout.str().c_str(), tytul, MB_OK | MB_ICONINFORMATION); // Koniec ExitProcess(0); } |
Efekt uruchomienia programu |
---|
![]()
|
Objaśnienia
W przedstawionym powyżej programie występuje kilka fragmentów, które wymagają wyjaśnienia.
int maski[] = {1,2,4,8}; srand((unsigned)time(NULL)); for(int i = 0; i < 50; i++) { int x = rand() % 4; int y = rand() % 4; int z = maski[x]; maski[x] = maski[y]; maski[y] = z; } |
Liczbę użytkownika odgadujemy testując, czy zawiera odpowiednie wagi
binarne 1,2,4 i 8. Na przykład liczba 13 w zapisie binarnym postać: Oznacza to, iż zawiera wagi 8, 4 i 1. Do testowania
wag będziemy używali tablicy maski[]. Jednakże, aby zdezorientować
użytkownika, zawartość tablicy pomieszamy losowo. Np. jeśli na początku
ma ona zawartość:
|
int liczba = 0; |
W tej zmiennej będziemy zbierać wagi wskazane przez użytkownika, które występują w jego liczbie. |
for(int i = 0; i < 4; i++) { ostringstream sout; sout << "Pytanie nr " << i + 1 << "\n\nCzy twoja liczba jest jedną z liczb : \n\n"; for(int j = 1; j < 16; j++) if(j & maski[i]) sout << j << " "; if(MessageBox(0, sout.str().c_str(), tytul, MB_YESNO | MB_ICONQUESTION) == IDYES) liczba += maski[i]; } |
Wykonujemy cztery obiegi pętli. W każdym obiegu
zadajemy pytanie, czy liczba wymyślona przez użytkownika znajduje się
wśród liczb zawierających wagę Na uwagę zasługuje typ |
ostringstream sout; sout << "Twoją liczbą jest liczba : " << liczba; MessageBox(0, sout.str().c_str(), tytul, MB_OK | MB_ICONINFORMATION); |
Gdy pętla wykona 4 pełne obiegi, w zmiennej liczba
otrzymamy wynik - liczbę wymyśloną przez użytkownika. Wykorzystując
ponownie klasę |
ExitProcess(0);
}
|
Kończymy działanie programu. |
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe