Okna dialogowe niemodalne
Takie okienka dialogowe, o jakich mówiliśmy do tej pory, nie do wszystkiego da się wykorzystać. I tak na przykład jeśli chcemy zrobić aplikację składającą się z kilku okien widocznych za ekranie jednocześnie (np. jedno okno główne i drugie okno jako pasek narzędzi), dialogi modalne stają się kompletnie nieprzydatne, ponieważ taki dialog trzeba zamknąć, by móc znów korzystać z głównego okna.
Dialogi "niemodalne" ("modeless dialogs") nie posiadają własnej pętli komunikatów. Wszystko, co się na nich dzieje, wysyłane jest do okna-rodzica. Zresztą w tym przypadku określenia "okno-rodzic" i "okno-dziecko" są bardzo adekwatne do sytuacji: niemodalne okna dialogowe są "niesamodzielne" i całkowicie podległe swym "rodzicom".
Po tej szczypcie teorii czas zakasać rękawy i brać się do roboty, czyli do stworzenia takiego niemodalnego okna dialogowego. Załóżmy, że chcemy mieć pasek narzędzi z trzema przyciskami. Czyli coś takiego:
Zaczniemy od edycji pliku *.rc:
#include <windows.h>
#include "pasek.h"
IDD_PASEK DIALOGEX 0, 0, 98, 52
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
EXSTYLE WS_EX_TOOLWINDOW
CAPTION "Mój pasek narzędzi"
FONT 8, "MS Sans Serif"
{
PUSHBUTTON "&Pierwszy przycisk", IDC_PRZYC1, 7, 7, 84, 14
PUSHBUTTON "&Drugi przycisk", IDC_PRZYC2, 7, 31, 84, 14
PUSHBUTTON "&Trzeci przycisk", IDC_PRZYC3, 7, 55, 84, 14
}
Nagłówek
pasek.h może wyglądać jakoś tak:
#define IDD_PASEK 200
#define IDC_PRZYC1 201
#define IDC_PRZYC2 202
#define IDC_PRZYC3 203
Jak widać, powyższy plik zasobów nie różni się zbytnio od tego dla dialogu modalnego. Wstawiłem go tylko po to, by pokazać, jak określać rozszerzone opcje stylów w pliku zasobów. Dla naszego dialogu użyjemy rozszerzonego stylu
WS_EX_TOOLWINDOW, który zamienia nasze okienko na pasek narzędzi. Charakteryzuje się on przede wszystkim mniejszym paskiem tytułowym. Jeśli chcemy skorzystać z rozszerzonych stylów dla dialogu, definiujemy go w pliku *.rc słowem
DIALOGEX (zamiast zwykłego
DIALOG). Stałe rozszerzonych stylów podajemy po słowie
EXSTYLE.
Oczywiście rozszerzone style można równie dobrze stosować dla dialogów niemodalnych jak i modalnych. W budowie pliku zasobów tych dwóch rodzajów dialogów nie ma, jak już powiedziałem, żadnej różnicy. Pojawia się ona dopiero przy makrze wywołującym dialog. Dla dialogów niemodalnych będzie to
CreateDialog. Składnia jest identyczna, jak w przypadku
DialogBox:
Składnia:
CreateDialog( HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent,
DLGPROC lpDialogFunc )
Podobna jest też budowa procedury dialogowej dialogu niemodalnego. Jedyna istotna różnica to sposób zamykania dialogu. Tym razem nie wywołujemy
EndDialog, tylko niszczymy okno poleceniem
DestroyWindow, tak jak w przypadku "zwykłego" (nie-dialogowego) okna. Oczywiście okno niszczymy zazwyczaj tylko raz, a konkretnie przy wychodzeniu z programu. Czasami jednak użytkownik może zapragnąć schować na jakiś czas swój pasek narzędzi (np. żeby nie zasłaniał mu uroczego widoku na inne okienko ;-)), a później znowu je pokazać, gdy będzie potrzebne. Wtedy możemy skorzystać z usług funkcji
ShowWindow. Ukrywamy okno tak:
ShowWindow( hwnd, SW_HIDE );
...a z powrotem pokazujemy tak:
ShowWindow( hwnd, SW_SHOW );
Kodu przykładowego wykorzystującego dialog niemodalny nie będzie, gdyż jest on prawie identyczny z tym do dialogów modalnych (a tak naprawdę to nie chce mi się go kopiować).
Domyślna obsługa komunikatów
Uczyniwszy nasz dialog niemodalnym, pozbawiliśmy go przy okazji pewnej cennej cechy: domyślnej obsługi przełączania się między kontrolkami za pomocą klawisza TAB. Na szczęście jest na to sposób. Wystarczy wywołać funkcję
IsDialogMessage. Jak sugeruje nazwa, funkcja ta sprawdza, czy podany komunikat pochodzi od podanego dialogu, czy też nie. Jeśli pochodzi, funkcja obsłuży ten komunikat (zapewniając przy okazji automatyczną obsługę TAB-a) i zwróci
TRUE. Tak więc modyfikując pętlę komunikatów w następujący sposób:
while( GetMessage( & msg, NULL, 0, 0 ) )
{
if( !IsDialogMessage( hPasek, & msg ) )
{
TranslateMessage( & msg );
DispatchMessage( & msg );
}
}
...zyskujemy automatyczną obsługę TAB-a również w niemodalnym dialogu. Co więcej, sztuczkę tę można wykorzystać także dla "zwykłego" okna, podając funkcji
IsDialogMessage uchwyt tego okna jako argument! Windows "pomyśli" sobie, że okno jest dialogiem i zapewni mu obsługę TAB-a :-).