Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: 'Złośliwiec'
Biblioteki C++

Okna dialogowe, cz. 2

[lekcja] Rozdział 9. Omówienie różnic pomiędzy dialogami modalnymi a niemodalnymi. Zawarto również informacje, w jaki sposób zapewnić domyślną obsługę klawisza Tab dla wszystkich typów okien.

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:

Niemodalny dialog w roli paska narzędziowego (Windows 98)
Niemodalny dialog w roli paska narzędziowego (Windows 98)


Zaczniemy od edycji pliku *.rc:

C/C++
#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:

C/C++
#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:
C/C++
CreateDialog( HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent,
DLGPROC lpDialogFunc )

Argument Znaczenie
hInstance Uchwyt do naszej aplikacji
lpTemplate Identyfikator wzorca dialogu
hWndParent Uchwyt okna wywołującego dialog
lpDialogFunc Wskaźnik do procedury dialogowej

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:

C/C++
ShowWindow( hwnd, SW_HIDE );

...a z powrotem pokazujemy tak:

C/C++
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:

C/C++
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 :-).
Poprzedni dokument Następny dokument
Okna dialogowe, cz. 1 Okna dialogowe, cz. 3