Wyjście Spis treści Poprzedni Następny
Autor:
©Iczelion |
©2008 mgr
Jerzy Wałaszek |
|
Teraz nadeszła naprawdę interesująca część graficznego interfejsu użytkownika - okienko dialogowe. Na tej lekcji (oraz na następnej) nauczymy się, jak użyć okienka dialogowego w funkcji głównego okna.
Załaduj pliki {przykładu 1} i {przykładu 2}
Jeśli bawiłeś się wystarczająco długo przykładami z poprzedniej lekcji, to zapewne odkryłeś, iż nie można przenosić się z jednej kontrolki na drugą przy pomocy klawisza TAB. Jedyną metoda uaktywnienia danej kontrolki jest kliknięcie jej myszką. Sytuacja taka jest raczej uciążliwa. Inną rzeczą, którą mogłeś zauważyć, jest to, iż zmieniłem kolor tła okna nadrzędnego na szary zamiast zwykłego białego, jak w poprzednich przykładach. Celem była zgodność kolorów kontrolek z kolorem okna głównego. Istnieje sposób obejścia tego problemu, lecz nie jest on łatwy. Musiałbyś utworzyć wszystkie kontrolki okna potomnego jako podklasy swojego okna głównego.
Powodem istnienia tej niewygody jest to, iż kontrolki okna potomnego są pierwotnie zaprojektowane do pracy z oknem dialogowym, a nie ze zwykłym oknem. Standardowym kolorem kontrolek okien potomnych, takich jak przycisk, jest kolor szary, ponieważ obszar roboczy okna dialogowego jest zwykle szary, więc bez problemu pasują do takich okien nie wywołując potu na czole programisty.
Zanim zagłębimy się w szczegóły, powinniśmy się dowiedzieć, czym jest okno dialogowe. Nie jest to nic innego niż zwykłe okno zaprojektowane do pracy z kontrolkami okna potomnego. System Windows udostępnia również wewnętrznego "zarządcę okienek dialogowych", który odpowiada za większość logiki obsługi klawiatury, jak np. uaktywnianie następnych kontrolek, gdy użytkownik naciska klawisz TAB, naciskanie standardowego przycisku, jeśli zostanie wciśnięty klawisz Enter, itp. a wszystko po to, aby programista mógł zająć się zadaniami na wyższym poziomie. Okienka dialogowe są zwykle stosowane w funkcji narzędzi wejścia/wyjścia. Jako takie, okienko dialogowe można uważać za "czarną skrzynkę" wejścia/wyjścia, co oznacza, iż nie musisz wiedzieć, jak ono pracuje wewnętrznie, aby móc je używać. Musisz jedynie posiadać wiedzę, jak z nim współpracować. Jest to główna zasada programowania zorientowanego obiektowo (OOP) zwana ukrywaniem informacji. Jeśli czarna skrzynka została idealnie zaprojektowana, to użytkownik może z niej korzystać bez najmniejszej wiedzy na temat jej funkcjonowania. Problemem jest to, iż czarna skrzynka musi być doskonała, a to trudno osiągnąć w rzeczywistym świecie. Funkcje API biblioteki Win32 są również takimi czarnymi skrzynkami.
Trochę odbiegliśmy od tematu. Wracajmy do rzeczy. Okienka dialogowe opracowano, aby zmniejszyć wkład pracy programistów. Zwykle umieszczając kontrolki okna potomnego na zwykłym oknie musisz je utworzyć jako podklasę oraz samodzielnie zaprojektować logikę obsługi klawiatury. Lecz jeśli umieścisz je na oknie dialogowym, ono zajmie się ich obsługą. Musisz jedynie wiedzieć, jak odczytać z okna dialogowego wprowadzoną przez użytkownika informację oraz jak wysłać do niego polecenia.
Okno dialogowe definiowane jest jako zasób, tak samo jak menu. Tworzysz szablon okna dialogowego opisując jego charakterystyki oraz jego kontrolki, a następnie kompilujesz skrypt zasobów za pomocą kompilatora zasobów.
Zwróć uwagę, iż wszystkie zasoby są umieszczane razem w tym samym pliku skryptu zasobów. Możesz zastosować dowolny edytor tekstu do napisania szablonu okna dialogowego, lecz nie polecam tej metody. Powinieneś skorzystać z wizualnego edytora zasobów do aranżacji kontrolek okna potomnego w oknie dialogowym, ponieważ praca ta jest trudna do wykonania na piechotę. Dostępne jest kilkanaście doskonałych edytorów zasobów. Większość głównych zestawów kompilatorów zawiera własne edytory zasobów. Możesz wykorzystać je do utworzenia skryptu zasobów dla swojego programu, a następnie usunąć z nich nieistotne fragmenty.
Istnieją dwa główne rodzaje okien dialogowych: modalne i niemodalne. Niemodalne okno dialogowe pozwala ci uaktywnić inne okno. Przykładem może być okno dialogowe Znajdź w programie MS Word. Wśród okien modalnych wyróżniamy dwa podtypy: modalne dla aplikacji oraz modalne dla systemu. Okno dialogowe modalne dla aplikacji nie pozwoli ci uaktywnić innego okna należącego do tej samej aplikacji, lecz możesz uaktywnić okno w INNEJ aplikacji. Okno dialogowe modalne dla systemu nie pozwoli ci przejść do żadnego innego okna, zanim nie obsłużysz go.
Niemodalne okno dialogowe tworzone jest przez wywołanie funkcji API CreateDialogParam. Modalne okno dialogowe tworzy się wywołując DialogBoxParam. Rozróżnienie pomiędzy oknem dialogowym modalnym dla aplikacji i modalnym dla systemu dokonuje się jedynie poprzez styl DS_SYSMODAL. Jeśli dołączysz ten styl w szablonie okna dialogowego, to będzie ono oknem dialogowym modalnym dla systemu.
Możesz komunikować się z dowolną kontrolką okna potomnego w oknie
dialogowym korzystając z funkcji
SendDlgItemMessage. Jej składnia jest następująca:
SendDlgItemMessage PROTO hwndDlg: DWORD,\ idControl: DWORD,\ uMsg: DWORD,\ wParam: DWORD,\ lParam: DWORD
To wywołanie API jest niesamowicie użyteczne przy
wymianie informacji z kontrolką okna potomnego. Na przykład jeśli chcesz pobrać
tekst z kontrolki edycyjnej, możesz to zrobić tak:
INVOKE SendDlgItemMessage, hDlg,\ ID_EDITBOX,\ WM_GETTEXT, 256, ADDR text_buffer
Informację na temat możliwych do wysłania wiadomości znajdziesz w plikach pomocy
dla funkcji API biblioteki
Win32 (jak zwykle z resztą w
takich przypadkach - pamiętaj o tym!).
System Windows udostępnia również kilka funkcji API specyficznych dla określonej kontrolki dla szybkiego ustawienia danych, na przykład GetDlgItemText, CheckDlgButton itp. Funkcje te są udostępniane dla wygody programisty, aby nie musiał szukać znaczenia wParam i lParam przy każdej wiadomości. Powinieneś z nich korzystać, gdy są dostępne, ponieważ funkcje takie ułatwiają późniejszą poprawę kodu aplikacji. Powróć do SendDlgItemMessage tylko wtedy, gdy dla danej kontrolki nie ma odpowiedniej funkcji API specyficznej dla niej.
Zarządca okienek dialogowych systemu Windows
wysyła niektóre wiadomości do specjalizowanej funkcji zwrotnej zwanej procedurą
okna dialogowego, która posiada następujący format:
DlgProc PROTO hDlg: DWORD ,\ iMsg: DWORD ,\ wParam: DWORD ,\ lParam: DWORD
Procedura okna dialogowego jest bardzo podobna do procedury okna z wyjątkiem
typu zwracanej wartości, która wynosi TRUE/FALSE
zamiast
LRESULT. Wewnętrzny zarządca okna dialogowego w
systemie Windows JEST pełnoprawną procedurą okna dla okna dialogowego.
Wywołuje on naszą procedurę okna dialogowego przy niektórych wiadomościach.
Generalną zasadą jest to, iż jeżeli nasza procedura okna dialogowego obsługuje
daną wiadomość, to
MUSI
zwrócić wartość TRUE w rejestrze eax, a jeśli tej
wiadomości nie obsługuje, to w eax musi zwrócić FALSE.
Zwróć uwagę, iż procedura okna dialogowego nie przekazuje nieobsługiwanych przez
nią wiadomości dalej do wywołania DefWindowProc, ponieważ
nie jest ona prawdziwą procedurą okna.
Istnieją dwa bezpośrednie wykorzystania okien dialogowych. Możesz je stosować jako okna główne swoich aplikacji lub używać ich do wprowadzania danych. Na tej lekcji zbadamy pierwsze podejście.
"Użycie okna dialogowego jako okna głównego" można zinterpretować dwojako.
Ta lekcja będzie dosyć długa. Przedstawię najpierw pierwsze rozwiązania, a później przyglądniemy się drugiemu.
Plik DIALOG.ASM - wersja nr 1.
.386 .MODEL FLAT, STDCALL OPTION CASEMAP:NONE WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD INCLUDE \masm32\include\windows.inc INCLUDE \masm32\include\user32.inc INCLUDE \masm32\include\kernel32.inc INCLUDELIB \masm32\lib\user32.lib INCLUDELIB \masm32\lib\kernel32.lib .DATA ClassName DB "DLGCLASS",0 MenuName DB "MyMenu",0 DlgName DB "MyDialog",0 AppName DB "Nasze pierwsze okno dialogowe",0 TestString DB "Och! Jestem w edytorze",0 .DATA? hInstance HINSTANCE ? CommandLine LPSTR ? buffer DB 512 DUP(?) .CONST IDC_EDIT EQU 3000 IDC_BUTTON EQU 3001 IDC_EXIT EQU 3002 IDM_GETTEXT EQU 32000 IDM_CLEAR EQU 32001 IDM_EXIT EQU 32002 .CODE start: INVOKE GetModuleHandle, NULL mov hInstance, eax INVOKE GetCommandLine mov CommandLine, eax INVOKE WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT INVOKE ExitProcess, eax WinMain PROC hInst: HINSTANCE,\ hPrevInst: HINSTANCE,\ CmdLine: LPSTR,\ CmdShow: DWORD LOCAL wc: WNDCLASSEX LOCAL msg: MSG LOCAL hDlg: HWND mov wc.cbSize, SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW OR CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra, NULL mov wc.cbWndExtra, DLGWINDOWEXTRA push hInst pop wc.hInstance mov wc.hbrBackground, COLOR_BTNFACE+1 mov wc.lpszMenuName, OFFSET MenuName mov wc.lpszClassName, OFFSET ClassName INVOKE LoadIcon, NULL, IDI_APPLICATION mov wc.hIcon, eax mov wc.hIconSm, eax INVOKE LoadCursor, NULL, IDC_ARROW mov wc.hCursor, eax INVOKE RegisterClassEx, ADDR wc INVOKE CreateDialogParam, hInstance, ADDR DlgName, NULL, NULL, NULL mov hDlg, eax INVOKE GetDlgItem, hDlg, IDC_EDIT INVOKE SetFocus, eax INVOKE ShowWindow, hDlg, SW_SHOWNORMAL INVOKE UpdateWindow, hDlg .WHILE TRUE INVOKE GetMessage, ADDR msg, NULL, 0, 0 .BREAK .IF (!eax) INVOKE IsDialogMessage, hDlg, ADDR msg .IF eax==FALSE INVOKE TranslateMessage, ADDR msg INVOKE DispatchMessage, ADDR msg .ENDIF .ENDW mov eax, msg.wParam ret WinMain ENDP WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_CREATE INVOKE SetDlgItemText, hWnd, IDC_EDIT, ADDR AppName .ELSEIF uMsg==WM_DESTROY INVOKE PostQuitMessage, NULL .ELSEIF uMsg==WM_COMMAND mov eax, wParam .IF lParam==0 .IF ax==IDM_GETTEXT INVOKE GetDlgItemText, hWnd, IDC_EDIT, ADDR buffer, 512 INVOKE MessageBox, NULL, ADDR buffer, ADDR AppName, MB_OK .ELSEIF ax==IDM_CLEAR INVOKE SetDlgItemText, hWnd, IDC_EDIT, NULL .ELSE INVOKE DestroyWindow, hWnd .ENDIF .ELSE mov dx, WORD PTR wParam + 2 .IF dx==BN_CLICKED .IF ax==IDC_BUTTON INVOKE SetDlgItemText, hWnd, IDC_EDIT, ADDR TestString .ELSEIF ax==IDC_EXIT INVOKE SendMessage, hWnd, WM_COMMAND, IDM_EXIT, 0 .ENDIF .ENDIF .ENDIF .ELSE INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam ret .ENDIF xor eax, eax ret WndProc ENDP END start
Plik DIALOG.RC
#include "resource.h" #define IDC_EDIT 3000 #define IDC_BUTTON 3001 #define IDC_EXIT 3002 #define IDM_GETTEXT 32000 #define IDM_CLEAR 32001 #define IDM_EXIT 32003 MyDialog DIALOG 10, 10, 205, 60 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Nasze pierwsze okno dialogowe" CLASS "DLGCLASS" { EDITTEXT IDC_EDIT, 15, 17, 111, 13, ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP DEFPUSHBUTTON "Przywitaj się", IDC_BUTTON, 141, 10, 52, 13 PUSHBUTTON "&Koniec", IDC_EXIT, 141, 26, 52, 13 } MyMenu MENU { POPUP "Testowe Kontrolki" { MENUITEM "Pobierz tekst", IDM_GETTEXT MENUITEM "Wymaż tekst", IDM_CLEAR MENUITEM SEPARATOR MENUITEM "&Koniec", IDM_EXIT } }
Przeanalizujmy pierwszy przykład.
Pokazuje on sposób rejestracji szablonu okna dialogowego jako klasy okna i utworzenia okna z tej klasy. Upraszcza to twój program, ponieważ nie musisz własnoręcznie tworzyć kontrolki okna potomnego.
Najpierw przeanalizujmy szablon okna dialogowego.
MyDialog DIALOG 10, 10, 205, 60
Zadeklaruj nazwę okna dialogowego, w tym przypadku "MyDialog",
za którą umieść słowo kluczowe DIALOG. Następne
cztery liczby określają współrzędne x i y oraz szerokość i wysokość okna
dialogowego podane w jego jednostkach (to nie to samo
co piksele).
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
Zadeklaruj style okienka dialogowego.
CAPTION "Nasze pierwsze okno dialogowe"
To jest tekst, który pojawi się na pasku tytułowym okienka dialogowego.
CLASS "DLGCLASS"
Ten wiersz jest najistotniejszy. Słowo kluczowe CLASS
umożliwia nam użycie szablonu okna dialogowego jako klasy okna. Za tym słowem
występuje nazwa "klasy okna".
{ EDITTEXT IDC_EDIT, 15, 17, 111, 13, ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP DEFPUSHBUTTON "Przywitaj się", IDC_BUTTON, 141, 10, 52, 13 PUSHBUTTON "&Koniec", IDC_EXIT, 141, 26, 52, 13 }
Powyższy blok definiuje kontrolki okna dialogowego. Składnia jest zwykle
następująca:
typ-kontrolki "tekst" ,numerID, x, y, szerokość, wysokość [,style]
Typy kontrolek są określone przez stałe kompilatora zasobów, zatem
musisz skonsultować się z jego instrukcją.
Teraz przechodzimy do kodu źródłowego w asemblerze. Interesujący
fragment występuje w strukturze klasy okna:
mov wc.cbWndExtra, DLGWINDOWEXTRA ... mov wc.lpszClassName, OFFSET ClassName
Zwykle pole to pozostawia się z wartością NULL,
lecz jeżeli chcemy zarejestrować szablon okna dialogowego jako klasę
okna, musimy ustawić jego wartość na DLGWINDOWEXTRA.
Zwróć uwagę, iż nazwa tej klasy musi być identyczna z nazwą za słowem
kluczowym CLASS w szablonie okna dialogowego.
Pozostałe pola struktury klasy okna są inicjowane standardowo. Po
wypełnieniu odpowiednią informacja struktury klasy okna rejestrujemy ją
przy pomocy funkcji RegisterClassEx. Znajome? To
jest ta sama procedura, którą musisz wykonać w celu zarejestrowania
zwykłej klasy okna.
INVOKE CreateDialogParam, hInstance, ADDR DlgName, NULL, NULL, NULL
Po zarejestrowaniu "klasy okna" tworzymy nasze
okno dialogowe. W tym przykładzie tworzę je jako niemodalne za pomocą
funkcji CreateDialogParam. Funkcja ta wymaga
pięciu parametrów, lecz wypełnić musisz tylko pierwsze dwa: uchwyt
egzemplarza programu oraz wskazanie nazwy szablonu okna dialogowego.
Zwróć uwagę, iż drugi parametr nie jest wskazaniem nazwy klasy.
W tym miejscu system Windows tworzy okno
dialogowe wraz z jego kontrolkami. Twoja procedura okna otrzyma jak
zwykle wiadomość WM_CREATE.
INVOKE GetDlgItem, hDlg, IDC_EDIT INVOKE SetFocus, eax
Po utworzeniu okna dialogowego chcę, aby aktywnym elementem była
kontrolka edycyjna. Gdybym umieścił ten kod w sekcji
WM_CREATE, to wywołanie
GetDlgItem by się nie powiodło, ponieważ w tym czasie
kontrolki okna dialogowego nie są jeszcze utworzone. Jedynym sposobem
osiągnięcia założonego celu jest wywołanie tej funkcji po utworzeniu
okna dialogowego wraz ze wszystkimi jego kontrolkami. Funkcja
GetDlgItem pobiera numer ID kontrolki i
zwraca powiązany z nim uchwyt okna kontrolki. W ten sposób możesz
otrzymać uchwyt okna, jeśli znasz jego numer ID.
.WHILE TRUE INVOKE GetMessage, ADDR msg, NULL, 0, 0 .BREAK .IF (!eax) INVOKE IsDialogMessage, hDlg, ADDR msg .IF eax==FALSE INVOKE TranslateMessage, ADDR msg INVOKE DispatchMessage, ADDR msg .ENDIF .ENDW
Program wchodzi w pętlę wiadomości i zanim przetłumaczymy i wyślemy
wiadomości, wywołujemy funkcję IsDialogMessage,
aby zarządca okienka dialogowego mógł obsłużyć dla nas logikę naszego
okna dialogowego. Jeśli funkcja ta zwróci wartość TRUE,
to oznacza to, iż wiadomość była przeznaczona dla okna dialogowego i
została obsłużona przez jego zarządcę. Zwróć uwagę na jeszcze jedną
różnicę w stosunku do poprzednich lekcji. Gdy procedura okna chce pobrać
tekst z pola edycyjnego, wywołuje funkcję GetDlgItemText
zamiast GetWindowText. Funkcja
GetDlgItemText akceptuje numer
ID kontrolki zamiast uchwytu okna. Ułatwia to
wywołanie w przypadku okna dialogowego.
Teraz przejdźmy do drugiego przykładu wykorzystania okna dialogowego jako głównego okna aplikacji. W następnym przykładzie utworzę okienko dialogowe modalne dla aplikacji. Nie znajdziesz pętli wiadomości ani procedury okna, ponieważ są one zbędne!
Plik DIALOG.ASM - wersja nr 2.
.386 .MODEL FLAT, STDCALL OPTION CASEMAP:NONE INCLUDE \masm32\include\windows.inc INCLUDE \masm32\include\user32.inc INCLUDE \masm32\include\kernel32.inc INCLUDELIB \masm32\lib\user32.lib INCLUDELIB \masm32\lib\kernel32.lib DlgProc PROTO :DWORD, :DWORD, :DWORD, :DWORD .DATA DlgName DB "MyDialog",0 AppName DB "Nasze drugie okno dialogowe",0 TestString DB "Och! Jestem w edytorze",0 .DATA? hInstance HINSTANCE ? CommandLine LPSTR ? buffer DB 512 DUP(?) .CONST IDC_EDIT EQU 3000 IDC_BUTTON EQU 3001 IDC_EXIT EQU 3002 IDM_GETTEXT EQU 32000 IDM_CLEAR EQU 32001 IDM_EXIT EQU 32002 .CODE start: INVOKE GetModuleHandle, NULL mov hInstance, eax INVOKE DialogBoxParam, hInstance,\ ADDR DlgName, NULL, ADDR DlgProc, NULL INVOKE ExitProcess, eax DlgProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_INITDIALOG INVOKE GetDlgItem, hWnd, IDC_EDIT INVOKE SetFocus, eax .ELSEIF uMsg==WM_CLOSE INVOKE SendMessage, hWnd, WM_COMMAND, IDM_EXIT, 0 .ELSEIF uMsg==WM_COMMAND mov eax, wParam .IF lParam==0 .IF ax==IDM_GETTEXT INVOKE GetDlgItemText, hWnd, IDC_EDIT, ADDR buffer, 512 INVOKE MessageBox, NULL, ADDR buffer, ADDR AppName, MB_OK .ELSEIF ax==IDM_CLEAR INVOKE SetDlgItemText, hWnd, IDC_EDIT, NULL .ELSEIF ax==IDM_EXIT INVOKE EndDialog, hWnd, NULL .ENDIF .ELSE mov dx, WORD PTR wParam + 2 .IF dx==BN_CLICKED .IF ax==IDC_BUTTON INVOKE SetDlgItemText, hWnd, IDC_EDIT, ADDR TestString .ELSEIF ax==IDC_EXIT INVOKE SendMessage, hWnd, WM_COMMAND, IDM_EXIT, 0 .ENDIF .ENDIF .ENDIF .ELSE mov eax, FALSE ret .ENDIF mov eax, TRUE ret DlgProc ENDP END start
Plik DIALOG.RC - wersja nr 2
#include "resource.h" #define IDR_MENU1 3003 #define IDC_EDIT 3000 #define IDC_BUTTON 3001 #define IDC_EXIT 3002 #define IDM_GETTEXT 32000 #define IDM_CLEAR 32001 #define IDM_EXIT 32003 MyDialog DIALOG 10, 10, 205, 60 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Nasze drugie okno dialogowe" MENU IDR_MENU1 { EDITTEXT IDC_EDIT, 15, 17, 111, 13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "CZEŚĆ", IDC_BUTTON, 141, 10, 52, 13 PUSHBUTTON "&Koniec", IDC_EXIT, 141, 26, 52, 13 } IDR_MENU1 MENU { POPUP "Kontrolki Testowe" { MENUITEM "Pobierz tekst", IDM_GETTEXT MENUITEM "Wyczyść tekst", IDM_CLEAR MENUITEM SEPARATOR MENUITEM "&Koniec", IDM_EXIT } }
Analizujemy dalej:
DlgProc PROTO :DWORD, :DWORD, :DWORD, :DWORD
Deklarujemy prototyp funkcji dla DlgProc, aby
można było się do niej odwołać za pomocą operatora ADDR
w wierszu poniżej:
INVOKE DialogBoxParam, hInstance,\ ADDR DlgName, NULL, ADDR DlgProc, NULL
Powyższy wiersz wywołuje funkcję DialogBoxParam,
która przyjmuje pięć parametrów: uchwyt egzemplarza programu, nazwę
szablonu okna dialogowego, uchwyt okna nadrzędnego, adres procedury okna
dialogowego oraz dane specyficzne dla tego okna.
DialogBoxParam
tworzy modalne okno dialogowe. Nie zwróci ona sterowania, aż okno
dialogowe zostanie zamknięte.
.IF uMsg==WM_INITDIALOG INVOKE GetDlgItem, hWnd, IDC_EDIT INVOKE SetFocus, eax .ELSEIF uMsg==WM_CLOSE INVOKE SendMessage, hWnd, WM_COMMAND, IDM_EXIT, 0
Procedura okna dialogowego jest podobna do procedury okna, z tą różnicą,
iż nie otrzymuje wiadomości WM_CREATE. Pierwszą
otrzymywaną wiadomością jest WM_INITDIALOG.
Zwykle w obsłudze tej wiadomości umieszczamy kod inicjalizacji. Zauważ,
iż musisz umieścić w rejestrze eax wartość
TRUE, jeśli przetwarzasz tę wiadomość.
Wewnętrzny zarządca okienka dialogowego nie wysyła automatycznie do naszej procedury okna dialogowego wiadomości WM_DESTROY przy wysłaniu WM_CLOSE. Zatem jeśli chcemy zareagować, gdy użytkownik kliknie myszką przycisk zamykający na naszym okienku dialogowym, musimy obsłużyć wiadomość WM_CLOSE. W naszym przykładzie wysyłamy wiadomość WM_COMMAND z wartością IDM_EXIT w wParam. Ma to ten sam efekt, co wybranie elementu menu Koniec. W odpowiedzi wywołana zostaje funkcja EndDialog,
Obsługa wiadomości WM_COMMAND pozostaje taka sama.
Gdy chcesz usunąć okno dialogowe, jedynym sposobem jest wywołanie funkcji EndDialog. Nie próbuj stosować DestroyWindow! Funkcja EndDialog nie usuwa okna dialogowego natychmiast. Ustawia ona jedynie znacznik dla wewnętrznego zarządcy okienek dialogowych i powraca do wykonania następnej instrukcji.
Teraz przebadajmy plik zasobów. Widoczną zmianą jest to, iż zamiast użycia tekstu jako nazwy menu używamy wartość IDR_MENU1. Jest to konieczne, jeśli chcesz dołączyć menu do okna dialogowego utworzonego przy pomocy DialogBoxParam. Zwróć uwagę, iż w szablonie okna dialogowego musisz dodać słowo kluczowe MENU, za którym występuje numer zasobu ID.
Drugą widoczną różnicą jest brak w drugim przykładzie ikony dla okna dialogowego. Jednakże możesz ustawić tę ikonę wysyłając do okna dialogowego wiadomość WM_SETICON podczas obsługi wiadomości WM_INITDIALOG. W tym celu dodaj do tej sekcji następujący kod:
.IF uMsg==WM_INITDIALOG INVOKE GetDlgItem, hWnd, IDC_EDIT INVOKE SetFocus, eax INVOKE LoadIcon, NULL, IDI_APPLICATION INVOKE SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
Ta sama aplikacja w
Pascalu.
Uwaga
Program używa tego samego pliku zasobów i pliku definicji, co wersja asemblerowa. Musisz je przekopiować do katalogu uruchomieniowego. Plik zasobów nazwij RSRC.RC (można zachować oryginalną nazwę pliku. ale wtedy należy ustawić ją w opcjach projektu).
Oryginalny kompilator zasobów w pakiecie DevPascal (windres.exe) ma błąd, który uniemożliwi poprawną kompilację. Dlatego najlepszym rozwiązaniem będzie skopiowanie tego pliku z pakietu DevC++, który również możesz darmowo pobrać z sieci. Kompilator windres.exe znajduje się w obu pakietach w katalogu bin.
Wersja nr 1 (wymaga pierwszego pliku zasobów)
{******************************** ** I Liceum Ogólnokształcące ** ** w Tarnowie ** ** mgr Jerzy Wałaszek ** ********************************} program MainDialog1; uses Windows; const ClassName = 'DLGCLASS'; MenuName = 'MyMenu'; DlgName = 'MyDialog'; AppName = 'Nasze pierwsze okno dialogowe'; TestString = 'Och! Jestem w edytorze'; IDC_EDIT = 3000; IDC_BUTTON = 3001; IDC_EXIT = 3002; IDM_GETTEXT = 32000; IDM_CLEAR = 32001; IDM_EXIT = 32002; var buffer : array [0..511] of byte; function WndProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM) : longint; begin WndProc := 0; case uMsg of WM_CREATE : SetDlgItemText(hWnd,IDC_EDIT,AppName); WM_DESTROY : PostQuitMessage(0); WM_COMMAND : if lParam = 0 then case (wParam and $ffff) of IDM_GETTEXT : begin GetDlgItemText(hWnd,IDC_EDIT,@buffer,512); MessageBox(0,@buffer,AppName,MB_OK); end; IDM_CLEAR : SetDlgItemText(hWnd,IDC_EDIT,0); else DestroyWindow(hWnd); end else begin if (wParam shr 16) = BN_CLICKED then case (wParam and $ffff) of IDC_BUTTON : SetDlgItemText(hWnd,IDC_EDIT,TestString); IDC_EXIT : SendMessage(hWnd,WM_COMMAND,IDM_EXIT,0); end; end; else {dla case} WndProc := DefWindowProc(hWnd,uMsg,wParam,lParam); end; end; function WinMain(hInst,hPrevInst:HINST;CmdLine:LPSTR;CmdShow:DWORD) : longint; var wc : WNDCLASSEX; msg : MSG; hDlg : HWND; begin wc.cbSize := SizeOf(WNDCLASSEX); wc.style := CS_HREDRAW or CS_VREDRAW; wc.lpfnWndProc := @WndProc; wc.cbClsExtra := 0; wc.cbWndExtra := DLGWINDOWEXTRA; wc.hInstance := hInst; wc.hbrBackground := COLOR_BTNFACE + 1; wc.lpszMenuName := MenuName; wc.lpszClassName := ClassName; wc.hIcon := LoadIcon(0,IDI_APPLICATION); wc.hIconSm := wc.hIcon; wc.hCursor := LoadCursor(0,IDC_ARROW); RegisterClassEx(wc); hDlg := CreateDialogParam(hInst,DlgName,0,Nil,0); SetFocus(GetDlgItem(hDlg,IDC_EDIT)); ShowWindow(hDlg,SW_SHOWNORMAL); UpdateWindow(hDlg); while GetMessage(msg,0,0,0) do if not IsDialogMessage(hDlg,msg) then begin TranslateMessage(msg); DispatchMessage(msg); end; WinMain := msg.wParam; end; begin ExitProcess(WinMain(GetModuleHandle(0),0,GetCommandLine,SW_SHOWDEFAULT)); end.
Wersja nr 2 (wymaga drugiego pliku zasobów)
{******************************** ** I Liceum Ogólnokształcące ** ** w Tarnowie ** ** mgr Jerzy Wałaszek ** ********************************} program MainDialog2; uses Windows; const DlgName = 'MyDialog'; AppName = 'Nasze drugie okno dialogowe'; TestString = 'Och! Jestem w edytorze'; IDC_EDIT = 3000; IDC_BUTTON = 3001; IDC_EXIT = 3002; IDM_GETTEXT = 32000; IDM_CLEAR = 32001; IDM_EXIT = 32002; var buffer : array[0..511] of byte; function DlgProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM) : longint; begin DlgProc := longint(true); case uMsg of WM_INITDIALOG : SetFocus(GetDlgItem(hWnd,IDC_EDIT)); WM_CLOSE : SendMessage(hWnd,WM_COMMAND,IDM_EXIT,0); WM_COMMAND : if lParam = 0 then case (wParam and $ffff) of IDM_GETTEXT: begin GetDlgItemText(hWnd,IDC_EDIT,@buffer,512); MessageBox(0,@buffer,AppName,MB_OK); end; IDM_CLEAR : SetDlgItemText(hWnd,IDC_EDIT,0); IDM_EXIT : EndDialog(hWnd,0); end else if (wParam shr 16) = BN_CLICKED then begin if (wParam and $ffff) = IDC_BUTTON then SetDlgItemText(hWnd,IDC_EDIT,TestString) else if (wParam and $ffff) = IDC_EXIT then SendMessage(hWnd,WM_COMMAND,IDM_EXIT,0); end; else {dla case} DlgProc := longint(false); end; end; begin ExitProcess(DialogBoxParam(GetModuleHandle(0),DlgName,0,@DlgProc,0)); end.
Autorem
kursu jest
Iczelion. Kurs
programowania Windows znalazł się na serwerze I LO w Tarnowie za pisemną
zgodą autora. |
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