![]() |
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