Sunteți pe pagina 1din 58

Ferestre de dialog

A realizat:Vrabie Aliona
Jomiru Nicolai
Ferestre de dialog modale
 Cel mai des se utilizeaza ferestre de dialog modale. 
 Dacă programul afișează o fereastră de dialog modală, utilizatorul programului nu poate comuta
între fereastra de dialog și alte ferestre ale programului. 
 Utilizatorul trebuie mai întâi să termine lucrul cu fereastra de dialog, acest lucru se face de obicei
făcând clic pe butonul marcat cu OK sau cu Cancel. Dar, în ciuda prezenței pe ecran a unei
ferestre de dialog, utilizatorul poate trece la alte programe. 
 Unele ferestre de dialog (numite ferestre modale de sistem) nu permit acest lucru. Fereastra de
dialog modal de sistem forțează utilizatorul, înainte de a avea ocazia să facă altceva în Windows,
să termine lucrul cu el.
Procedura de dialog . Apelarea unei ferestre de dialog
Procedura de dialog a programului prelucrează mesajele primite de
fereastra de dialog. 
Deși seamănă îndeaproape cu o procedura windows (WndProc), nu este o
procedură windows reală. Procedura ferestrei casetei de dialog este pe
Windows. Această procedură de fereastră apelează procedura de dialog,
transmitându-i multe dintre mesajele pe care le primește.
 Iată procedura de dialog a programului ABOUT1:
 Parametrii acestei funcții sunt identici cu parametrii unei proceduri
obișnuite de fereastră; ca o fereastră, o procedură de dialog trebuie
definită ca o funcție de tip CALLBACK.
  Deși descriptorul hDlg a fost folosit ca descriptor al casetei de dialog ,
puteți utiliza hwnd în schimb 
Diferența dintre o procedura fereastrei windows
și procedura ferestrei de dialog
 Procedura ferestrei returnează o valoare de tip
LRESULT; iar procedura casetei de dialog este o valoare de
tip BOOL (definită ca int în fișierele antetului Windows ).
 Dacă procedura de fereastră nu procesează niciun mesaj,
apelează DefWindowProc ; procedura de dialog, dacă nu
procesează mesajul, returnează FALSE (0), iar dacă se
procesează, atunci TRUE (valoare non-zero).
  Procedura ferestrei de dialog nu procesează mesajele
WM_PAINT și WM_DESTROY. Procedura ferestrei de
dialog nu va primi mesaje WM_CREATE; în schimb, se
inițializează la procesarea mesajului special
WM_INITDIALOG.
Mesajul WM_INITDIALOG este primul mesaj pe care îl primește
procedura ferestrei de dialog. Acest mesaj este trimis numai la procedurile
de dialog. Dacă procedura de dialog returnează TRUE, atunci Windows
plasează focalizarea pe prima fereastră copil a controlului, care are stilul
WS_TABSTOP . 
În fereastra de dialog, prima fereastră copil a controlului care are stilul
WS_TABSTOP este butonul. Pe de altă parte, la procesarea mesajului
WM_INITDIALOG, procedura de dialog poate utiliza
funcția SetFocus pentru a seta focalizarea pe una dintre ferestrele de
control pentru copii din fereastra de dialog, iar apoi ar trebui să returneze o
valoare FALS.
Când prelucrați mesajele WM_CREATE în WndProc , programul ABOUT1
primește un control la instanța programului și îl stochează într-o variabilă statică:
hInstance = ((LPCREATESTRUCT) lParam) -> hInstance;
Programul ABOUT1 procesează acele mesaje WM_COMMAND în care
parametrului wParam este IDM_ABOUT. Când programul îl primește, apelează
funcția DialogBox :
DialogBox (hInstance, "AboutBox", hwnd, AboutDlgProc);
Funcția DialogBox , care este apelată să afișeze caseta de dialog, nu returnează
controlul la WndProc până când caseta de dialog este închisă. Valoarea de retur a
funcției DialogBox este al doilea parametru al funcției EndDialog , care se
numește în procedura de dialog. Atunci WndProc poate transfera controlul
Windows.
Chiar și atunci când este afișată o casetă de dialog, WndProc poate continua să
primească mesaje. Puteți trimite chiar și mesaje din procedura de
dialog către WndProc . Deoarece fereastra principală a programului ABOUT1
este fereastra părinte a ferestrei pop-up de dialog, apelul către
funcția SendMessage din AboutDlgProc ar trebui să înceapă după cum urmează:
SendMessage (GetParent (hDlg), ...);
Stilul cel mai des utilizat pentru ferestrele de dialog modale:
STYLE WS_POPUP | WS_DLGFRAME
Cu toate acestea, puteți experimenta și cu alte stiluri. De exemplu, puteți încerca să utilizați acest stil:
STYLE WS_POPUP | WS_CAPTION
Acest stil vă permite să creați o casetă de dialog cu o bară de titlu și cadrul obișnuit pentru fereastră. Bara de titlu
permite utilizatorului să utilizeze mouse-ul pentru a muta fereastra de dialog pe ecran. Dacă se folosește stilul
WS_CAPTION, atunci coordonatele x și y specificate în instrucțiunea DIALOG sunt coordonatele zonei de lucru a
casetei de dialog în raport cu colțul din stânga sus al zonei de lucru a ferestrei părinte. Bara de titlu va fi amplasat
deasupra axei y .
Dacă există o bară de titlu după instrucțiunea STYLE din șablonul casetei de dialog, puteți seta textul titlului
folosind instrucțiunea CAPTION:
CAPIUNE "Titlu casetă de dialog"
Puteți face același lucru cu funcția SetWindowText atunci când prelucrați mesajul WM_INITDIALOG în procedura
de dialog:
SetWindowText (hDlg, "Legenda casetelor de dialog");
Adăugarea identificatorului WS_THICKFRAME la stil permite utilizatorului să redimensioneze fereastra de dialog,
deși o astfel de redimensionare pentru ferestrele de dialog este neobișnuită. Situația cu identificatorul
WS_MAXIMIZEBOX este similară.
Instrucțiunea STYLE nu este necesară. Dacă șablonul nu include instrucțiunea STYLE sau CAPTION, atunci stilul
următor este setat în mod implicit:
WS_POPUP | WS_BORDER
Dar o fereastră de acest stil arată mai rău. Identificatorul WS_DLGFRAME oferă rezultate mult mai atractive. Dacă
adăugați o instrucțiune CAPTION la o declarație STYLE, stilul implicit este:
WS_POPUP | WS_CAPTION | WS_SYSMENU
În plus, meniul pentru caseta de dialog poate fi adăugat folosind următoarele instrucțiuni din șablonul casetei de
dialog: MENU menu-name
Tabelul de mai jos arată clasa ferestrei și stilul ferestrei
corespunzător fiecărui tip de fereastră copil a
controlului:
Fiecare dintre ferestrele de control pentru copii prezentate
are un stil: WS_CHILD | WS_VISIBLE
Pentru toate tipurile de ferestre de control pentru copii, cu
excepția EDITTEXT, SCROLLBAR, LISTBOX și
COMBOBOX, se utilizează următorul format de
instrucțiuni care descriu controalele:
control-type "text", id, xPos, yPos,
xWidth, yHeight [, iStyle]
Și pentru tipurile de controale EDITTEXT,
SCROLLBAR, LISTBOX și COMBOBOX, câmpul text
nu este inclus în formatul de instrucțiuni de definire:
ID de tip control, xPos, yPos, x Lățime,
yHeight [, iStyle ]
În ambele instrucțiuni, câmpul iStyle este opțional.
 Dacă instrucțiunea CONTROL este utilizată într-un șablon
de fereastră de dialog, nu este necesară includerea stilurilor
WS_CHILD și WS_VISIBLE. Windows le include în stilul
ferestrei atunci când creați ferestre child. În plus, formatul
de instrucțiuni CONTROL face mai ușor să înțelegeți ce
face managerul casetei de dialog Windows atunci când
creează o casetă de dialog.
  În primul rînd creează o fereastră pop-up a cărei fereastră
părinte este definită de mânerul de fereastră specificat în
funcția DialogBox . Apoi, pentru fiecare instrucțiune de
control din șablonul de dialog, managerul ferestrei de
dialog creează o fereastră copil. Fereastra părinte a fiecărei
ferestre de control pentru copii este o casetă de dialog pop-
up. Instrucțiunea CONTROL de mai sus se traduce printr-
un apel la funcția CreateWindowcare arată așa:
CreateWindow („buton”, „OK”,WS_CHILD
| WS_VISIBLE | BS_PUSHBUTTON
| WS_TABSTOP, 10 * cxChar / 4, 20 *
cyChar / 8,
32 * cxChar / 4,14 * cyChar / 8, hDlg,
IDOK, hInstance, NULL);
cxChar și cyChar sunt lățimea și înălțimea caracterului
fontului sistemului în pixeli. Parametrul hDlg este
valoarea de retur a funcției CreateWindow , care
creează o casetă de dialog. Parametrul hInstance
a fost primit pentru prima dată când a fost apelată
funcția DialogBox .
Fereastra de dialog mai complexă
 Programul ABOUT2 arată cum să lucrați cu ferestrele de control ale
copiilor (în acest caz, un grup de butoane radio) în cadrul unei căsuțe de
dialog și cum să d
esenați o casetă de dialog în zona de lucru.
Există două grupuri de butoane radio în fereastra programului
ABOUT2.
 Un grup este folosit pentru a selecta o culoare, iar celălalt pentru
a selecta un dreptunghi sau o elipsă. În caseta de dialog este afișat
un dreptunghi sau elipsă, colorat în funcție de culoarea selectată. 
Când faceți clic pe OK, caseta de dialog se închide, iar procedura
ferestrei programului atrage figura selectată în zona sa de
lucru. Când faceți clic pe Cancel, zona de lucru a ferestrei
principale rămâne neschimbată. 
Deși cele două butoane din fereastra de dialog a programului
ABOUT2 folosesc identificatorii predefinite IDOK și
IDCANCEL, fiecare grup de comutare are propriul său
identificator, care începe cu literele IDD (identificatorul ferestrei
de control al copilului, controlul casetei de dialog ID). Acești
identificatori sunt definiți în fișierul antet ABOUT2.H.
Lucrul cu controale pentru copii din fereastra de dialog
Capitolul 8 s-a arătat că majoritatea ferestrelor de control copii trimit mesaje
WM_COMMAND în fereastra părintească. În plus, s-a arătat că fereastra părinte
poate schimba starea ferestrelor sale de control pentru copii prin trimiterea de
mesaje către ferestrele de control pentru copii.
 În mod similar, puteți modifica starea ferestrelor de control pentru copii într-o
procedură de dialog. De exemplu, dacă aveți mai multe grupuri de butoane radio,
puteți activa și dezactiva butoanele radio din fiecare grup. Pe lângă lucrul cu
ferestrele de control în ferestrele de dialog, Windows ne oferă mai multe
opțiuni. Luați în considerare unul dintre modurile în care procedura de dialog
interacționează cu ferestrele de control pentru copii.
În capitolul 8, s-a arătat că pornirea și oprirea necesită trimiterea mesajului
BM_SETCHECK în fereastra de control a copilului. Prin urmare, următoarea
instrucțiune este utilizată pentru a seta comutatorul:
SendMessage (hwndCtrl, BM_SETCHECK, 1, 0);
Și pentru a elimina oprirea, aceasta:
SendMessage (hwndCtrl, BM_SETCHECK, 0, 0);
Parametrul hwndCtrl este un maner pentru fereastra copil a controlului.
Dar această metodă duce la o mică problemă, deoarece descriptorii tuturor
ferestrelor de comutare sunt necunoscute în procedura ferestrei de dialog. Numai
identificatorul de comutare de la care vine mesajul este cunoscut. Din fericire,
Windows are o funcție pentru preluarea mânerului ferestrei din controlul casetei de
dialog, care utilizează descriptorul ferestrei de dialog și identificatorul de control:
hwndCtrl = GetDlgItem (hDlg, id);
(În plus, folosind funcția GetWindowLong , puteți obține valoarea identificatorului
ferestrei de control, știind care este manevra acestei ferestre:
id = GetWindowLong (hwndCtrl, GWL_ID); dar această expresie este rar
folosită.)
Codul de mai jos este utilizat pentru a activa și dezactiva comutatoarele
din procedura ferestrei de dialog
static int iColor;
[alte linii ale programului]
case WM_COMMAND: switch(LOWORD(wParam))
{
[alte linii ale programului]
case IDD_BLACK: case IDD_RED: case IDD_GREEN: case
IDD_YELLOW: case IDD_BLUE: case IDD_MAGENTA: case
IDD_CYAN: case IDD_WHITE:
iColor = LOWORD(wParam);
for(i = IDD_BLACK; i <= IDD_WHITE; i++)
SendMessage(GetDlgItem(hDlg, i), BM_SETCHECK, i ==
LOWORD(wParam), 0); return TRUE;
[alte linii ale programului]
Butoanele OK și Cancel
Programul ABOUT2 are două butoane, marcate ca OK
și Anulare. În șablonul de dialog din fereastra de
dialog a fișierului de descriere a resurselor
ABOUT2.RC, butonul OK are un identificator IDOK
(definit în fișierele antetului Windows ca 1), iar
butonul Anulare are un identificator IDCANCEL
(definit ca 2). În acest caz, butonul implicit este
butonul OK:
DEFPUSHBUTTO
N "OK" IDOK, 20, 168, 40, 14,WS_GROUP
PUSHBUTTON "Cancel"IDCANCEL, 80, 168, 40, 14,WS_GROUP
Un astfel de acord este destul de comun pentru butoanele OK și Cancel din
ferestrele de dialog; prezența butonului OK implicit ajută la interfața tastaturii. Și
iată de ce: de obicei caseta de dialog este închisă fie făcând clic pe unul dintre
aceste butoane, fie apăsând tasta <Spațiu> când butonul dorit are focalizarea de
intrare. În plus, procedura de fereastră a ferestrei de dialog generează un mesaj
WM_COMMAND atunci când este apăsată tasta <Enter>, indiferent de care dintre
ferestrele de control are focalizarea de intrare. 
Loword al parametrului wParam corespunde valorii de identificare a butonului
implicit pentru butonul casetei de dialog până când celălalt buton primește
focalizarea de intrare. În acest caz, loword al parametrului wParam primește
valoarea de identificare a butonului care are focalizare de intrare. Dacă nu există
niciun buton implicit în caseta de dialog, Windows trimite mesajul
WM_COMMAND cu loword al parametrului wParam la procedura de dialog egal
cu IDOK. Și când apăsați tastele <Esc> sau <Ctrl> + <Break>, Windows trimite
mesajul WM_COMMAND cu loword al parametrului wParam la procedura casetei
de dialog  egal cu IDCANCEL la procedura casetei de dialog. 
Astfel, nu este necesară adăugarea unei logici de operare a tastaturii separate la
procedura ferestrei de dialog, deoarece acele apăsări de taste care conduc de obicei
la închiderea ferestrei de dialog sunt convertite de Windows în mesaje
WM_COMMAND pentru aceste două butoane.
Funcția AboutDlgProc , apelând funcția EndDialog ,
procesează aceste două mesaje WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
iCurrentColor = iColor; iCurrentFigure =
iFigure; EndDialog(hDlg, TRUE); return TRUE;
case IDCANCEL: EndDialog(hDlg, FALSE); return
TRUE;
Atunci când procedura fereastra ABOUT2 desenează un
dreptunghi sau elipsă în spațiul de lucru al programului său,
folosește iCurrentColor și iCurrentFigure variabile
globale . AboutDlgProc utilizează variabilele statice
locale iColor și iFigure pentru a desena o figură în caseta de
dialog .
Tabele și grupuri
Windows oferă toată logica necesară pentru a muta focalizarea de intrare de la o
fereastră a controlului la alta. Cu toate acestea, pentru a face acest lucru, trebuie să
includeți stilurile WS_TABSTOP și WS_GROUP în șablonul casetei de dialog. Pentru
toate ferestrele de control pentru copii care trebuie accesate cu ajutorul tastei <Tab>,
este setat stilul de fereastră WS_TABSTOP.
 Dacă revenim la slide 11 stilurile a casetei de dialog observam faptul că multe
controale pentru copii conțin în mod implicit stilul WS_TABSTOP, în timp ce altele
nu. De obicei, controalele pentru copii care nu conțin stilul WS_TABSTOP (în special,
controale statice) nu ar trebui să primească focus de intrare, deoarece nu sunt necesare
acolo. Până când focalizarea de intrare este setată la o fereastră de control specifică, la
procesarea mesajului WM_INITDIALOG, acesta returnează FALSE, iar Windows
stabilește focalizarea de intrare la prima fereastră de control din caseta de dialog, care
are stilul WS_TABSTOP.
A doua opțiune de tastatură pe care Windows o oferă în caseta de
dialog include utilizarea tastelor săgeată. Această caracteristică este
deosebit de importantă pentru grupurile de comutatoare.
 După ce utilizați tasta <Tab> pentru a trece la comutatorul marcat
în prezent cu o bifă în interiorul grupului, trebuie să utilizați tastele
cursor pentru a transfera focalizarea de intrare de la un comutator
din grup la altul. Acest lucru poate fi realizat folosind stilul ferestrei
WS_GROUP.
 Pentru secvențe specifice de controale copil într-un șablon de
fereastră de dialog, Windows va utiliza tastele de cursor pentru a
transfera focalizarea de intrare de la primul control care are stilul
WS_GROUP la următoarele grupuri de control (dar până la
următorul control, având stilul WS_GROUP). Când ajungeți la
ultimul control de grup, Windows va reveni la primul și așa mai
departe.
În mod implicit, Ferestrele de control pentru copii
LTEXT, CTEXT, RTEXT și ICON includ stilul
WS_GROUP, care de obicei marchează sfârșitul unui
grup. Pentru ferestrele de control pentru copii de alte
tipuri, este adesea necesar să adăugați un stil
WS_GROUP
Șablonul casetei de dialog din fișierul ABOUT2.RC:
Desen într-o fereastră de dialog
 Programul ABOUT2 desenează într-o casetă de dialog. În șablonul casetei de dialog din fișierul
ABOUT2.RC, o casetă text de control goală este definită cu dimensiuni și poziție care definește zona
în care se presupune că desenul este:
CTEXT "" IDD_PAINT, 68, 54, 60, 60
 Deoarece nu există niciun text în această fereastră de control, tot ceea ce face procedura de fereastră a
clasei „statice” este actualizarea fundalului atunci când fereastra de control a copilului este
redirecționată.
 Când culoarea sau forma curentă se schimbă sau când fereastra de dialog primește un mesaj
WM_PAINT, procedura de dialog apelează la funcția PaintTheBlock , al cărei apel în ABOUT2.C
arată astfel:
PaintTheBlock (hCtrlBlock, iColor, iFigure);
 Mânerul ferestrei hCtrlBlock , care este primul parametru al funcției, a fost primit în timpul procesării
mesajului
WM_INITDIALOG: hCtrlBlock = GetDlgItem (hDlg, IDD_PAINT);
 Corpul funcției PaintTheBlock :

void PaintTheBlock (HWND hCtrl, int iColor, int iFigure)


{
InvalidateRect (hCtrl, NULL, TRUE); UpdateWindow (hCtrl); PaintWindow (hCtrl,
iColor, iFigure);
Funcția PaintWindow obține descriptorul contextului dispozitivului
din fereastra hCtrl și desenează forma selectată, pictând-o cu o
pensulă de culoare selectată de utilizator. 
Mărimea ferestrei de control pentru copii se obține folosind
funcția GetClientRect . Deși dimensiunea ferestrei de control este
definită cu caractere în șablonul casetei de
dialog, GetClientRect returnează dimensiunile în pixeli. Pe lângă
aceasta, puteți utiliza funcția MapDialogRect , care transformă
coordonatele simbolice ale casetei de dialog în coordonatele de
pixeli ale spațiului de lucru.
De fapt, nu desenăm în spațiul de lucru al casetei de dialog, ci în
spațiul de lucru al ferestrei copilului controlului. Ori de câte ori o
fereastră de dialog primește un mesaj WM_PAINT, fereastra de
control pentru copii nu este valabilă, atunci este actualizată și
spațiul său de lucru devine valabil.
Utilizarea altor funcții cu fereastra de dialog
Majoritatea funcțiilor care se folosesc cu ferestrele copil pot fi de asemenea
utilizate cu ferestrele de control ale copiilor într-o fereastră de dialog. De
exemplu, folosind funcția MoveWindow , puteți muta fereastra de control în jurul
ferestrei de dialog și forțați utilizatorul să-l miște cu mouse-ul.
Uneori devine necesar, în funcție de setările altor ferestre de control, să faceți
dinamic anumite controale disponibile sau inaccesibile în caseta de
dialog. Apelați următoarea funcție: EnableWindow (hwndCtrl, bEnable);
Face fereastra de control disponibilă atunci când bEnable este TRUE (non zero)
și indisponibil atunci când bEnable este FALSE (0). Dacă fereastra de control nu
este disponibilă, atunci nu răspunde nici tastatura, nici mouse-ului. Nu puteți
face ca o fereastră de control cu ​focalizare de intrare să nu fie disponibilă.
Crearea propriilor controale pentru ferestre de dialog
Cu toate că Windows poarta automat responsabilitatea pentru crearea si
intretinerea ferestrelor de dialog, este posibil și ca să luăm puterea înapoi, în
mâinile noastre si sa adaugam un cod propriu pentru fereastra de dialog.
Anterior am observant o metodă de a desena direct pe fereastra de dialog
( în programul About2). Pe lângă asta, mai este posibil să definești o
fereastră child pe care să o folosești drept fereastră de dialog.
Puteți face acest lucru prin înregistrarea unei clase window și definind un
WndProc nou pentru ea. Apoi specificați această clasă în Developer Studio
în caseta de dialog Proprietăți asociată cu un control personalizat.
About 3
In programul About3 vom inregistra clasa window EllipPush.
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = EllipPushWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TEXT("EllipPush");

RegisterClass(&wndclass);

În editorul de dialog din Developer Studio, ștergeți butoanele Cancel și OK. Adaugati un buton CustomControl din bara de
instrumente. În dialogul Proprietăți pentru acest control, introduceti EllipPush în câmpul Class.
Adaugati un button Custom Control, in loc de o instrucțiune DEFPUSHBUTTON care apare în caseta de dialog șablon, veți vedea
instrucțiune CONTROL care specifică această clasă fereastră (wndclass):
CONTROL IDOK „OK”, „EllipPush”, TABGRP, 64, 60, 32, 14
Managerul casetei de dialog folosește această clasă windows într-un apel CreateWindow la crearea fereastrei child în caseta de dialog.
EllipPushWndProc
Procedura ferestrei EllipPushWndProc procesează trei
mesaje: WM_PAINT, WM_KEYUP, și
WM_LBUTTONUP.
În timpul mesajului WM_PAINT, acesta obține
dimensiunea ferestrei sale de la GetClientRect și
obține textul care apare în butonul push de la
GetWindowText.
Functia Ellipse și DrawText se folosește pentru a
desena elipsa și textul.
Deasemenea se procesează si evenimentele
WM_KEYUP și WM_LBUTTONUP :
EllipPushWndProc
case WM_PAINT:
GetClientRect(hwnd, &rect);
GetWindowText(hwnd, szText, sizeof(szText));
hdc = BeginPaint(hwnd, &ps);
//....//
Ellipse(hdc, rect.left, rect.top, rect.right,
rect.bottom);
DrawText(hdc, szText, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//....//
return 0;

case WM_KEYUP:
if (wParam != VK_SPACE)
break;
// fall through
case WM_LBUTTONUP:
SendMessage(GetParent(hwnd), WM_COMMAND,
GetWindowLongPtr(hwnd, GWLP_ID), (LPARAM)hwnd);
return 0;
Ferestre de dialog modeless
Ferestrele de dialog pot fi „modal” sau „modeless”.
Diferenta:
Casete de dialog modale permit utilizatorului să comute între fereastra de
dialog și alte programe, totusi el nu poate trece la o altă fereastră din
programul care a inițiat fereastra dialog.
Casetele de dialog modeless permit utilizatorului să comute între fereastra de
dialog și fereastra care a creat-o, precum și între caseta de dialog și alte
programe.
Caseta de dialog modeless sunt mai asemănătoare cu ferestrele pop-up
obișnuite.
Creare ferestre de dialog modeless
Casetele de dialog modale sunt create folosind DialogBox. Funcția
returnează o valoare numai după ce caseta de dialog este distrusă.
Ferestrele de dialog modeless sunt create folosind CreateDialog. Această
funcție accepta aceiași parametri ca si DialogBox:

hDlgModeless = CreateDialog(hInstance,TEXT("ColorScrDlg"),hwnd,
ColorScrDlg);
Diferențe dintre ferestrele de dialog Modal și Modeless
-I
Ferestrele de dialog modeless includ de obicei o bară de legendă și o fereastra
de meniu. Acestea sunt de fapt opțiunile implicite atunci când creați o fereastra
de dialog în Developer Studio.
Declarația STYLE din Șablonul de fereastra de dialog pentru o fereastra de
dialog modeless va arăta astfel:
STYLE WS_POPUP ¦ WS_CAPTION ¦ WS_SYSMENU ¦ WS_VISIBLE

Bara de legendă și meniul de sistem permit utilizatorului să mute caseta de dialog


modeless într-o altă zonă din ecran folosind mouse-ul sau tastatura.
În mod normal, nu furnizați o bară de legendă și meniu de sistem cu o fereastra de
dialog modală, deoarece utilizatorul nu poate face nimic în fereastra de bază oricum.
Diferențe dintre ferestrele de dialog Modal și
Modeless - II
Observați că stilul WS_VISIBLE este inclus în exemplul STYLE.
Dacă omiteți WS_VISIBLE, trebuie să apelați ShowWindow după apelul
CreateDialog:
hDlgModeless = CreateDialog(...);
ShowWindow(hDlgModeless, SW_SHOW);
Dacă nu includeți WS_VISIBLE și nici nu apelați ShowWindow, fereastra
de dialog modeless nu va fi afișata.
Diferențe dintre ferestrele de dialog Modal și
Modeless - III
A treia diferență: spre deosebire de mesajele la ferestrele de dialog modale și căsuțele de mesaje, mesajele către ferestrele de
dialog modeless vin prin coada de mesaje a programului.
Când utilizați CreateDialog pentru a crea o fereastra de dialog modeless, ar trebui să salvați handler-ul casetei de dialog
returnat de la apelul într-o variabilă globală (de exemplu, hDlgModeless).
Schimbați bucla de mesaj:
while (GetMessage(&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage(hDlgModeless, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Dacă mesajul este destinat pentru fereastra de dialog modeless, atunci IsDialogMessage îl trimite la procedura de fereastră a
ferestrei dialog și returnează TRUE (non-zero); în caz contrar, returnează FALSE (0).

Variabila hDlgModeless poate fi folosită și de alte părți ale programului ca test al existenței ferestrei de dialog modeless. De
exemplu, alte ferestre din program pot trimite mesaje la fereastra de dialog daca hDlgModeless nu este egal cu 0.
Diferențe dintre ferestrele de dialog Modal și
Modeless - VI
Pentru a încheia o fereastra de dialog modeless utilizați DestroyWindow, in loc de
EndDialog. Când apelați DestroyWindow, setați variabila globală hDlgModeless NULL.
De obicei utilizatorul închide o fereastra de dialog modeless, alegând Close in meniu.
Prelucrarea mesajul WM_CLOSE trebuie să o faceți în procedura casetei de dialog:
case WM_CLOSE:
DestroyWindow(hDlg);
hDlgModeless = NULL;
break;
Puteți permite, de asemenea, unui utilizator să închidă o fereastra de dialog, folosind
butoane. Folosiți aceeași logică ca și pentru mesajul WM_CLOSE. Orice informație pe
care fereastra de dialog trebuie să o „întoarcă” la fereastra respectivă poate fi stocata în
variabile globale.
Programul COLORS2
Programul COLORS2 este o modificare a programului COLORS1 care foloseste
ferestre de dialog pentru a il simplifica semnificativ.
Programul COLORS1 afișa 3 bare de defilare bazate pe dimensiunea fereastrei,
Colors2 le menține la o dimensiune constantă în fereastra de dialog modeless

Când creați șablonul casetei de dialog, utilizați numere de identificare explicite 10,
11 și 12 pentru cele trei bare de defilare, și 13, 14 și 15 pentru cele trei câmpuri de
text static care afișează valorile curente ale barelor de defilare.
Dați fiecărei bare de defilare un stil de oprire.
Fereastra de dialog modeless este creată în funcția WinMain în urma
apelului ShowWindow pentru fereastra principală a programului.
! Stilul ferestrei pentru fereastra principală include WS_CLIPCHILDREN,
care permite programului să recoloreze fereastra principală fără a șterge
fereastra dialog.
Handler-ul ferestrei de dialog returnate de CreateDialog este stocat într-o
variabilă globală și verificat în timpul buclei de mesaj.
HEXCALC: Fereastră sau casetă de dialog?
Programul HEXCALC nu apelează deloc
CreateWindow, nu procesează niciodată mesaje
WM_PAINT, nu obține niciodată un context de
dispozitiv și nu procesează niciodată mesajele mouse-
ului. Cu toate acestea, reușește să încorporeze un
calculator hexadecimal cu o tastatură completă și
interfață de mouse în mai puțin de 150 de linii de cod
sursă.
In HEXCALC fereastra afișată pe ecran pare a fi un hibrid dintre o fereastră normală
și o fereastra de dialog modeless.
Pe de o parte, toate mesajele către HEXCALC sunt procesate într-o funcție WndProc.
Pe de altă parte, fereastra este creată în WinMain cu un apel la CreateDialog care
folosește un șablon de fereastra de dialog definit în HEXCALC.DLG.
Explicatie: O fereastra de dialog, dupa definitie, poate fi asemanata cu o fereastră
simpla. În mod normal, Windows folosește propria sa procedura de fereastra pentru
procesarea mesajelor într-o fereastră de fereastra de dialog. Windows trimite apoi
aceste mesaje la procedura ferestrei de dialog din programul care creează fereastra de
dialog.
În HEXCALC obligăm Windows să folosească șablonul casetei de dialog pentru a
crea o fereastră, dar mesaje acestei ferestre le procesăm manual.
Clasa de fereastra HexCalc este înregistrată în funcția WinMain, la fel ca o clasă de fereastră pentru o fereastră
normală.
Cu toate acestea câmpul cbWndExtra din structura WNDCLASS este setat "DLGWINDOWEXTRA.
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = DLGWINDOWEXTRA; // Note!
wndclass.hInstance = hInstance;
//...//
După înregistrarea clasei de ferestre, WinMain apelează CreateDialog:
hwnd = CreateDialog(hInstance, szAppName, 0, NULL);

Al doilea argument (șirul „HexCalc”) este numele șablonului casetei de dialog. Al treilea - argumentul,
care este în mod normal handlerul ferestrei ferestrei părinte, este setat la 0 deoarece fereastra nu are
părinte. Ultimul argument, care este în mod normal adresa procedurii de dialog, nu este necesar deoarece
Windows nu va prelucra mesajele și, prin urmare, nu le poate trimite la un dialog procedură.
Avantaje utilizate de HEXCALC
Vom profita de un beneficiu enorm prin a permite Windows-ului să facă apelul la CreateWindow:
Windows nu se va opri la crearea ferestrei pop-up, dar va apela, de asemenea, CreateWindow pentru toate
cele 29 de ferestre child - butoane definite în șablonul casetei de dialog. Toate aceste controale trimit
WM_COMMAND mesaje către procedura de fereastră a ferestrei părinte, WndProc.
Aceasta este o tehnică excelentă pentru crearea unei ferestre care trebuie să conțină o colecție de
ferestre child.
Alt mod în care dimensiunea codului HEXCALC este redusă: veți observa că HEXCALC nu
conține un fișier antet necesar, în mod normal, pentru a defini identificatorii pentru toate
controalele ferestrei child din șablonul ferestrei de dialog. Putem renunța la acest fișier, deoarece
numărul de identificare pentru fiecare dintre butoane este setat drept codul ASCII al textului care
apare în control. Aceasta înseamnă că WndProc poate trata mesajele WM_COMMAND și
mesajele WM_CHAR în același mod. În fiecare caz, low word al wParam este codul ASCII al
butonului.
Common dialog box library
Unul dintre obiectivele principale ale Windows când a fost lansat a fost
promovarea un interfete de utilizator standarte.
Pentru multe elemente comune din meniu, acest lucru s-a întâmplat destul
de rapid. Aproape fiecare producător software a adoptat selecția Alt − File
− Open pentru a deschide un fișier.
Începând cu Windows 3.1, a devenit disponibilă o soluție si pentru
ferestrele de dialog. Aceasta este numită „common dialog box library”.
Această bibliotecă constă din mai multe funcții care invocă fereastre de
dialog standard pentru deschiderea și salvarea fișierelor, căutarea și
înlocuirea, alegerea culorilor, alegerea fonturilor și tipărirea.
POPPAD
Programul POPPAD este compus din mai multe fisiere:
POPPAD.C conține tot codul sursă de bază pentru program.
POPFILE.C are codul pentru invocarea ferestrele de dialog File Open și File
Save și conțin, de asemenea, rutinele I/O ale fișierului.
POPFIND.C conține logica de căutare și înlocuire.
POPFONT.C are logica de selectare a fonturilor.
POPFILE.C conține mai multe funcții pentru a afișa ferestrele de dialog File
Open și File Save și a efectua operatiile I / O. Ferestrele de dialog sunt
afișate folosind funcțiile GetOpenFileName și GetSaveFileName.
BOOL PopFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR
pstrTitleName)
{
ofn.hwndOwner = hwnd;
ofn.lpstrFile = pstrFileName;
ofn.lpstrFileTitle = pstrTitleName;
ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT;
return GetOpenFileName(&ofn);
}
Ambele funcții utilizează o structură de tip OPENFILENAME. În POPFILE.C, pentru această structură se folosește
o variabilă globală numită ofn. Cei mai multi parametri ofn sunt inițializati în funcția PopFileInitialize, pe care
POPPAD.C o apelează la procesarea Mesaj WM_CREATE în WndProc.
Este convenabil să declarati ofn drept variabila statică globală, deoarece GetOpenFileName și GetSaveFileName.

void PopFileInitialize(HWND hwnd)


{
static TCHAR szFilter[] = TEXT("Text Files (*.TXT)\0*.txt\0") \
TEXT("ASCII Files (*.ASC)\0*.asc\0") \
TEXT("All Files (*.*)\0*.*\0\0");

ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.hInstance = NULL;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 0;
ofn.lpstrFile = NULL; // Set in Open and Close functions
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = NULL; // Set in Open and Close functions
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = NULL;
ofn.Flags = 0; // Set in Open and Close functions
//…//
}
Când utilizatorul selectează Open din meniul File menu, POPPAD3 apelează PopFileOpenDlg, trecând la ea:
 handlerul ferestrei,
 un pointer către bufferul de nume de fișier și
 un pointer la titlul fișierului.

PopFileOpenDlg stabilește câmpurile


 hwndOwner,
 lpstrFile și
 lpstrFileTitle

ale structurii OPENFILENAME si, în mod corespunzător, stabilește la ofn.Flags optiunea OFN_
CREATEPROMPT, apoi apelează GetOpenFileName, care afișează caseta de dialog familiară.

BOOL PopFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)


{
ofn.hwndOwner = hwnd;
ofn.lpstrFile = pstrFileName;
ofn.lpstrFileTitle = pstrTitleName;
ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT;

return GetOpenFileName(&ofn);
}
Caseta din colțul din dreapta jos listează tipurile de fișiere care vor fi afișate în lista de fișiere. Aceasta este cunoscuta sub numele de
"filtru". Utilizatorul poate schimba filtrul selectând un alt tip de fișier din lista casetei.
În funcția PopFileInitialize din POPFILE.C, se defineste un filtru în variabila szFilter (un tablou de caractere string) pentru trei tipuri
de fișiere: fișiere text cu extensia .TXT, fișiere ASCII cu extensia .ASC și pentru toate fișierele. Un pointer la primul șir din acest
tablou este setat pe câmpul lpstrFilter din Structura OPENFILENAME.
static TCHAR szFilter[] = TEXT("Text Files (*.TXT)\0*.txt\0") \
TEXT("ASCII Files (*.ASC)\0*.asc\0") \
TEXT("All Files (*.*)\0*.*\0\0");

 ofn.lpstrFilter = szFilter;

Dacă utilizatorul schimbă filtrul când caseta de dialog este activă, câmpul nFilterIndex din OPENFILENAME reflectă alegerea
utilizatorului. Deoarece structura este stocată ca o variabilă statică, data viitoare fereastra de dialog este invocată filtrul va fi setat la
tipul de fișier selectat precedent.

Funcția PopFileSaveDlg din POPFILE.C este similară. Setează parametrul Flags la OFN_OVERWRITEPROMPT și apelează
GetSaveFileName pentru a invoca fereastra de dialog Save File. OFN_OVERWRITEPROMPT flag face ca o fereastra de mesaje să
fie afișată întrebând utilizatorului dacă doreste sa suprascrie (overwrite) dacă fișierul selectat deja există.
BOOL PopFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd;
ofn.lpstrFile = pstrFileName;
ofn.lpstrFileTitle = pstrTitleName;
ofn.Flags = OFN_OVERWRITEPROMPT;

return GetSaveFileName(&ofn);
}
În timpul mesajului WM_CREATE, POPPAD apelează functia PopFontInitialize în POPFONT.C.

// Initialize common dialog box stuff


PopFileInitialize(hwnd);
PopFontInitialize(hwndEdit);

Această funcție obține o structură LOGFONT bazată pe fontul de sistem, creează un font de acest tip
și trimite un mesaj WM_SETFONT la controlul de editare pentru a seta un nou font. (Deși fontul de
control de editare implicit este fontul de sistem, funcția PopFontInitialize creează un nou font pentru
controlul de editare deoarece în cele din urmă fontul va fi șters și ar fi periculos să ștergeți fontul de
sistem stoc.)

void PopFontInitialize(HWND hwndEdit)


{
GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT),
(PTSTR)& logfont);

hFont = CreateFontIndirect(&logfont);
SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hFont, 0);
}
Când PopPad primește un mesaj WM_COMMAND pentru opțiunea font a programului, acesta apelează
PopFontChooseFont. Această funcție inițializează o structură CHOOSEFONT și apoi apelează ChooseFont pentru a
afișa caseta de dialog pentru selectarea fontului. Dacă utilizatorul apasă butonul OK, ChooseFont va returna TRUE.
BOOL PopFontChooseFont(HWND hwnd)
switch (LOWORD(wParam)) {
{ CHOOSEFONT cf;
//..//
case IDM_FORMAT_FONT: cf.lStructSize = sizeof(CHOOSEFONT);
cf.hwndOwner = hwnd;
if (PopFontChooseFont(hwnd))
cf.hDC = NULL;
PopFontSetFont(hwndEdit); cf.lpLogFont = &logfont;
return 0; cf.iPointSize = 0;
//..// cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS |
CF_EFFECTS;
cf.rgbColors = 0;
cf.lCustData = 0;
cf.lpfnHook = NULL;
cf.lpTemplateName = NULL;
cf.hInstance = NULL;
cf.lpszStyle = NULL;
cf.nFontType = 0; // Returned from
ChooseFont
cf.nSizeMin = 0;
cf.nSizeMax = 0;

return ChooseFont(&cf);
}
POPPAD apelează apoi la PopFontSetFont pentru a seta noul font în
controlul de editare. Fontul vechi este șters.
În cele din urmă, în timpul mesajului WM_DESTROY, POPPAD apelează
PopFontDeinitialize pentru a șterge ultimul font pe care PopFontSetFont
la creat.
void PopFontSetFont(HWND hwndEdit)
{
HFONT hFontNew;
void PopFontDeinitialize(void)
RECT rect; {
DeleteObject(hFont);
hFontNew = CreateFontIndirect(&logfont); }
SendMessage(hwndEdit, WM_SETFONT,
(WPARAM)hFontNew, 0);
DeleteObject(hFont);
hFont = hFontNew;
GetClientRect(hwndEdit, &rect);
InvalidateRect(hwndEdit, &rect, TRUE);
}
Căutați și înlocuiți
Biblioteca comună cu ferestre de dialog (The common dialog box library)
include, de asemenea, două căsuțe de dialog pentru funcțiile de căutare și
înlocuire a textului. Aceste două funcții (FindText și ReplaceText) folosesc
o structură de tip FINDREPLACE.
Fișierul POPFIND.C are două rutine (PopFindFindDlg și
PopFindReplaceDlg) pentru a apela aceste funcții, și are, de asemenea,
câteva funcții pentru a căuta prin text în pagina de editare și pentru a
înlocui textul.
static TCHAR BOOL PopFindFindText(HWND hwndEdit,
szFindText[MAX_STRING_LEN]; int* piSearchOffset, LPFINDREPLACE
static TCHAR pfr)
szReplText[MAX_STRING_LEN]; {
int iLength, iPos;
HWND PopFindFindDlg(HWND hwnd) HWND PopFindReplaceDlg(HWND hwnd) PTSTR pstrDoc, pstrPos;
{ {
static FINDREPLACE fr; // static FINDREPLACE fr; // // Read in the edit document
must be static for modeless must be static for modeless GetWindowText(hwndEdit, pstrDoc,
dialog!!! dialog!!! iLength + 1);
// Search the document for the find
fr.lStructSize = fr.lStructSize = string
sizeof(FINDREPLACE); sizeof(FINDREPLACE); pstrPos = _tcsstr(pstrDoc +
fr.hwndOwner = hwnd; fr.hwndOwner = hwnd; *piSearchOffset, pfr->lpstrFindWhat);
fr.hInstance = NULL; fr.hInstance = NULL; free(pstrDoc);
fr.Flags = FR_HIDEUPDOWN | fr.Flags = FR_HIDEUPDOWN | // Find the position in the document
FR_HIDEMATCHCASE | FR_HIDEMATCHCASE | and the new start offset
FR_HIDEWHOLEWORD; FR_HIDEWHOLEWORD; iPos = pstrPos - pstrDoc;
fr.lpstrFindWhat = szFindText; fr.lpstrFindWhat = szFindText; *piSearchOffset = iPos + lstrlen(pfr-
fr.lpstrReplaceWith = NULL; fr.lpstrReplaceWith = szReplText; >lpstrFindWhat);
fr.wFindWhatLen = MAX_STRING_LEN; fr.wFindWhatLen = MAX_STRING_LEN; // Select the found text
fr.wReplaceWithLen = 0; fr.wReplaceWithLen = SendMessage(hwndEdit, EM_SETSEL,
fr.lCustData = 0; MAX_STRING_LEN; iPos, *piSearchOffset);
fr.lpfnHook = NULL; fr.lCustData = 0; SendMessage(hwndEdit, EM_SCROLLCARET,
fr.lpTemplateName = NULL; fr.lpfnHook = NULL; 0, 0);
fr.lpTemplateName = NULL;
return FindText(&fr); return TRUE;
} return ReplaceText(&fr); }
}
!Ferestrele de dialog invocate sunt ferestre de dialog modeless, ceea ce înseamnă că
ar trebui să vă modificați bucla de mesaj pentru a apela IsDialogMessage.
În al doilea rând, structura FINDREPLACE folosita de FindText și ReplaceText
trebuie să fie o variabilă statică;
În al treilea rând, în timp ce dialogurile FindText și ReplaceText sunt afișate, acestea
comunică cu fereastra parinte printr-un mesaj special. Numărul mesajului poate fi
obținut apelând la funcția RegisterWindowMessage cu parametrul
FINDMSGSTRING. Acest lucru se face în timp ce se proceseaza mesajului
WM_CREATE în WndProc, iar numărul mesajului este stocat într-o variabilă statică.

case WM_CREATE:
hInst = ((LPCREATESTRUCT)lParam)->hInstance;

// Create the edit control child window


//. . . //
// Initialize common dialog box stuff
messageFindReplace = RegisterWindowMessage(FINDMSGSTRING);
În timp ce se procesează mesajului implicit, WndProc compară variabila mesajului cu valoarea returnata din RegisterWindowMessage.
Parametrul mesajului lParam este un indicator către Structura FINDREPLACE și câmpul Flags indică dacă utilizatorul a folosit caseta de
dialog pentru a gasi text sau pentru a înlocui text sau dacă caseta de dialog se încheie.
switch (LOWORD(wParam))
{
//. . . //
default:

if (message == messageFindReplace)
{
pfr = (LPFINDREPLACE)lParam;
if (pfr->Flags & FR_DIALOGTERM)
hDlgModeless = NULL;

if (pfr->Flags & FR_FINDNEXT)


if (!PopFindFindText(hwndEdit, &iOffset, pfr))
OkMessage(hwnd, TEXT("Text not found!"),
TEXT("\0"));

if (pfr->Flags & FR_REPLACE || pfr->Flags & FR_REPLACEALL)


if (!PopFindReplaceText(hwndEdit, &iOffset, pfr))
OkMessage(hwnd, TEXT("Text not found!"),
TEXT("\0"));

if (pfr->Flags & FR_REPLACEALL)


while (PopFindReplaceText(hwndEdit, &iOffset, pfr));

return 0;
}
Sfârșit.

S-ar putea să vă placă și