Programarea in Windows Cap 10

download Programarea in Windows  Cap 10

of 37

description

Programarea in Windows

Transcript of Programarea in Windows Cap 10

Capitolul 10Meniuri i taste de acceleraremi amintesc o schi a lui Monty Python despre un magazin de brnzeturi. Era cam aa: un tip intr ntr-un magazin de brnzeturi i cere un anumit sortiment de brnz. Desigur, magazinul nu avea aa ceva. Tipul cere un alt sortiment, apoi altul i altul (n total cam 40 de sortimente de brnz) i rspunsul este n continuare: nu, nu, nu. n sfrit, povestea se termin cu nite mpucturi.Acest incident nefericit ar fi putut fi evitat dac s-ar fi folosit meniuri. Un meniu este o list de opiuni disponibile. Un meniu i poate spune unui tip flmnd ce poate servi buctria sau, n cazul unui program Windows, i poate spune utilizatorului ce operaii poate s execute aplicaia respectiv.Meniurile sunt probabil partea cea mai important a interfeei cu utilizatorul, oferit de programele Windows, iar adugarea unui meniu la un program este o operaie relativ uoar n programarea sub Windows. Nu trebuie dect s definii structura meniului n fiierul de resurse i s atribuii un numr de identificare (ID) unic fiecrui articol din meniu. Specificai apoi numele meniului n structura de clas a ferestrei. Atunci cnd utilizatorul selecteaz o opiune de meniu, Windows trimite programului un mesaj WM_COMMAND care conine identificatorul articolului respectiv. Dar nu ne vom opri la acest exemplu simplu. Unul dintre cele mai interesante lucruri pe care le putei face cu meniurile este s afiai imagini bitmap n meniu n locul unor iruri de caractere, aa c vom discuta n detaliu modul n care putei s facei acest lucru.Tot n acest capitol vom discuta i despre tastele de accelerare". Acestea sunt combinaii de taste folosite, n principal, pentru dublarea unor funcii de meniu.

MeniuriBara de meniu a unei ferestre este afiat imediat sub bara de titlu i este numit uneori meniu principal" sau meniul de pe primul nivel". Articolele din meniul principal sunt folosite de obicei pentru afiarea unui meniu derulant (drop-down menu" sau popup menu") numit uneori i submeniu". Putei s definii niveluri multiple de meniuri derulante: un articol al unui meniu derulant poate s activeze un alt meniu derulant. Uneori articolele din meniurile derulante activeaz o caset de dialog pentru afiarea unor informaii suplimentare. (Despre casetele de dialog vom discuta n capitolul urmtor.) Majoritatea ferestrelor principale afieaz n partea stng a barei de titlu o pictogram mic a programului. Aceast pictogram apeleaz meniul de sistem, care este tot un meniu derulant.Articolele din meniurile derulante pot fi validate", ceea ce nseamn c Windows deseneaz un mic marcaj de validare n partea stng a textului corespunztor articolului de meniu. Marcajele de validare permit utilizatorului s-i dea seama ce opiuni au fost selectate din meniu. Aceste opiuni se pot exclude reciproc, dar acest lucru nu este obligatoriu. Articolele din meniul principal nu pot fi validate.Articolele din meniul principal i din meniurile derulante pot fi activate", dezactivate" (uneori se folosesc cu acelai sens termenii active" i inactive") sau gri". Articolele de meniu activate i dezactivate arat la fel pentru utilizatori, dar textul meniurilor gri" este scris cu un ton de gri.Din punctul de vedere al utilizatorului, articolele de meniu activate, dezactivate sau gri pot fi selectate". Aceasta nseamn c utilizatorul poate s execute clic pe un articol de meniu dezactivat, poate s mute bara cursor afiat n video invers pe un articol dezactivat sau poate s marcheze articolul respectiv folosind tasta cheie corespunztoare. Totui, din perspectiva programuui, articolele de meniu activate, dezactivate i gri funcioneaz n mod diferit. Windows trimite programului un mesaj WM_COMMAND numai pentru meniurile activate. Meniurile dezactivate sau gri sunt folosite pentru opiunile care n momentul respectiv nu sunt valide. Dac vrei ca utilizatorul s tie c o anumit opiune nu este valid, afiai-o cu gri.Structura meniurilorAtunci cnd creai sau cnd modificai meniurile unui program, este bine s v gndii la meniul principal i la meniurile derulante, ca la meniuri diferite. Meniul principal are o variabil handle, fiecare meniu derulant apelat de meniul principal are o variabil handle proprie i meniul de sistem (care este tot un meniu derulant) are o alt variabil handle.Fiecare articol de meniu este definit prin trei caracteristici. Prima caracteristic este ceea ce apare n meniu. Aceasta poate fi un ir de caractere sau o imagine bitmap. Cea de-a doua caracteristic este fie un numr de identificare pe care Windows l trimite programului prin mesajul WM_COMMAND, fie un meniu derulant afiat atunci cnd utilizatorul selecteaz articolul respectiv. A treia caracteristic descrie atributele articolului respectiv, indiferent dac acesta este activat, dezactivat, gri sau validat.ablonul meniurilorPutei s creai un meniu n trei moduri. Cea mai obinuit (i mai simpl) cale este s definii meniul n fiierul script de resurse sub forma unui ablon de meniu, cum ar fi:HyMenu MENU { [lista meniului]MyMenu este numele meniului. Acest nume este referit n structura de clas a ferestrei. De obicei, numele meniului este acelai cu numele aplicaiei.ntre acolade putei s folosii instruciunile MENUITEM i POPUP. Formatul instruciunii MENUITEM este:MENUITEM "&Text", id [, opiuni] iar formatul instruciunii POPUP este:POPUP "&Text", id [, opiuni] {[lista meniului] }n locul acoladelor, dac dorii, putei s folosii cuvintele cheie BEGIN i END. Textul afiat pentru fiecare meniu trebuie s fie ncadrat ntre ghilimele. Caracterul care urmeaz dup ampersand (&) va fi afiat subliniat. Acesta este caracterul pe care l va cuta sistemul de operare Windows atunci cnd selectai meniul cu ajutorul tastei Alt. Dac textul nu conine caracterul ampersand, nu va fi subliniat nici un caracter, iar Windows va folosi prima liter a textului pentru combinaiile cu tasta Alt.Opiunile pe care putei s le folosii pentru instruciunile MENUITEM i POPUP din lista meniurilor principale sunt: GRAYED - Articolul respectiv este dezactivat, nu genereaz mesajeWM_COMMAND, iar textul este afiat cu gri. INACTIVE - Articolul respectiv este dezactivat, nu genereaz mesajeWM_COMMAND, iar textul este afiat normal. MENUBREAK - Articolul respectiv i cele care urmeaz sunt afiate pe onou linie a meniului. HELP - Articolul respectiv i cele care urmeaz sunt aliniate la dreapta.Opiunile pot fi combinate cu ajutorul simbolului SAU orientat pe bii din C (|), dar opiunile GRAYED i INACTIVE nu pot fi folosite mpreun. Opiunea MENUBREAK este rareori folosit pentru articolele din meniul principal, deoarece Windows afieaz automat acest meniu pe mai multe linii, dac fereastra este prea ngust ca s ncap toate articolele.Dac urmeaz dup o instruciune POPUP, acoladele (sau cuvintele cheie BEGIN i END) ncadreaz lista articolelor in meniul derulant. Urmtoarele instruciuni pot fi folosite pentru definirea unui meniu derulant:MENUITEM "text", id [, opiuni]SIMENUITEM SEPARATOR iPOPUP "text", [, opiuni]MENUITEM SEPARATOR deseneaz o linie orizontal n meniul derulant. Aceast linie este deseori folosit pentru separarea grupurilor de articole nrudite.Pentru articolele din meniurile derulante putei s folosii n irul de caractere caracterul tab (\t). Textul care urmeaz dup acest caracter este afiat ntr-o nou coloan, destul de departe, pentru ca n prima coloan s ncap cel mai lung ir de caractere din meniul derulant. Vom vedea cum funcioneaz acest caracter atunci cnd vom discuta despre tastele de accelerare, ctre sfritul acestui capitol. Dac n irul de caractere includei combinaia \a, textul care urmeaz este aliniat la dreapta, n meniurile derulante, pentru instruciunea MENUITEM putei s folosii urmtoarele opiuni. CHECKED - n partea stng a textului este afiat un marcaj de validare.

GRAYED - Articolul respectiv este dezactivat, nu genereaz mesajeWM_COMMAND, iar textul este afiat cu gri. INACTIVE - Articolul respectiv este dezactivat, nu genereaz mesajeWM_COMMAND, iar textul este afiat normal. MENUBREAK - Articolul respectiv i cele care urmeaz sunt afiate pe onou coloan a meniului. MENUBARBREAK - Articolul respectiv i cele care urmeaz sunt afiatepe o nou coloan a meniului. Coloanele sunt separate de o linie vertical.Opiunile GRAYED i INACTIVE nu pot fi folosite mpreun. Opiunile MENUBREAK i MENUBARBREAK nu pot fi folosite mpreun. Putei s folosii opiunea MENUBREAK sau opiunea MENUBARBREAK atunci cnd meniul derulant conine prea multe opiuni pentru a fi afiate pe o singur coloan.Identificatorii din instruciunile MENUITEM sunt numerele pe care Windows le \ trimite procedurii ferestrei prin mesajele de meniu. Valorile de identificare trebuie s fie unice n cadrul unui meniu. n locul numerelor putei s folosii identificatori definii ntr-un fiier antet. Prin convenie, aceti identificatori ncep cu literele IDM (IDentificator de Meniu").Referirea unui meniu n programMulte aplicaii Windows au n fiierul script de resurse un singur meniu. Programul face referire la acest meniu atunci cnd este definit clasa ferestrei:wndclass.lpszMenuName = "MyMenu" ;Programatorii folosesc deseori pentru numele meniului numele programului, astfel nct acelai ir de caractere poate fi folosit pentru clasa ferestrei, numele pictogramei

programului i numele meniului. Totui, n locul numelui putei s folosii un numr (sau un macro-identificator). n acest caz, fiierul script de resurse va arta astfel:45 MENU ([definiia meniului] )n acest caz, instruciunea de atribuire a variabilei membru IpszMenuName din structura clasei poate fi:wndclass.IpszMenuName = MAKEINTRESOURCE (45) ; sauwndclass.IpszMenuName "#45" ;Dei specificarea meniului n clasa ferestrei este calea cel mai des folosit de referire a unei resurse de tip meniu, avei i alte posibiliti. O aplicaie Windows poate s ncarce resursa unui meniu n memorie folosind funcia LoadMenu, asemntoare cu funciile Loadlcon i LoadCursor descrise n Capitolul 9. Dac n fiierul script de resurse folosii un nume pentru meniu, funcia LoadMenu returneaz o variabil handle a meniului:hMenu = LoadMenu (hlnstance, "MyMenu") ; Dac folosii un numr, apelul funciei LoadMenu ia una dintre formele urmtoare:hMenu = LoadMenu (hlnstance, MAKEINTRESOURCE (45)) ;sauhMenu LoadMenu (hlnstance, "#45") ;Putei apoi s specificai variabila handle returnat ca al noulea parametru al funciei CreateWindow:hwnd - CreateWindow ("MyClass", "Window Caption", WS_OVERLAPPEDWINDOW, CW USEDEFAULT, CWJJSEDEFAULT, CITUSEDEFAULT, CWJSEDEFAULT, NULL, NULL,hlnstance, NULL) ;n acest caz, meniul specificat ca parametru al funciei CreateWindow suprascrie orice meniu specificat n clasa ferestrei. Putei s considerai meniul din clasa ferestrei ca fiind meniul prestabilit pentru ferestrele bazate pe clasa ferestrei n cazul n care cel de-al noulea parametru al funciei CreateWindow are valoarea NULL. Ca urmare, putei s folosii meniuri diferite pentru mai multe ferestre bazate pe aceeai clas.Putei s avei un meniu NULL n clasa ferestrei i un meniu NULL la apelarea funciei CreateWindow, i s atribuii ferestri un meniu dup creare:SetMenu (hwnd, hMenu) ;Aceast funcie v permite schimbarea dinamic a meniului unei ferestre. Vom vedea un astfel de exemplu n programul NOPOPUPS, prezentat mai trziu n acest capitol.Orice meniu ataat unei ferestre este distrus odat cu fereastra. Orice meniu care nu este ataat unei ferestre trebuie s fie distrus explicit prin apelarea funciei DestroyMenu, nainte de nchiderea programului.Meniuri i mesajeSistemul de operare Windows trimite procedurii unei ferestre mai multe mesaje diferite atunci cnd utilizatorul selecteaz un articol din meniu. n majoritatea cazurilor, programul poate s ignore aceste mesaje i s le retransmit procedurii DefWindowProc. Un astfel de mesaj este WMJNITMENU, cu urmtorii parametri:wParam

IParamVariabila handle a meniului principal 0Parametrul wParam conine variabila handle a meniului principal, chiar dac utilizatorul selecteaz un articol din meniul de sistem. n general, programele Windows ignor mesajul WM_INITMENU. Dei transmiterea acestui mesaj v d posibilitatea s modificai meniul nainte de selectarea unui articol, bnuiesc c orice modificare n meniul principal n acest moment ar fi foarte deconcertant pentru utilizator.De asemenea, programul primete i mesaje WM_MENUSELECT. Programul poate primi mai multe mesaje WM_MENUSELECT, pe msur ce utilizatorul mut cursorul sau mouse-ul pe diferite articole de meniu. Aa cum vom vedea n Capitolul 12, acest mesaj este foarte util pentru implementarea unei bare de stare care conine o descriere complet a opiunii din meniu. Parametrii mesajului WM_MENUSELECT sunt:LOWORD (wParam)

HIWORD (vParam) IParamArticolul selectat: identificatorul de meniu sau variabila handle a meniului derulant

Indicatorul flag de selectare

Variabila handle a meniului care conine articolul selectatWM_MENUSELECT este un mesaj de urmrire a meniului. Cuvntul mai puin semnificativ al parametrului wParam specific articolul de meniu care a fost selectat (marcat). Indicatorul flag de selectare" din cuvntul mai semnificativ al parametrului wParam poate fi o combinaie a urmtorilor identificatori: MF_GRAYED, MF_DIS-ABLED, MF_CHECKED, MF_BITMAP, MFJPOPUP, MFJHELP, MF_SYSMENU i MF_MOUSESELECT. Putei s folosii mesajul WM_MENUSELECT dac dorii s modificai ceva n zona client a ferestrei n funcie de deplasarea barei de selectare ntre articolele de meniu. Majoritatea programelor retransmit acest mesaj procedurii DefWindowProc.Atunci cnd este pregtit s afieze un meniu derulant, Windows trimite procedurii ferestrei un mesaj WM_INITMENUPOPUP cu urmtorii parametri:Capitolul 10 Meniuri i taste de accelerarewParam

LOWORD (IParam)

HIWORD (IParam)Variabila handle a meniului derulant

Indexul meniului derulant

1 pentru meniul sistem, O pentru alte meniuriAcest mesaj este important dac vrei s activai sau s dezactivai articole dintr-un meniu derulant nainte ca acesta s fie afiat. De exemplu, s presupunem c programul ofer utilizatorului posibilitatea de a copia text din memoria temporar (clipboard) cu ajutorul comenzii Paste, dintr-un meniu derulant. Atunci cnd primii mesajul WMJNITMENUPOPUP trebuie s determinai dac n clipboard exist vreun text. Dac nu exist, ar trebui s afiai cu gri articolul de meniu Paste. Vei vedea un astfel de exemplu n programul POPPAD revizuit, prezentat ctre sfritul acestui capitol.Cel mai important mesaj este WM_COMMAND. Acest mesaj indic faptul c utilizatorul a selectat un articol activat din meniul ferestrei. V amintii din Capitolul 8 c mesajul WM_COMMAND este trimis i de controale. Dac folosii acelai identificator pentru un articol de meniu i pentru un control, putei s difereniai mesajele n funcie de parametrul IParam, care are valoarea 0 n cazul articolelor de meniu.LOWORD (wParam)

HIWORD (wParam) IParamMeniu: Identificatorul meniului Control: Identificatorul controlului

0Cod de ntiinare

0Variabila handle a ferestrei descendentMesajul WM_SYSCOMMAND este asemntor cu mesajul WM_COMMAND, cu excepia faptului c primul semnaleaz selectarea unui articol activat din meniul de sistem:LOWORDHIWORD

(wParam)(wParam)IParam

Meniu de sistem:Identificatorul00 (Dac mesajul

meniuluiWM SYSCOMMAND a fost

trimis n urma executrii unui clic,

LOWORD (IParam) i HIWORD

(IParam) conin coordonatele X i

Y ale indicatorului mouse-ului.)

Identificatorul de meniu specific articolul selectat din meniul sistem. Pentru articolele de meniu predefinite, ultimii patru bii ar trebui mascai. Valoarea rezultat poate fi: SC_SIZE, SC_MOVE, SC_MINIMIZE, SCJMAXIMIZE, SC_NEXTWINDOW, SCJPREVWINDOW, SQCLOSE, SCJVSCROLL, SC_HSCROLL, SC_ARRANGE, SC_RESTORE i SC_TASKLIST. n plus, cuvntul mai puin semnificativ al parametrului xoPram poate fi SC_MOUSEMENU sau SC_KEYMENU.Dac adugai noi articole n meniul sistem, cuvntul mai puin semnificativ al parametrului wParam va conine numrul de identificare al articolului pe care l-ai definit. Pentru a evita conflictele cu identificatorii articolelor predefinite, folosii valori mai mici de OxFOOO. Este foarte important ca mesajele WM_SYSCOMMAND s fie trimise ctre procedura DefWindowProc. n caz contrar, vei dezactiva comenzile normale din meniul sistem.Ultimul mesaj despre care vom discuta este WM_MENUCHAR, care nu este un mesaj de meniu. Windows trimite acest mesaj ctre procedura ferestrei n dou situaii: dac utilizatorul apas tasta Alt i o tast care nu corespunde unui articol de meniu, sau atunci cnd este afiat un meniu derulant, dac utilizatorul apas o tast care nu corespunde nici unui articol din meniul respectiv. Mesajul WM_MENU-CHAR are urmtorii parametri:LOWORD (wParam)

HP/VORD (wParam)

IParamCod ASCII

Cod de selectare

Variabil handle a meniuluiCodul de selectare poate avea urmtoarele valori: 0 - Nu a fost afiat nici un meniu derulant. MF_POPUP - Este afiat un meniu derulant. MF_SYSMENU - Este afiat meniul sistem.De obicei, programele Windows transmit acest mesaj procedurii DefWindowProc, care returneaz sistemului de operare Windows valoarea 0, avnd ca rezultat emiterea unui semnal sonor (beep). Vom vedea cum este folosit mesajul WM_MENUCHAR n programul GRAFMENU prezentat mai trziu n acest capitol.Un program de exemplificareHaidei s vedem un mic exemplu. Programul MENUDEMO, prezentat n Figura 10-1, are patru articole n meniul principal - File, Edit, Background, Timer i Help. Fiecare dintre aceste articole are un meniu derulant. MENUDEMO execut cele mai simple i mai obinuite operaii de prelucrare a meniurilor, care implic interceptarea mesa-jmlui WM_COMMAND i verificarea cuvntului mai puin semnificativ al parametrului wParam.

MENUDEMO.MAK

#------------------------

# Fiierul de construcie MENUDEMO.MAK

#------------------------

menudemo.exe : menudemo.obj menudemo.res

$(LINKER) $(GUIFLAGS) -OUT:menudemo.exe menudemo.obj \

menudemo.res $(GUILIBS)

menudemo.obj : menudemo.c menudemo.h

$(CC) $(CFLAGS) menudemo.c

menudemo.res : menudemo.rc menudemo.h

$(RC) $(RCVARS) menudemo.rc

MENUDEMO.C

/*-----------------------------------------

MENUDEMO.C Program demonstrativ pentru meniuri

-----------------------------------------*/

#include

#include "menudemo.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char szAppName[] = "MenuDemo";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

HWND hwnd;

MSG msg;

WNDCLASSEX wndclass;

wndclass.cbSize = sizeof(wndclass);

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = szAppName;

wndclass.lpszClassName = szAppName;

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hwnd = CreateWindow(szAppName, "Menu Demonstration",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static int iColorID[5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,

DKGRAY_BRUSH, BLACK_BRUSH };

static int iSelection = IDM_WHITE;

HMENU hMenu;

switch(iMsg)

{

case WM_COMMAND :

hMenu = GetMenu(hwnd);

switch(LOWORD(wParam))

{

case IDM_NEW :

case IDM_OPEN :

case IDM_SAVE :

case IDM_SAVEAS :

MessageBeep(0);

return 0;

case IDM_EXIT :

SendMessage(hwnd, WM_CLOSE, 0, 0L);

return 0;

case IDM_UNDO :

case IDM_CUT :

case IDM_COPY :

case IDM_PASTE :

case IDM_DEL :

MessageBeep(0);

return 0;

case IDM_WHITE : // Note: Logica urmtoare se bazeaz pe presupunerea c indicatorii cuprini ntre IDM_WHITE i IDM_BLACK sunt numere consecutive n ordinea artat aicicase IDM_LTGRAY : // case IDM_GRAY : // case IDM_DKGRAY : // case IDM_BLACK : // CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);

iSelection = LOWORD(wParam);

CheckMenuItem(hMenu, iSelection, MF_CHECKED);

SetClassLong(hwnd, GCL_HBRBACKGROUND,

(LONG) GetStockObject

(iColorID[LOWORD(wParam) - IDM_WHITE]));

InvalidateRect(hwnd, NULL, TRUE);

return 0;

case IDM_START :

if(SetTimer(hwnd, 1, 1000, NULL))

{

EnableMenuItem(hMenu, IDM_START, MF_GRAYED);

EnableMenuItem(hMenu, IDM_STOP, MF_ENABLED);

}

return 0;

case IDM_STOP :

KillTimer(hwnd, 1);

EnableMenuItem(hMenu, IDM_START, MF_ENABLED);

EnableMenuItem(hMenu, IDM_STOP, MF_GRAYED);

return 0;

case IDM_HELP :

MessageBox(hwnd, "Help not yet implemented!",

szAppName, MB_ICONEXCLAMATION | MB_OK);

return 0;

case IDM_ABOUT :

MessageBox(hwnd, "Menu Demonstration Program.",

szAppName, MB_ICONINFORMATION | MB_OK);

return 0;

}

break;

case WM_TIMER :

MessageBeep(0);

return 0;

case WM_DESTROY :

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

MENUDEMO.RC

/*-----------------------------

MENUDEMO.RC - fiier script de resurse -----------------------------*/

#include "menudemo.h"

MenuDemo MENU

{

POPUP "&File"

{

MENUITEM "&New", IDM_NEW

MENUITEM "&Open...", IDM_OPEN

MENUITEM "&Save", IDM_SAVE

MENUITEM "Save &As...", IDM_SAVEAS

MENUITEM SEPARATOR

MENUITEM "E&xit", IDM_EXIT

}

POPUP "&Edit"

{

MENUITEM "&Undo", IDM_UNDO

MENUITEM SEPARATOR

MENUITEM "Cu&t", IDM_CUT

MENUITEM "&Copy", IDM_COPY

MENUITEM "&Paste", IDM_PASTE

MENUITEM "De&lete", IDM_DEL

}

POPUP "&Background"

321

{

MENUITEM "&White", IDM_WHITE, CHECKED

MENUITEM "&Lt Gray", IDM_LTGRAY

MENUITEM "&Gray", IDM_GRAY

MENUITEM "&Dk Gray", IDM_DKGRAY

MENUITEM "&Black", IDM_BLACK

}

POPUP "&Timer"

{

MENUITEM "&Start" IDM_START

MENUITEM "S&top" IDM_STOP, GRAYED

}

POPUP "&Help"

{

MENUITEM "&Help...", IDM_HELP

MENUITEM "&About MenuDemo...", IDM_ABOUT

}

}

MENUDEMO.H

/*------------------------

MENUDEMO.H fiier antet------------------------*/

#define IDM_NEW 1

#define IDM_OPEN 2

#define IDM_SAVE 3

#define IDM_SAVEAS 4

#define IDM_EXIT 5

#define IDM_UNDO 10

#define IDM_CUT 11

#define IDM_COPY 12

#define IDM_PASTE 13

#define IDM_DEL 14

#define IDM_WHITE 20

#define IDM_LTGRAY 21

#define IDM_GRAY 22

#define IDM_DKGRAY 23

#define IDM_BLACK 24

#define IDM_START 30

#define IDM_STOP 31

#define IDM_HELP 40

#define IDM_ABOUT 41

Fig. 10.1 Programul MENUDEMO

Identificatorii pentru fiecare meniu sunt definii n fiierul MENUDEMO.H. Acest fiier trebuie specificat (de obicei printr-o instruciune Mnclude) att n fiierul script de resurse, ct i n codul surs C. Toi identificatorii ncep cu literele IDM. Nu este nevoie ca numerele de identificare folosite pentru articolele dintr-un meniu s fie consecutive. Totui, dac prelucrai aceti identificatori folosind instruciuni switch i case, compilatorul C poate s optimizeze codul cu ajutorul unor tabele de salt (jump tables) dac folosii numere de identificare consecutive.Pentru majoritatea articolelor din meniurile File i Edit, programul MENUDEMO nu face dect s emit un semnal sonor atunci cnd primete mesajul WM_COM-MAND. Meniul derulant Background conine un set de cinci pensule pe care putei s Ie folosii pentru colorarea fondului. n fiierul de resurse MENUDEMO.RC articolul de meniu White (cu identificatorul IDM_WHITE) este marcat cu opiunea CHECKED, ceea ce are ca efect afiarea unui marcaj de validare n dreptul acestui articol. n fiierul MENUDEMO.C, variabila iSeledion are iniial valoarea IDM_WHITE.'Cele cinci pensule din meniul Background se exclud reciproc. Atunci cnd primete un mesaj WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam conine identificatorul unuia dintre cele cinci articole din meniul Background, programul trebuie s tearg mai nti marcajul de validare din dreptul articolului selectat anterior i apoi s adauge altul n dreptul noii culori. Pentru aceasta, programul are nevoie de o variabil handle a meniului:hMenu - GetMenu (hwnd) ;Funcia CheckMenuItem este folosit pentru tergerea marcajului de validare din dreptul articolului curent selectat:CheckMenuItem (hMenu, iSelection, MFJINCHECKED) ;Variabila iSelection primete valoarea cuvntului mai puin semnificativ al parametrului wParam i noua culoare de fond este marcat:iSelection = LOWORD (wParam) ;CheckMenuItem (hMenu, iSelection, MF_CHECKED) ;n continuare culoarea de fond din clasa ferestrei este nlocuit cu noua culoare, iar zona client a ferestrei este invalidat. Windows terge zona client folosind noua culoare de fond.Meniul derulant Timer (Cronometru) conine dou opiuni - Start i Stop. Iniial, opiunea Stop este scris cu gri (aa cum indic definiia meniului din fiierul script de resurse). Atunci cnd selectai opiunea Start, programul MENUDEMO ncearc s porneasc un cronometru i, dac reuete, afieaz cu gri opiunea Start i activeaz opiunea Stop:EnableMenuItem (hMenu, IDMJTART, MFJRAYED) ; EnableMenuItem (hMenu, IDM_ST0P, MF_ENABLED) ;La primirea unui mesaj WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam conine identificatorul IDM_STOP, programul MENUDEMO oprete cronometrul, activeaz opiunea Start i dezactiveaz opiunea Stop:EnableMenuItem (hMenu, IDM START, MF_ENABLEO) ; EnableMenuItem (hMenu, IDMJTOP, MF_GRAYED) ;Remarcai faptul c este imposibil ca programul s primeasc un mesaj WM_COM-MAND n care cuvntul mai puin semnificativ al parametrului wParam s conin identificatorul IDM_START dup pornirea cronometrului. La fel, programul nu poate s primeasc un mesaj WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam s conin identificatorul IDM_STOP dup oprirea cronometrului.Atunci cnd primete un mesaj WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam conine identificatorul IDM_ABOUT sau IDM_HELP, programul MENUDEMO afieaz o caset de mesaje. (n capitolul urmtor vom nlocui aceast caset de mesaje cu o caset de dialog.)Atunci cnd primete un mesaj WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam conine identificatorul IDM_EXIT, programul MENUDEMO trimite un mesaj WM_CLOSE. Acelai mesaj l trimite procedura DefWindowProc ctre procedura ferestrei atunci cnd primete un mesaj WM_SYS-COMMAND n care cuvntul mai puin semnificativ al parametrului wParam conine identificatorul SC_CLOSE. Vom discuta mai multe despre acest mesaj n programul POPPAD2, prezentat ctre sfritul acestui capitol.Capitolul 10 Meniuri i taste de accelerareModul de folosire a meniurilorFormatul meniurilor Edit i File din programul MENUDEMO sunt foarte asemntoare cu aceleai meniuri din alte programe Windows. Unul dintre obiectivele sistemului de operare Windows este asigurarea unei interfee uor de recunoscut, astfel nct utilizatorul s nu fie nevoit de fiecare dat s nvee din nou conceptele de baz ale fiecrui program. Cu siguran, este de mare ajutor dac meniurile File i Edit din toate programele Windows arat la fel i folosesc aceleai combinaii de taste pentru selectare.n afar de meniurile File i Edit, celelalte meniuri ale programelor Windows arat diferit. Atunci cnd proiectai un meniu, ar trebui s studiai programele Windows existente i s ncercai s pstrai o configuraie uniform. Desigur, dac vi se pare c programele respective sunt greite i cunoatei o cale mai bun de a face aceleai lucruri, nimeni nu v oprete. De asemenea, reinei c pentru modificarea unui meniu trebuie s modificai numai fiierul script de resurse, nu i codul surs al programului. De exemplu, putei s schimbai ordinea articolelor din meniu fr prea multe probleme.Dei meniul unui program poate avea instruciuni MENUITEM pe primul nivel, situaia nu este una prea obinuit, deoarece aceste articole ar putea fi selectate din greeal. Dac facei acest lucru, adugai la sfritul textului un semn de exclamare, care s indice faptul c articolul respectiv nu apeleaz un meniu derulant.0 cale mai greoaie de definire a unui meniuDefinirea unui meniu n fiierul script de resurse al programului este, de obicei, cea mai simpl cale, dar nu i singura. Putei s renunai la fiierul script de resurse i s creai ntregul meniu direct n codul surs, folosind funciile CreateMenu i Append-Menu. Dup ce definii meniul, putei s transmitei funciei CreateWindow variabila handle a acestuia sau s apelai funcia SetMenu ca s schimbai meniul ferestrei.Iat cum putei s facei acest lucru. Funcia CreateMenu returneaz variabila handle a meniului:hHenu CreateMenu () ;Iniial meniul este gol. Prin apelarea funciei AppendMenu sunt inserate articolele de meniu. Trebuie s obinei variabile handle diferite pentru meniul principal i pentru fiecare meniu derulant. Meniurile derulante sunt construite separat, apoi variabilele handle ale acestora sunt inserate n meniul principal. Codul prezentat n Figura 10-2 creeaz un meniu prin aceast metod; de fapt, acesta este acelai meniu cu cel folosit de programul MENUDEMO.

hMenu = CreateMenu();

hMenuPopup = CreateMenu();

AppendMenu(hMenuPopup, MF_STRING, IDM_NEW, "&New");

AppendMenu(hMenuPopup, MF_STRING, IDM_OPEN, "&Open...");

AppendMenu(hMenuPopup, MF_STRING, IDM_SAVE, "&Save");

AppendMenu(hMenuPopup, MF_STRING, IDM_SAVEAS, "Save &As...");

AppendMenu(hMenuPopup, MF_SEPARATOR, 0, NULL);

AppendMenu(hMenuPopup, MF_STRING, IDM_EXIT, "E&xit");

AppendMenu(hMenu, MF_POPUP,(UINT) hMenuPopup, "&File");

hMenuPopup = CreateMenu();

AppendMenu(hMenuPopup, MF_STRING, IDM_UNDO, "&Undo");

AppendMenu(hMenuPopup, MF_SEPARATOR, 0, NULL);

AppendMenu(hMenuPopup, MF_STRING, IDM_CUT, "Cu&t");

AppendMenu(hMenuPopup, MF_STRING, IDM_COPY, "&Copy");

AppendMenu(hMenuPopup, MF_STRING, IDM_PASTE, "&Paste");

AppendMenu(hMenuPopup, MF_STRING, IDM_DEL, "De&lete");

AppendMenu(hMenu, MF_POPUP,(UINT) hMenuPopup, "&Edit");

hMenuPopup = CreateMenu();

AppendMenu(hMenuPopup, MF_STRING | MF_CHECKED, IDM_WHITE, "&White");

AppendMenu(hMenuPopup, MF_STRING, IDM_LTGRAY, "&Lt Gray");

AppendMenu(hMenuPopup, MF_STRING, IDM_GRAY, "&Gray");

AppendMenu(hMenuPopup, MF_STRING, IDM_DKGRAY, "&Dk Gray");

AppendMenu(hMenuPopup, MF_STRING, IDM_BLACK, "&Black");

AppendMenu(hMenu, MF_POPUP,(UINT) hMenuPopup, "&Background");

hMenuPopup = CreateMenu();

AppendMenu(hMenuPopup, MF_STRING, IDM_START, "&Start");

AppendMenu(hMenuPopup, MF_STRING | MF_GRAYED, IDM_STOP, "S&top");

AppendMenu(hMenu, MF_POPUP,(UINT) hMenuPopup, "&Timer");

hMenuPopup = CreateMenu();

AppendMenu(hMenuPopup, MF_STRING, IDM_HELP, "&Help...");

AppendMenu(hMenuPopup, MF_STRING, IDM_ABOUT, "&About MenuDemo...");

AppendMenu(hMenu, MF_POPUP,(UINT) hMenuPopup, "&Help");

Fig. 10.2 Codul C care creaz meniul utilizat de programul MENUDEMO, fr se foloseasc un fiier script de resurse.Cred c suntei de acord c metoda care folosete ablonul de meniu din fiierul script de resurse este mai simpl i mai clar. Ca urmare, nu v recomand s definii meniul j direct n codul surs, ci doar am artat c exist i aceast cale. Desigur, putei s ( reducei substanial dimensiunea codului surs cu ajutorul unor matrice, care s \ aonin irurile de caractere, identificatorii i indicatorii flag ai articolelor de meniu. Dar dac facei acest lucru, putei s folosii la fel de bine cea de-a treia metod de definire a unui meniu, prezentat n continuare.A treia metod de definire a unui meniuceasta funcie este folosit n Windows pentru construirea unui meniu dup ce ablonul normal a fost ncrcat din fiierul script de resurse. Dac suntei un programator curajos, putei s ncercai i aceast metod.Meniuri derulante plutitoare"Putei s folosii meniuri chiar dac nu avei o bar de meniu principal. Puteri s facei ca un meniu derulant s apar n orice parte a ecranului. O metod des folosit este apelarea acestui tip de meniuri ca rspuns la executarea unui clic cu butonul din dreapta al rnouse-ului. Articolele de meniu trebuie s fie selectate, ns, tot cu ajutorul butonului din stnga al mouse-ului. Programul POPMENU, prezentat n Figura 10-3 arata cum poate fi fcut acest lucru.POPMENU.MAK

#-----------------------

# Fiierul de construcie POPMENU.MAK

#-----------------------

popmenu.exe : popmenu.obj popmenu.res

$(LINKER) $(GUIFLAGS) -OUT:popmenu.exe popmenu.obj \

popmenu.res $(GUILIBS)

popmenu.obj : popmenu.c popmenu.h

$(CC) $(CFLAGS) popmenu.c

popmenu.res : popmenu.rc popmenu.h

$(RC) $(RCVARS) popmenu.rc

POPMENU.C

/*----------------------------------------

POPMENU.C program demonstrativ pentru meniurile derulante(c) Charles Petzold, 1996

----------------------------------------*/

#include

#include "popmenu.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char szAppName[] = "PopMenu";

HINSTANCE hInst;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

HWND hwnd;

MSG msg;

WNDCLASSEX wndclass;

wndclass.cbSize = sizeof(wndclass);

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = szAppName;

325

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hInst = hInstance;

hwnd = CreateWindow(szAppName, "Popup Menu Demonstration",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static HMENU hMenu;

static int iColorID[5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,

DKGRAY_BRUSH, BLACK_BRUSH };

static int iSelection = IDM_WHITE;

POINT point;

switch(iMsg)

{

case WM_CREATE :

hMenu = LoadMenu(hInst, szAppName);

hMenu = GetSubMenu(hMenu, 0);

return 0;

case WM_RBUTTONDOWN :

point.x = LOWORD(lParam);

point.y = HIWORD(lParam);

ClientToScreen(hwnd, &point);

TrackPopupMenu(hMenu, 0, point.x, point.y, 0, hwnd, NULL);

return 0;

case WM_COMMAND :

switch(LOWORD(wParam))

{

case IDM_NEW :

case IDM_OPEN :

case IDM_SAVE :

case IDM_SAVEAS :

case IDM_UNDO :

case IDM_CUT :

case IDM_COPY :

case IDM_PASTE :

case IDM_DEL :

MessageBeep(0);

return 0;

case IDM_WHITE : // Logica urmtoare se bazeaz pe presupunerea c identificatorii cuprini n intervalul IDM_WHITE i IDM_BLACK sunt numere consecutive n ordinea artat aicicase IDM_LTGRAY : // case IDM_GRAY : // case IDM_DKGRAY : // case IDM_BLACK : //

CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);

iSelection = LOWORD(wParam);

CheckMenuItem(hMenu, iSelection, MF_CHECKED);

SetClassLong(hwnd, GCL_HBRBACKGROUND,

(LONG) GetStockObject

(iColorID[LOWORD(wParam) - IDM_WHITE]));

InvalidateRect(hwnd, NULL, TRUE);

return 0;

case IDM_ABOUT :

MessageBox(hwnd, "Popup Menu Demonstration Program.",

szAppName, MB_ICONINFORMATION | MB_OK);

return 0;

case IDM_EXIT :

SendMessage(hwnd, WM_CLOSE, 0, 0);

return 0;

case IDM_HELP :

MessageBox(hwnd, "Help not yet implemented!",

szAppName, MB_ICONEXCLAMATION | MB_OK);

return 0;

}

break;

case WM_DESTROY :

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

POPMENU.RC

/*----------------------------

POPMENU.RC fiier script de resurse

----------------------------*/

#include "popmenu.h"

PopMenu MENU

{

POPUP ""

{

POPUP "&File"

{

MENUITEM "&New", IDM_NEW

MENUITEM "&Open...", IDM_OPEN

MENUITEM "&Save", IDM_SAVE

MENUITEM "Save &As...", IDM_SAVEAS

MENUITEM SEPARATOR

MENUITEM "E&xit", IDM_EXIT

}

POPUP "&Edit"

{

MENUITEM "&Undo", IDM_UNDO

MENUITEM SEPARATOR

MENUITEM "Cu&t", IDM_CUT

MENUITEM "&Copy", IDM_COPY

MENUITEM "&Paste", IDM_PASTE

327

MENUITEM "De&lete", IDM_DEL

}

POPUP "&Background"

{

MENUITEM "&White", IDM_WHITE, CHECKED

MENUITEM "&Lt Gray", IDM_LTGRAY

MENUITEM "&Gray", IDM_GRAY

MENUITEM "&Dk Gray", IDM_DKGRAY

MENUITEM "&Black", IDM_BLACK

}

POPUP "&Help"

{

MENUITEM "&Help...", IDM_HELP

MENUITEM "&About PopMenu...", IDM_ABOUT

}

}

}

POPMENU.H

/*-----------------------

POPMENU.H fiier antet-----------------------*/

#define IDM_NEW 1

#define IDM_OPEN 2

#define IDM_SAVE 3

#define IDM_SAVEAS 4

#define IDM_EXIT 5

#define IDM_UNDO 10

#define IDM_CUT 11

#define IDM_COPY 12

#define IDM_PASTE 13

#define IDM_DEL 14

#define IDM_WHITE 20

#define IDM_LTGRAY 21

#define IDM_GRAY 22

#define IDM_DKGRAY 23

#define IDM_BLACK 24

#define IDM_HELP 30

#define IDM_ABOUT 31

Fig. 10.3 Programul POPMENU Fiierul script de resurse POPMENU.RC definete un meniu foarte asemntor cu cel definit n fiierul MENUDEMO.RC. Diferena const n faptul c meniul principal conine un singur articol - un meniu derulant care conine opiunile File, Edit, Background i Help.n timpul prelucrrii mesajului WM_CREATE n procedura WndProc, POPMENU obine o variabil handle a acestui meniu derulant:hMenu = LoadMenu (hlnst, szAppName) ; hMenu = GetSubMenu (hMenu, 0) ;n timpul prelucrrii mesajului WM_RBUTTONDOWN, POPMENU obine poziia indicatorului mouse-ului, convertete aceast poziie n coordonate de ecran i transmite coordonatele obinute funciei TraekPopupMenu:point.x LOWORD (IParam) ; point.y = HIWORD (IParam) ; ClientToScreen (hwnd, &point) ;

TrackPopupMenu (hMenu, 0, point.x, point.y, 0, hwnd, NULL) ;Sistemul de operare afieaz apoi meniul derulant cu articolele File, Edit, Background i Help. Selectarea oricruia dintre aceste articole determin afiarea meniurilor derulante corespunztoare. Funciile din meniuri au acelai rol ca i funciile din meniul normal.Folosirea meniului sistemFerestrele printe create cu un stil care include identificatorul WS_SYSMENU au un meniu sistem n partea stng a barei de titlu. Dac dorii, putei s modificai acest meniu. De exemplu, putei s adugai n meniul sistem comenzi proprii. Dei acest lucru nu este recomandat, modificarea meniului sistem este o metod rapid, dar mai puin elegant de adugare a unui meniu la un program, fr definirea acestuia n fiierul script de resurse. Singura restricie este necesitatea ca numerele de identificare a comenzilor adugate n meniul sistem s fie mai mici de OxFOOO. n caz contrar, aceste numere vor intra n conflict cu identificatorii pe care Windows i folosete pentru comenzile normale din meniul sistem. Nu uitai c, dei mesajele WM_SYS-COMMAND pentru noile articole de meniu sunt prelucrate n procedura ferestrei, trebuie s transmitei procedurii DefWindowProc celelalte mesaje WM_SYSCOM-MAND. Dac nu facei acest lucru, toate opiunile normale din meniul sistem vor fi efectiv dezactivate.Programul POORMENU, prezentat n Figura 10-4, adaug n meniul sistem un separator i trei comenzi suplimentare. Ultima dintre cele trei comenzi terge comenzile adugate.

POORMENU.MAK

#------------------------

# Fiierul de construcie POORMENU.MAK make file

#------------------------

poormenu.exe : poormenu.obj

$(LINKER) $(GUIFLAGS) -OUT:poormenu.exe poormenu.obj $(GUILIBS)

poormenu.obj : poormenu.c

$(CC) $(CFLAGS) poormenu.c

POORMENU.C

/*-----------------------------------------

POORMENU.C Meniu pentru sraci(c) Charles Petzold, 1996

-----------------------------------------*/

#include

#define IDM_ABOUT 1

#define IDM_HELP 2

#define IDM_REMOVE 3

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char szAppName[] = "PoorMenu";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

HMENU hMenu;

HWND hwnd;

MSG msg;

WNDCLASSEX wndclass;

wndclass.cbSize = sizeof(wndclass);

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = szAppName;

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hwnd = CreateWindow(szAppName, "The Poor-Person's Menu",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

hMenu = GetSystemMenu(hwnd, FALSE);

AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);

AppendMenu(hMenu, MF_STRING, IDM_ABOUT, "About...");

AppendMenu(hMenu, MF_STRING, IDM_HELP, "Help...");

AppendMenu(hMenu, MF_STRING, IDM_REMOVE, "Remove Additions");

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

switch(iMsg)

{

case WM_SYSCOMMAND :

switch(LOWORD(wParam))

{

case IDM_ABOUT :

MessageBox(hwnd, "A Poor-Person's Menu Program.",

szAppName, MB_OK | MB_ICONINFORMATION);

return 0;

case IDM_HELP :

MessageBox(hwnd, "Help not yet implemented!",

szAppName, MB_OK | MB_ICONEXCLAMATION);

return 0;

case IDM_REMOVE :

GetSystemMenu(hwnd, TRUE);

return 0;

}

break;

case WM_DESTROY :

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}Fig. 10.4 Programul POORMENUCele trei numere de identificare ale meniurilor adugate sunt definite n partea de sus a fiierului POORMENU.C:fdefine IDM ABOUT 1 #define IDM~HELP 2 #define IDM^REMOVE 3Dup crearea ferestrei programului, POORMENU obine o variabil handle a meniului sistem: hMenu = GetSystemMenu (hwnd, FALSE) ;La prima apelare a funciei GetSystemMenu trebuie s dai celui de-al doilea parametru valoarea FALSE ca s pregtii modificarea meniului.Meniul este modificat prin patru apeluri ale funciei AppendMenu:AppendMenu (hMenu, MF SEPARATOR, 0, NULL) ;AppendMenu (hMenu, MF~STRING, IDM ABOUT, "About...") ; AppendMenu (hMenu, MF~STRING, IDMJELP, "Help...") ;AppendMenu (hMenu, MF~STRING, IDM REMOVE, "Remove Additions") ; * ~ ~Primul apel al funciei AppendMenu adaug o bar de separare. Selectarea opiuni Remove Additions determin eliminarea articolelor de meniu adugate, operaie efectuat prin apelarea funciei GetSystemMenu avnd al doilea parametru cu valoarea TRUE:GetSystemMenu (hwnd, TRUE) ;Meniul sistem standard conine opiunile Restore, Move, Size, Minimize, Maximize, Close i Switch To. Acestea genereaz mesaje WM_SYSCOMMAND n care parametrul wParam poate avea valorile SC_RESTORE, SC_MOVE, SC_SIZE, SC.MINIMIZE, SC_MAXIMIZE, SC_CLOSE i SC_TASKLIST. Dei, n general, programele Windows nu fac acest lucru, putei s prelucrai aceste mesaje, n loc s le transmitei procedurii DefWindowProc. De asemenea, putei s dezactivai sau s tergei unele dintre opiunile standard folosind metodele descrise mai jos. Documentaia Windows include i alte opiuni standard pe care putei s le adugai n meniul sistem. Aceste opiuni suplimentare folosesc identificatorii SC_NEXTWIN-DOW, SQPREVWINDOW, SC_VSCROLL, SC_HSCROLL i SC_ARRANGE. Este posibil ca n unele aplicaii s dorii s adugai i aceste comenzi la meniul sistem.Modificarea meniuluiAm vzut deja cum poate fi folosit funcia AppendMenu pentru definirea unui ntreg meniu direct ntr-un program i pentru adugarea unor articole la meniul sistem, nainte de apariia versiunii Windows 3.0, pentru aceste operaii trebuia s folosii funcia ChangeMenu. Funcia ChangeMenu, datorit flexibilitii ei, era una dintre cele mai complexe funcii Windows. In Windows 95 funcia ChangeMenu poate fi nc folosit, dar operaiile pe care le poate executa aceasta au fost mprite ntre alte cinci noi funcii: AppendMenu - adaug un nou articol la sfritul unui meniu.

DeleteMenu - terge un articol existent dintr-un meniu i distruge articolulrespectiv. InsertMenu - insereaz un nou articol ntr-un meniu. ModifyMenu - modific un articol de meniu existent. RemoveMenu - terge un articol existent dintr-un meniu.Diferena dintre funciile RemoveMenu i DeleteMenu este important dac articolul respectiv face parte dintr-un meniu derulant. DeleteMenu distruge meniul derulant, pe cnd RemoveMenu nu face acest lucru.Alte comenzi pentru meniuriExist alte cteva funcii care pot fi folosite pentru meniuri.Arunci cnd modificai un articol din meniul principal, modificarea fcut nu este vizibil pn cnd meniul nu este redesenat. Putei s forai redesenarea meniuluiastfel:DrawMenuBar (hwnd) ;Remarcai c parametrul fuwsei DrawMenuBar este variabila handie a ferestrei, nu a meniului.Putei s obinei variabila handie a unui meniu derulant astfel:

hMenuPopup - GetSubMenu (hMenu, iPosition) ;unde iPosition este indexul meniului derulant (ncepnd de la 0) n cadrul meniului principal indicat de parametrul hMenu. Putei apoi s folosii variabila handle obinut pentru apelarea altor funcii (cum ar fi AppendMenu).Putei s obinei numrul curent de articole dintr-un meniu derulant astfel:iCount = GetMenuItemCount (hMenu) ; Putei s obinei identificatorul unui articol dintr-un meniu derulant astfel:id - GetMenuItemID (hMenuPopup, iPosition) ;unde iPosition este poziia articolului n meniul derulant (ncepnd de la 0).n programul MENUDEMO ai vzut cum putei s marcai sau s demarcai un articol dintr-un meniu:CheckMenuItem (hMenu, id, iCheck) ;n programul MENUDEMO, hMenu era variabila handle a meniului principal, id era identificatorul meniului, iar iCheck avea una dintre valorile MF_CHECKED sau MF_UNCHECKED. Dac hMenu este variabila handle a unui meniu derulant, atunci id poate fi un index poziional n loc de un identificator de meniu. Dac folosirea indexului este mai convenabil, includei identificatorul MF_B\TOSITION n cel de-al treilea parametru. De exemplu:ChedkMenuItem (hMenu, iPosition, MF_CHECKED j MF_BYP0SITI0N) ;Funcia EnableMenuItem lucreaz ntr-un mod asemntor cu funcia CheckMenuItem, exceptnd faptul c cel de-al treilea parametru poate avea una dintre valorile MF_ENABLED, MF_DISABLED sau MF_GRAYED. Dac folosii funcia EnableMenuItem pentru un articol al meniului principal care apeleaz un meniu derulant, n cel de-al treilea parametru trebuie s includei identificatorul MF_BYPOSITION, deoarece articolul respectiv nu are un identificator de meniu. Vom vedea un exemplu de folosire a funciei EnableMenuItem n programul POPPAD prezentat mai trziu n acest capitol. Funcia HUiieMenuItem este asemntoare cu funciile EnableMenuItem i CheckMenuItem, dar folosete identificatorii MF_HILITE i MFJJNHILITE. Acest marcaj (highlighting) este modul de afiare n video invers pe care sistemul de operare Windows l folosete atunci cnd v deplasai de la un articol de meniu la altul. n mod normal nu avei nevoie s folosii funcia HUiieMenuItem.Ce altceva ai mai avea nevoie s facei cu un meniu? Ai uitat ce ir de caractere ai folosit ntr-un meniu? Putei s v mprosptai memoria cu urmtorul apel:iByteCount = GetMenuString (hMenu, id, pString, iMaxCount, iFlag) ;iFlag poate fi MF_BYCOMMAND (caz n care id este identificatorul meniului) sau MFJBYPOSITION (iar id este un index poziional). Funcia copiaz cel mult iMaxCount octei n pString i returneaz numrul de octei copiai.Sau poate c dorii s aflai care sunt indicatoarele flag stabilite pentru un articol de meniu:iFlags = GetMenuState (hMenu, id, iFlag) ;Din nou, iFlag poate fi MF_BYCOMMAND sau MF_BYPOSITION. Valoarea iFlags returnat este o combinaie a tuturor indicatoarelor flag curente. Putei s stabilii care sunt acestea comparnd aceast valoare cu identificatorii MF_DISABLED,MF.GRAYED, MF_CHECKED, MF_MENUBREAK, MF_MENUBARBREAK i MF_SEPARATOR.Probabil c v-ai plictisit de meniuri. n acest caz, v vei bucura s aflai c putei scpa de un meniu de care nu mai avei nevoie cu ajutorul funciei DestroyMenu:DestroyMenu (hMenu) ; Apelul de mai sus invalideaz variabila handle a meniului.0 abordare mai neortodox" a meniurilorHaidei s ne abatem puin de la crarea cunoscut. Ce spunei dac, n loc s folosii n program meniuri derulante, creai mai multe meniuri de nivel nalt i trecei de la un meniu la altul apelnd funcia SetMenu? Programul NOPOPUPS, prezentat n Figura 10-5, v arat cum putei s facei acest lucru. Programul conine articolele File i Edit asemntoare cu cele din programul MENUDEMO, dar le afieaz ca meniuri de nivel nalt alternative.

NOPOPUPS.MAK

#------------------------

# Fiierul de construcie NOPOPUPS.MAK

#------------------------

nopopups.exe : nopopups.obj nopopups.res

$(LINKER) $(GUIFLAGS) -OUT:nopopups.exe nopopups.obj \

nopopups.res $(GUILIBS)

nopopups.obj : nopopups.c nopopups.h

$(CC) $(CFLAGS) nopopups.c

nopopups.res : nopopups.rc nopopups.h

$(RC) $(RCVARS) nopopups.rc

332

NOPOPUPS.C

/*-------------------------------------------------

NOPOPUPS.C Program demonstrative pentru utilizarea meniurilor imbricate, nederulate

(c) Charles Petzold, 1996

-------------------------------------------------*/

#include

#include "nopopups.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

static char szAppName[] = "NoPopUps";

HWND hwnd;

MSG msg;

WNDCLASSEX wndclass;

wndclass.cbSize = sizeof(wndclass);

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = szAppName;

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hwnd = CreateWindow(szAppName, "No-Popup Nested Menu Demonstration",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static HMENU hMenuMain, hMenuEdit, hMenuFile;

HINSTANCE hInstance;

switch(iMsg)

{

case WM_CREATE :

hInstance =(HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE);

hMenuMain = LoadMenu(hInstance, "MenuMain");

hMenuFile = LoadMenu(hInstance, "MenuFile");

hMenuEdit = LoadMenu(hInstance, "MenuEdit");

SetMenu(hwnd, hMenuMain);

return 0;

case WM_COMMAND :

switch(LOWORD(wParam))

{

case IDM_MAIN :

SetMenu(hwnd, hMenuMain);

return 0;

case IDM_FILE :

SetMenu(hwnd, hMenuFile);

return 0;

case IDM_EDIT :

SetMenu(hwnd, hMenuEdit);

return 0;

case IDM_NEW :

case IDM_OPEN :

case IDM_SAVE :

case IDM_SAVEAS :

case IDM_UNDO :

case IDM_CUT :

case IDM_COPY :

case IDM_PASTE :

case IDM_DEL :

MessageBeep(0);

return 0;

}

break;

case WM_DESTROY :

SetMenu(hwnd, hMenuMain);

DestroyMenu(hMenuFile);

DestroyMenu(hMenuEdit);

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

NOPOPUPS.RC

/*-----------------------------

NOPOPUPS.RC fiierul script de resurse-----------------------------*/

#include "nopopups.h"

MenuMain MENU

{

MENUITEM "MAIN:", 0, INACTIVE

MENUITEM "&File...", IDM_FILE

MENUITEM "&Edit...", IDM_EDIT

}

MenuFile MENU

{

MENUITEM "FILE:", 0, INACTIVE

MENUITEM "&New", IDM_NEW

MENUITEM "&Open...", IDM_OPEN

MENUITEM "&Save", IDM_SAVE

MENUITEM "Save &As...", IDM_SAVEAS

MENUITEM "(&Main)", IDM_MAIN

}

MenuEdit MENU

{

MENUITEM "EDIT:", 0, INACTIVE

MENUITEM "&Undo", IDM_UNDO

MENUITEM "Cu&t", IDM_CUT

MENUITEM "&Copy", IDM_COPY

MENUITEM "&Paste", IDM_PASTE

MENUITEM "De&lete", IDM_DEL

MENUITEM "(&Main)", IDM_MAIN

}

NOPOPUPS.H

/*------------------------

NOPOPUPS.H fiier antet

------------------------*/

#define IDM_NEW 1

#define IDM_OPEN 2

#define IDM_SAVE 3

#define IDM_SAVEAS 4

#define IDM_UNDO 5

#define IDM_CUT 6

#define IDM_COPY 7

#define IDM_PASTE 8

#define IDM_DEL 9

#define IDM_MAIN 10

#define IDM_EDIT 11

#define IDM_FILE 12

Fig. 10.5 Programul NOPOPUPS

Fiierul script de resurse conine trei meniuri. n timpul prelucrrii mesajului

WM_CREATE, Windows ncarc n memorie resursele celor trei meniuri: hMenuMain = LoadMenu(hInstance, "MenuMain");

hMenuFile = LoadMenu(hInstance, "MenuFile");

hMenuEdit = LoadMenu(hInstance, "MenuEdit");

Iniial, programul afieaz meniul principal:

SetHenu (hwnd, hMenuMain) ;Meniul principal conine trei opiuni, identificate prin irurile de caractere MAIN:", File..." i Edit...". Opiunea MAIN:" este ns dezactivat, aa c nu trimite mesaje WM_COMMAND ctre procedura ferestrei. Meniurile File i Edit sunt identificate prin irurile de caractere FILE:" i EDIT:". Ultima opiune din meniurile File i Edit este (Main)"; aceast opiune permite ntoarcerea la meniul principal. Trecerea de la un meniu la altul este simpl:case WM COMMAND :switch (LOWORD (wParam)) { case IDH_MAIN :SetMenu (hwnd, hMenuMain) ; return 0 ;case IOM FILE :SetMenu (hwnd, hMenuFile) ; return 0 ;case IDM EDIT :SetMenu (hwnd, hMenuEdit) ; return 0 ;[alte linii ale programului] } break ;n timpul prelucrrii mesajului WM_DESTROY, programul NOPOPUPS stabilete ca meniu al programului meniul principal (Main) i distruge meniurile File i Edit apelnd funcia DestroyMenu. Meniul principal este distrus automat odat cu fereastra.FOLOSIREA IMAGINILOR BITMAP N MENIURIirurile de caractere nu sunt singura cale de afiare a unui articol de meniu. Pentru acelai lucru putei s folosii i imagini bitmap, cu condiia s v convin ideea de a folosi imagini de dosare, fiiere i couri de gunoi" n meniuri. Totui, gndii-v ct de utile ar putea fi imaginile bitmap din meniuri pentru un program de desenare. Gndii-v la ideea folosirii mai multor fonturi i dimensiuni de fonturi, dimensiuni de linii, modele de hauri i culori, n meniurile programului.Programul pe care urmeaz s l studiem se numete GRAFMENU (meniu grafic"). Meniul principal al programului este prezentat n Figura 10-6. Literele mrite sunt stocate n fiiere ca imagini bitmap monocrome, cu dimensiunea 40x16 pixeli. Imaginile au fost create n editorul de imagini Developer Studio i au fost salvate ca fiiere .BMP; n locul acestora ar putea fi folosite orice imagini. Articolul Font din meniu apeleaz un meniu derulant care conine trei opiuni: Courier New, Arial si Times New Roman. Acestea sunt fonturile TrueType standard n Windows i numele fiecruia este afiat cu fontul respectiv (Figura 10-7). Aceste imagini au fost create n program printr-o tehnic ce implic folosirea unui context de dispozitiv de memorie.

Partea a iii-a Folosirea resurselor

||r|Bitn.pMl... !Figura 10-6. Meniul principal al programului GRAFMENU.

Figura 10-7. Meniul derulant FONT al programului GRAFMENU.n sfrit, dac derulai meniul sistem, vei vedea c avei acces la unele informaii de asisten soft (help), opiunea Help fiind o imagine a disperrii unui utilizator nou (Figura 10-8). Aceast imagine bitmap monocrom de 64x64 pixeli a fost creat n editorul de imagini Developer Studio.

Figura 10-8. Meniul sistem al programului GRAFMENU.Programul GRAFMENU, inclusiv cele patru imagini bitmap create n editorul de imagini, sunt prezentate n Figura 10-9.GRAFMENU.MAK

#------------------------

# Fiier de construcie GRAFMENU.MAK

#------------------------

grafmenu.exe : grafmenu.obj grafmenu.res

$(LINKER) $(GUIFLAGS) -OUT:grafmenu.exe \

grafmenu.obj grafmenu.res $(GUILIBS)

grafmenu.obj : grafmenu.c grafmenu.h

$(CC) $(CFLAGS) grafmenu.c

grafmenu.res : grafmenu.rc grafmenu.h \

editlabl.bmp filelabl.bmp fontlabl.bmp bighelp.bmp

$(RC) $(RCVARS) grafmenu.rc

GRAFMENU.C

/*----------------------------------------------

GRAFMENU.C Program ilustrativ pentru articole de meniu

(c) Charles Petzold, 1996

----------------------------------------------*/

#include

#include

#include "grafmenu.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

HBITMAP StretchBitmap(HBITMAP);

HBITMAP GetBitmapFont(int);

char szAppName[] = "GrafMenu";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

HBITMAP hBitmapHelp, hBitmapFile, hBitmapEdit,

hBitmapFont, hBitmapPopFont[3];

HMENU hMenu, hMenuPopup;

HWND hwnd;

int i;

MSG msg;

WNDCLASSEX wndclass;

wndclass.cbSize = sizeof(wndclass);

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = szAppName;

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hMenu = CreateMenu();

hMenuPopup = LoadMenu(hInstance, "MenuFile");

hBitmapFile = StretchBitmap(LoadBitmap(hInstance, "BitmapFile"));

AppendMenu(hMenu, MF_BITMAP | MF_POPUP,(int) hMenuPopup,

(PSTR)(LONG) hBitmapFile);

hMenuPopup = LoadMenu(hInstance, "MenuEdit");

hBitmapEdit = StretchBitmap(LoadBitmap(hInstance, "BitmapEdit"));

AppendMenu(hMenu, MF_BITMAP | MF_POPUP,(int) hMenuPopup,

(PSTR)(LONG) hBitmapEdit);

hMenuPopup = CreateMenu();

for(i = 0; i < 3; i++)

{

hBitmapPopFont[i] = GetBitmapFont(i);

AppendMenu(hMenuPopup, MF_BITMAP, IDM_COUR + i,

(PSTR)(LONG) hBitmapPopFont[i]);

}

hBitmapFont = StretchBitmap(LoadBitmap(hInstance, "BitmapFont"));

AppendMenu(hMenu, MF_BITMAP | MF_POPUP,(int) hMenuPopup,

(PSTR)(LONG) hBitmapFont);

hwnd = CreateWindow(szAppName, "Bitmap Menu Demonstration",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, hMenu, hInstance, NULL);

hMenu = GetSystemMenu(hwnd, FALSE);

hBitmapHelp = StretchBitmap(LoadBitmap(hInstance, "BitmapHelp"));

AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);

AppendMenu(hMenu, MF_BITMAP, IDM_HELP,(PSTR)(LONG) hBitmapHelp);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

DeleteObject(hBitmapHelp);

DeleteObject(hBitmapEdit);

DeleteObject(hBitmapFile);

DeleteObject(hBitmapFont);

for(i = 0; i < 3; i++)

DeleteObject(hBitmapPopFont[i]);

return msg.wParam;

}

HBITMAP StretchBitmap(HBITMAP hBitmap1)

{

BITMAP bm1, bm2;

HBITMAP hBitmap2;

HDC hdc, hdcMem1, hdcMem2;

TEXTMETRIC tm;

hdc = CreateIC("DISPLAY", NULL, NULL, NULL);

GetTextMetrics(hdc, &tm);

hdcMem1 = CreateCompatibleDC(hdc);

hdcMem2 = CreateCompatibleDC(hdc);

DeleteDC(hdc);

GetObject(hBitmap1, sizeof(BITMAP),(PSTR) &bm1);

bm2 = bm1;

bm2.bmWidth =(tm.tmAveCharWidth * bm2.bmWidth) / 4;

bm2.bmHeight =(tm.tmHeight * bm2.bmHeight) / 8;

bm2.bmWidthBytes =((bm2.bmWidth + 15) / 16) * 2;

hBitmap2 = CreateBitmapIndirect(&bm2);

SelectObject(hdcMem1, hBitmap1);

SelectObject(hdcMem2, hBitmap2);

StretchBlt(hdcMem2, 0, 0, bm2.bmWidth, bm2.bmHeight,

hdcMem1, 0, 0, bm1.bmWidth, bm1.bmHeight, SRCCOPY);

DeleteDC(hdcMem1);

DeleteDC(hdcMem2);

DeleteObject(hBitmap1);

return hBitmap2;

}

HBITMAP GetBitmapFont(int i)

{

static char *szFaceName[3] = { "Courier New", "Arial",

"Times New Roman" };

static LOGFONT lf;

HBITMAP hBitmap;

HDC hdc, hdcMem;

HFONT hFont;

SIZE size;

TEXTMETRIC tm;

hdc = CreateIC("DISPLAY", NULL, NULL, NULL);

GetTextMetrics(hdc, &tm);

lf.lfHeight = 2 * tm.tmHeight;

strcpy((char *) lf.lfFaceName, szFaceName[i]);

hdcMem = CreateCompatibleDC(hdc);

hFont =(HFONT) SelectObject(hdcMem, CreateFontIndirect(&lf));

GetTextExtentPoint(hdcMem, szFaceName[i], strlen(szFaceName[i]), &size);

hBitmap = CreateBitmap(size.cx, size.cy, 1, 1, NULL);

SelectObject(hdcMem, hBitmap);

TextOut(hdcMem, 0, 0, szFaceName[i], strlen(szFaceName[i]));

DeleteObject(SelectObject(hdcMem, hFont));

DeleteDC(hdcMem);

DeleteDC(hdc);

return hBitmap;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

HMENU hMenu;

static int iCurrentFont = IDM_COUR;

switch(iMsg)

{

case WM_CREATE :

CheckMenuItem(GetMenu(hwnd), iCurrentFont, MF_CHECKED);

return 0;

case WM_SYSCOMMAND :

switch(LOWORD(wParam))

{

case IDM_HELP :

MessageBox(hwnd, "Help not yet implemented!",

szAppName, MB_OK | MB_ICONEXCLAMATION);

return 0;

}

break;

case WM_COMMAND :

switch(LOWORD(wParam))

{

case IDM_NEW :

case IDM_OPEN :

case IDM_SAVE :

case IDM_SAVEAS :

case IDM_UNDO :

case IDM_CUT :

case IDM_COPY :

case IDM_PASTE :

case IDM_DEL :

MessageBeep(0);

return 0;

case IDM_COUR :

case IDM_ARIAL :

case IDM_TIMES :

hMenu = GetMenu(hwnd);

CheckMenuItem(hMenu, iCurrentFont, MF_UNCHECKED);

iCurrentFont = LOWORD(wParam);

CheckMenuItem(hMenu, iCurrentFont, MF_CHECKED);

return 0;

}

break;

case WM_DESTROY :

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

GRAFMENU.RC

/*-----------------------------

GRAFMENU.RC fiier script de resurse

-----------------------------*/

#include "grafmenu.h"

BitmapEdit BITMAP editlabl.bmp

BitmapFile BITMAP filelabl.bmp

BitmapFont BITMAP fontlabl.bmp

BitmapHelp BITMAP bighelp.bmp

MenuFile MENU

{

MENUITEM "&New", IDM_NEW

MENUITEM "&Open...", IDM_OPEN

MENUITEM "&Save", IDM_SAVE

MENUITEM "Save &As...", IDM_SAVEAS

}

MenuEdit MENU

{

MENUITEM "&Undo", IDM_UNDO

MENUITEM SEPARATOR

MENUITEM "Cu&t", IDM_CUT

MENUITEM "&Copy", IDM_COPY

MENUITEM "&Paste", IDM_PASTE

MENUITEM "De&lete", IDM_DEL

}

GRAFMENU.H

/*------------------------

GRAFMENU.H fiier antet

------------------------*/

#define IDM_NEW 1

#define IDM_OPEN 2

#define IDM_SAVE 3

#define IDM_SAVEAS 4

#define IDM_UNDO 5

#define IDM_CUT 6

#define IDM_COPY 7

#define IDM_PASTE 8

#define IDM_DEL 9

#define IDM_COUR 10

#define IDM_ARIAL 11

#define IDM_TIMES 12

#define IDM_HELP 13

Fig. 10.9 Programul GRAFMENU

EDITLABL.BMP

FILELABL.BMP

FONTLABL.BMP

BIGHELP.BMP

Dou metode de creare a imaginilor bitmap pentru meniuriPentru inserarea unei imagini bitmap ntr-un meniu folosii funciile AppendMenu si InsertMenu. Dar de unde provine imaginea bitmap? Exist dou posibile surse. In primul rnd, putei s creai o imagine bitmap folosind editorul de imagini Developer Studio i incluznd apoi fiierul bitmap n fiierul script de resurse. n program, putei s folosii funcia LoadBitmap ca s ncrcai resursa imaginii n memorie i apoi s folosii funciile AppendMenu i InsertMenu ca s o ataai la meniu. Totui, acest mod de abordare prezint o problem. Imaginea bitmap creat poate s nu fie potrivit pentru toate tipurile de rezoluie video i rate de afiare - va fi nevoie s restrngei imaginea bitmap creat, n funcie de acestea. O a doua metod este s creai imaginea bitmap direct n program i apoi s o ataai la meniu.Ambele metode par mai dificile dect sunt n realitate. De fapt, nu trebuie s lucrai direct cu biii. Sistemul de operare Windows pune la dispoziie o serie de funcii care ne permit s manipulm cu uurin imaginile bitmap folosind contextul de dispozitiv n memorie.Contextul de dispozitiv n memorieAtunci cnd folosii apelurile GDI (cum ar fi TextOut) ca s scriei n zona client a ferestrei, scriei de fapt ntr-o zon de memorie (memoria video), care este organizat foarte asemntor cu o imagine bitmap uria. Limea i nlimea acestei imagini j sunt egale cu rezoluia ecranului. Modul n care mai muli bii definesc culoarea! fiecrui pixel este determinat de placa video. De fapt, Windows ar putea s considere c un bloc din memoria obinuit este memoria video, i ar putea s scrie n acest bloc j de memorie la fel cum scrie pe ecran. n acest caz am putea folosi acest bloc de memorie ca pe o imagine bitmap.Exact acest lucru nseamn un context de dispozitiv de memorie. Acesta ne ajutai s desenm i s manipulm imagini bitmap ntr-un program Windows. Iat etapele care trebuie parcurse:1. Creai un context de dispozitiv n memorie folosind funcia CreateCompatibleDC,Iniial, suprafaa de afiare a contextului de dispozitiv conine un singur pimonocrom. Putei s v gndii la acest context de dispozitiv ca avnd un pilime, un pixel nlime i dou culori (alb i negru).2. Creai o imagine neiniializat folosind funciile CreateBitmap, CreateBitmapIndirecsau CreateCompatbleBitmap. La crearea imaginii bitmap specificai nlimea, limea i organizarea culorilor, chiar dac pixelii imaginii nu reprezint nc nimicSalvai variabila handle a imaginii bitmap.3. Selectai imaginea bitmap n contextul de dispozitiv n memorie cu ajutorul funciei SelectObject. Acum contextul de dispozitiv are o suprafa de afiare de dimeiB siunea imaginii bitmap i cu acelai numr de culori.4.Folosii funciile GDI ca s desenai n contextul de dispozitiv n memorie ca i cuiai desena ntr-un context de dispozitiv obinuit. Tot ceea ce desenai pe suprafaide afiare a contextului de dispozitiv n memorie se deseneaz de fapt n imaginebitmap selectat n contextul de dispozitiv.Dou metode de creare a imaginilor bitmap pentru meniuriPentru inserarea unei imagini bitmap ntr-un meniu folosii funciile AppendMenu si InsertMenu. Dar de unde provine imaginea bitmap? Exist dou posibile surse. In primul rnd, putei s creai o imagine bitmap folosind editorul de imagini Developer Studio i incluznd apoi fiierul bitmap n fiierul script de resurse. n program, putei s folosii funcia LoadBitmap ca s ncrcai resursa imaginii n memorie i apoi s folosii funciile AppendMenu i InsertMenu ca s o ataai la meniu. Totui, acest mod de abordare prezint o problem. Imaginea bitmap creat poate s nu fie potrivit pentru toate tipurile de rezoluie video i rate de afiare - va fi nevoie s restrngei imaginea bitmap creat, n funcie de acestea. O a doua metod este s creai imaginea bitmap direct n program i apoi s o ataai la meniu.Ambele metode par mai dificile dect sunt n realitate. De fapt, nu trebuie s lucrai direct cu biii. Sistemul de operare Windows pune la dispoziie o serie de funcii care ne permit s manipulm cu uurin imaginile bitmap folosind contextul de dispozitiv n memorie.Contextul de dispozitiv n memorieAtunci cnd folosii apelurile GDI (cum ar fi TextOut) ca s scriei n zona client a ferestrei, scriei de fapt ntr-o zon de memorie (memoria video), care este organizat foarte asemntor cu o imagine bitmap uria. Limea i nlimea acestei imagini j sunt egale cu rezoluia ecranului. Modul n care mai muli bii definesc culoarea! fiecrui pixel este determinat de placa video. De fapt, Windows ar putea s considere c un bloc din memoria obinuit este memoria video, i ar putea s scrie n acest bloc j de memorie la fel cum scrie pe ecran. n acest caz am putea folosi acest bloc de memorie ca pe o imagine bitmap.Exact acest lucru nseamn un context de dispozitiv de memorie. Acesta ne ajutai s desenm i s manipulm imagini bitmap ntr-un program Windows. Iat etapele care trebuie parcurse:1. Creai un context de dispozitiv n memorie folosind funcia CreateCompatibleDC,Iniial, suprafaa de afiare a contextului de dispozitiv conine un singur pimonocrom. Putei s v gndii la acest context de dispozitiv ca avnd un pilime, un pixel nlime i dou culori (alb i negru).2. Creai o imagine neiniializat folosind funciile CreateBitmap, CreateBitmapIndirecsau CreateCompatbleBitmap. La crearea imaginii bitmap specificai nlimea, limea i organizarea culorilor, chiar dac pixelii imaginii nu reprezint nc nimicSalvai variabila handle a imaginii bitmap.3. Selectai imaginea bitmap n contextul de dispozitiv n memorie cu ajutorul funciei SelectObject. Acum contextul de dispozitiv are o suprafa de afiare de dimeiB siunea imaginii bitmap i cu acelai numr de culori.4.Folosii funciile GDI ca s desenai n contextul de dispozitiv n memorie ca i cuiai desena ntr-un context de dispozitiv obinuit. Tot ceea ce desenai pe suprafaide afiare a contextului de dispozitiv n memorie se deseneaz de fapt n imaginebitmap selectat n contextul de dispozitiv.5. tergei contextul de dispozitiv n memorie. Ai rmas cu o variabil handle a unei imagini bitmap care conine o reprezentare n pixeli a ceea ce ai desenat n contextul de dispozitiv n memorie.Crearea unei imagini bitmap cu textFuncia GetBitmapFont din programul GRAFMENU primete parametrii 0,1 sau 2 i returneaz o variabil handle a imaginii bitmap. Imaginea bitmap conine irurile de caractere Courier New", Arial" sau Times New Roman" scrise cu fontul corespunztor i aproximativ de dou ori mai mari dect fontul sistem normal. S vedem cum face funcia GetBitmapFont acest lucru. (Codul care urmeaz nu este identic cu cel din fiierul GRAFMENU.C. Pentru mai mult claritate am nlocuit referirile la variabila szFaceName cu valorile corespunztoare fontului Arial.)Mai nti trebuie s determinm dimensiunea fontului sistem folosind structura TEXTMETRIC:hdc - CreatelC ("DISPLAY", NULL, NULL, NULL) ; GetTextMetrics (hdc, &tm) ;Unele cmpuri din structura TEXTMETRIC trebuie s fie modificate pentru a descrie un font Arial mai mare ntr-o structur logic a fontului:lf.lfHeight = 2 * tm.tmHeight ;strepy ((char *) lf.lfFaceName, "Arial") ;Urmtorul pas este s obinem un context de dispozitiv pentru ecran i s crem un context de dispozitiv n memorie compatibil cu ecranul:hdcMem CreateCompatibleDC (hdc) ;Variabila handle a contextului de dispozitiv n memorie este hdcMem. n continuare, crem un font pe baza structurii modificate //i selectm fontul respectiv n contextul de dispozitiv n memorie:hFont = (HFONT) SelectObject (hdcMem, CreateFontlndirect (&lf)) ;Din acest moment, dac scriem un text n contextul de dispozitiv n memorie, Windows va folosi fontul TrueType Arial, selectat n contextul de dispozitiv.Dar contextul de dispozitiv nu are dect o suprafa de afiare monocrom de un pixel. Trebuie s crem o imagine bitmap destul de mare pentru afiarea textului dorit. Putei s obinei dimensiunile textului cu ajutorul funciei GetTextExtentPoint i s creai o imagine bitmap pe baza acestor dimensiuni folosind funcia CreateBitmap:GetTextExtentPoint (hdcMem, "Arial", 5, &size) ; hBitmap = CreateBitmap (size.cx, size.cy, 1, 1, NULL) ; SelectObject (hdcMem, hBitmap) ;Contextul de dispozitiv are acum o suprafa de afiare de dimensiunile textului. Tot ce mai trebuie s facem este s scriem textul. Ai mai vzut aceast funcie:TextOut (hdcMem, 0, 0, "Arial", 5) ;Mai avem de fcut doar operaiile de curenie. Pentru aceasta, selectm din nou fontul sistem (cu variabila handle hFont) n contextul de dispozitiv folosind funciaSelectObject i tergem variabila handle a fontului returnat anterior de funcia Se-lectObject, respectiv variabila handle a fontului Arial:DeleteObject {SelectObject (hdcMem, hFont)) ;Acum putem s tergem i cele dou contexte de dispozitiv:DeleteOC (hdcMem) ; DeleteDC (hdc) ;Am rmas cu o imagine bitmap care conine textul Arial" scris cu fontul Arial.Scalarea imaginilor bitmapContextele de dispozitiv n memorie ne vin n ajutor i atunci cnd trebuie s scalm fonturile pentru diferite rezoluii i rate de afiare (aspect ratio). Cele patru imagini bitmap folosite de programul GRAFMENU au fost create astfel nct s aib dimensiunile corecte pentru un ecran pentru care fontul sistem are nlimea de 8 pixeli i limea de patru pixeli. Pentru alte dimensiuni ale fontului sistem, imaginile bitmap trebuie s fie micorate. n programul GRAFMENU, aceast operaie este executat de funcia StretchBitmap.Mai nti trebuie s obinem contextul de dispozitiv al ecranului, dimensiunile fontului sistem, i apoi s crem dou contexte de dispozitiv n memorie:hdc CreatelC ("DISPLAY", NULL, NULL, NULL) ; GetTextMetrics (hdc, &tm) ; hdcMeml CreateCompatibleDC (hdc) ; hdcMem2 - CreateCompatibleDC (hdc) ; DeleteDC (hdc) ;Variabila handle a imaginii bitmap transmis funciei este hBitmapl. Programul poate obine dimensiunile acestei imagini cu ajutorul funciei GetObject:GetObject (hBitmapl, sizeof (BITMAP), (PSTR) &bml) ;Apelul de mai sus copiaz dimensiunile n structura bml, de tip BITMAP. Structura bml primete aceleai valori ca i bml, apoi unele cmpuri sunt modificate pe baza dimensiunilor fontului sistem:bm2 = bml ;bm2.bmWidth=(tm.tmAveCharWidth * bm2.bmWidth) / 4 ;bm2.bmHeight-(tm.tmHeight * bm2.bmHeight) / 8 ;bm2.bmWidthBytes=((bm2.bmWidth + 15) / 16) * 2 ;Apoi poate fi creat o nou imagine bitmap cu variabila handle hBiimapl, pe baza dimensiunilor modificate:hBitmap2 = CreateBitmapIndirect (&bm2) ;Putei apoi s selectai cele dou imagini bitmap n contextele de dispozitiv create: SelectObject (hdcMeml, hBitmapl) ; SelectObject (hdcMem2, hBitmap2) ;Dorim s copiem prima imagine bitmap n cea de-a doua i s o micorm n timpul acestei operaii. Pentru aceasta folosim funcia StretchBH:StretchBlt (hdcMem2, O, O, bm2.bmWidth, bm2.bmHeight,hdcMeml, O, O, bml.bmWidth, bml.bmHeight, SRCCOPY) ;Acum, cea de-a doua imagine bitmap este scalat corespunztor i putem s o folosim n meniu. Operaiile de curenie sunt simple:DeleteDC (hdcMeml) ; DeleteDC (hdcMem2) ; DeleteObject (hBitmapl) ;Compunerea meniuluiFuncia WinMain din programul GRAFMENU folosete funciile StretchBitmap i GetBitmapFont n timpul construirii meniului. GRAFMENU are deja dou meniuri definite n fiierul script de resurse. Acestea vor fi folosite ca meniuri derulante pentru opiunile File i Edit.Programul GRAFMENU obine mai nti o variabil handle a unui meniu gol:hMenu CreateMenu {) ;Meniul derulant pentru opiunea File (coninnd articolele New, Open, Save i Save As) este ncrcat din fiierul script de resurse:hMenuPopup = LoadMenu (hlnstance, "MenuFile") ;Imaginea bitmap care conine cuvntul FILE" este ncrcat tot din fiierul script de resurse i adus la dimensiunile corespunztoare cu ajutorul funciei StretchBitmap:hBitmapFile StretchBitmap (LoadBitmap (hlnstance, "BitmapFile")) ;Variabilele handle ale imaginii bitmap i meniului derulant sunt folosite ca parametri pentru apelarea funciei AppendMenu:AppendMenu (hMenu, MF_BITMAP \ MF POPUP, (int) hMenuPopup, (PSTR) (LONG) hBitmapFile) ;Aceeai procedur este urmat i pentru meniul Edit:hMenuPopup LoadMenu (hlnstance, "MenuEdit") ; hBitmapEdit = StretchBitmap (LoadBitmap (hlnstance, "BitmapEdit")) ; AppendMenu (hMenu, MF BITMAP 1 MF_POPUP, (int) hMenuPopup, (PSTR) (LONG) hBitmapEdit) ;Meniul derulant pentru cele trei fonturi este construit prin apelarea funciei GetBitmapFont:hMenuPopup for (i = 0 CreateMenu () i < 3 ; 7++){hBitmapPopFont[i] = GetBitmapFont (i) ; AppendMenu (hMenuPopup, MFJITMAP, IDM_C0UR + i, (PSTR) (LONG) hMenuPopupFont[i]) ;Apoi meniul derulant creat este ataat la meniul principal:hBitmapFont = StretchBitmap (LoadBitmap (hlnstance, "BitmapFont")) AppendMenu (hMenu, MF_BITMAP | MF_POPUP, (int) hMenuPopup, (PSTR) (LONG) hBitmapFont) ;Acum meniul ferestrei este complet. Putei include variabila handle hMenu n apelul funciei CreateWvndow:hwnd = CreateWindow (szAppName, "Bitmap Menu Demonstraion", WS_OVERLAPPEDWINDOW, CWJJSEDEFAULT, CW_USEDEFAULT, CWJJSEDEFAULT, CWJSEDEFAULT, NULL, hMenu, hlnstance, NULL) ;Dup obinerea variabilei hwnd, programul GRAFMENU poate modifica meniul sistem. Pentru aceasta este nevoie de o variabil handle a meniului sistem:hMenu = GetSystemMenu {hwnd, FALSE);Instruciunea urmtoare ncarc imaginea bitmap Help" i o aduce la dimensiunile corespunztoare:hBitmapHelp = StretchBitmap (LoadBitmap {hlnstance, "BitmapHelp")) ;Instruciunile urmtoare adaug o bar de separare i imaginea bitmap redimen-sionat:AppendMenu (hMenu, MF_SEPARATOR, NULL, NULL) ;AppendMenu (hMenu, MF_BITMAP, IDM_HELP, (PSTR) (LONG) hBitmapHelp) ;Nu uitai c imaginile bitmap sunt obiecte GDI i trebuie s fie explicit terse nainte de nchiderea programului. Operaiile de tergere sunt executate dup ce GRAFMENU iese din bucla de prelucrare a mesajelor:DeleteObject(hBitmapHelp);DeleteObject(hBitmapEdit);DeleteObject(hBitmapFile);DeleteObject(hBitmapFont);for (i = 0 ; i < 3DeleteObject (hBitmapPopFont[i]) ;Vom ncheia aceast seciune cu cteva note suplimentare:n meniurile de pe primul nivel, Windows ajusteaz nlimea barei demeniu astfel nct s ncap cea mai nalt imagine bitmap. Celelalte imagini(sau iruri de caractere) sunt aliniate la partea de sus a barei de meniu.Dimensiunea barei de meniu obinut cu instruciuneaGetSystemMetrics (SM_CYMENU) ; nu mai este valabil dac includei imagini bitmap n bara de meniu.Dup cum putei s v dai seama dac v jucai puin cu programulGRAFMENU, putei s folosii marcaj de validare pentru articolele demeniu afiate prin imagini bitmap, dar marcajele au dimensiuni normale.* Dac acest lucru v deranjeaz, putei s creai un marcaj de validare propriu i s l folosii cu ajutorul funciei SetMenuItemBitmaps.O alt metod de folosire a articolelor de meniu non-text (sau a textelorscrise cu alte fonturi dect fontul sistem) este s folosii meniuri desenatede utilizator".Adugarea unei interfee cu tastaturaAcum avem o alt problem. Atunci cnd un articol de meniu conine text, Windows i adaug automat o interfa cu tastatura. Putei s selectai un articol de meniu folosind tasta Alt n combinaie cu o liter din irul de caractere. Dac includei n meniu o imagine bitmap, eliminai interfaa cu tastatura. Chiar dac imaginea bitmap conine un text, Windows nu tie acest lucru.Acum devine util mesajul WM_MENUCHAR. Windows trimite mesajul WM_MENUCHAR ctre procedura ferestrei atunci cnd utilizatorul apas tasta Alt n combinaie cu un caracter care nu corespunde unui articol de meniu. Trebuie s interceptai mesajele WM_MENUCHAR i s verificai cuvntul mai puin semnificativ al parametrului wParam (codul ASCII al tastei apsate). Dac acest caracter corespunde unui articol de meniu returnai sistemului de operare un numr care s fie ntreg lung i n care cuvntul mai semnificativ are valoarea 2, iar cuvntul mai puin semnificativ conine indexul articolului de meniu pe care vrei s l asociai tastei apsate. Windows va face restul.Taste de accelerareDescrise foarte simplu, tastele de accelerare sunt combinaii de taste care genereaz mesaje WM_COMMAND (sau WM_SYSCOMMAND). De cele mai multe ori, programele folosesc tastele de accelerare pentru duplicarea aciunilor unor opiuni de meniu folosite mai des. (Tastele de accelerare pot declana ns i executarea unor aciuni care nu sunt funcii de meniu.) De exemplu, unele programe Windows au meniuri Edit n care este inclus opiunea Delete; n mod convenional, aceste programe stabilesc tasta Del ca accelerator pentru aceast opiune. Utilizatorul poate s selecteze opiunea Delete din meniu apsnd o combinaie Alt+tast sau poate s apese direct tasta Del. Atunci cnd procedura ferestrei recepioneaz mesajul WM_COMMAND, nu trebuie s determine dac a fost folosit meniul sau tasta de accelerare.De ce avei nevoie de taste de accelerareS-ar putea s v ntrebai: de ce trebuie s folosesc taste de accelerare? Nu a putea s interceptez mesajele WM_KEYDOWN sau WM_CHAR i s dublez chiar eu funciile de meniu? Care este avantajul? n cazul aplicaiilor cu fereastr unic este destul de simplu s interceptai mesajele de la tastatur, dar folosirea tastelor de accelerare v ofer totui un avantaj: nu este nevoie s duplicai logica de interpretare a mesajelor de la meniu i tastatur.n cazul aplicaiilor cu ferestre i proceduri de fereastr multiple, tastele de accelerare devin foarte importante. Aa cum am vzut, Windows trimite mesajele de la tastatur procedurii corespunztoare ferestrei care deine cursorul de intrare. Totui, mesajele WM_COMMAND generate de tastele de accelerare sunt trimise procedurii de fereastr a crei variabil handle este specificat n funcia Windows Translate Accelerator. n general, aceasta este fereastra principal, adic fereastra creia i aparine i meniul, ceea ce nseamn c logica de tratare a tastelor de accelerare nu trebuie s fie coninut n fiecare procedur de fereastr.Acest avantaj devine i mai important dac folosii casete de dialog nemodale (despre care vom discuta n capitolul urmtor) sau ferestre descendent, n zona client a ferestrei principale. Dac definii o tast de accelerare pentru deplasarea ntre ferestre, atunci o singur procedur de fereastr trebuie s includ logica de tratare a acesteia. Ferestrele descendent nu primesc mesaje WM_COMMAND de la tastele de accelerare.Unele reguli privind atribuirea tastelor de accelerareTeoretic, putei s definii un accelerator pentru aproape orice tast n combinaie cu tastele Shift, Alt sau Ctrl. Totui, pentru consecven i pentru a evita ncurcturile, nu folosii tastele Tab, Enter, Esc i bara de spaiu pentru acceleratori, deoarece acestea sunt deseori folosite pentru funcii de sistem.De cele mai multe ori, tastele de accelerare sunt folosite pentru articolele din meniurile Edit ale programelor. Tastele de accelerare recomandate pentru aceste articole s-au schimbat de la Windows 3.0 la Windows 3.1, aa c nu este ceva neobinuit s gsii aplicaii care accept ambele stiluri, prezentate n tabelul urmtor:Funcie

Accelerator vechi

Accelerator nou

Undo (Anulare)Alt+BackspaceCtrl+Z

Cut (Decupare)Shift+DelCtrl+X

Copy (Copiere)Ctrl+InsCtrl+C

Paste (Lipire)Shift+InsCtrl+V

Delete (tergere)DelDel

O alt tast de accelerare deseori folosit este FI, pentru apelarea sistemului de asisten soft (help). Evitai folosirea tastelor F4, F5 i F6 deoarece acestea sunt deseori folosite pentru funcii speciale n programele care implementeaz interfaa multidocu-ment (MDI - Multiple Document Interface), despre care vom discuta n Capitolul 18.Tabelul de acceleratoriTabelul tastelor de accelerare este definit n fiierul script de resurse. Forma general a acestuia este:MyAccelerators ACCELERATORS {[definirea acceleratorilor] )Numele tabelului este MyAccelerators. Tabelul ACCELERATORS nu conine opiuni de ncrcare sau opiuni legate de folosirea memoriei. Fiierul script de resurse poate conine mai multe tabele ACCELERATORS.Fiecare tast de accelerare trebuie definit pe o linie separat. Exist patru tipuri de definiii de acceleratori:"char",id[.SHIFT] [.CONTROL] [,ALT]"Achar",id[,SHIFT] [.CONTROL] [,ALT]nCode,id,ASCII [,SHIFT] [.CONTROL] [.ALT]nCode,id,VIRTKEY [.SHIFT] [.CONTROL] [,ALT]n acest exemplu, char" nseamn un singur caracter ncadrat de ghilimele, Achar" nseamn caracterulA urmat de un singur caracter, ncadrate de ghilimele, id este un numr care are acelai rol ca i identificatorul din definiia unui meniu. Aceasta este valoare pe care Windows o trimite procedurii de fereastr prin mesajul WM_COM-MAND pentru identificarea acceleratorului. De obicei, aceti identificatori sunt definii n fiierul antet. Aproape ntotdeauna, tastele de accelerare selecteaz opiuni din meniurile derulante. Atunci cnd tasta de accelerare dubleaz o comand de meniu, folosii acelai identificator att pentru meniu, ct i pentru tasta de accelerare. Atunci cnd tasta de accelerare nu dubleaz o comand de meniu, folosii un identificator unic.Pentru prima definiie, tasta de accelerare este caracterul inclus ntre ghilimele, fcndu-se diferena ntre literele mari i cele mici:"char", id[,SHIFT] [.CONTROL] [,ALT]Dac vrei s definii un accelerator pentru o combinaie ntre caracterul ncadrat de ghilimele i tastele Shif t, Ctrl i Alt, adugai cuvintele cheie SHIFT, CONTROL i/sau ALT.Pentru a doua definiie, acceleratorul este o combinaie ntre caracterul specificat si tasta Ctrl:"Achar", id

[,SHIFT] [.CONTROL] [,ALT]Acest tip de definiie este identic cu primul tip dac se folosete numai identificatorul CONTROL.Ultimele dou tipuri folosesc un numr n locul caracterului dintre ghilimele:nCode, id, ASCII nCode, id, VIRTKEY

[,SHIFT] [.CONTROL] [,ALT] [,SHIFT] [.CONTROL] [.ALT]Acest numr este interpretat fie ca un cod ASCII, fcndu-se diferena ntre caracterele mari i cele mici, fie ca un cod virtual de tast, n funcie de cuvntul cheie folosit (ASCII sau VIRTKEY).Tipurile de acceleratori cel mai des folosite sunt al doilea i al patrulea. Al doilea tip este folosit pentru combinaiile cu tasta Ctrl. De exemplu, linia urmtoare definete un accelerator pentru combinaia Ctrl+A:"AA\ idAl patrulea tip de definiie este folosit pentru codurile de taste virtuale, cum ar fi tastele funcionale. De exemplu, linia urmtoare definete un accelerator pentru combinaia Ctrl+F9:VKJ9, wid, VIRTKEY, CONTROLIdentificatorul VK_F9 este definit n fiierele antet Windows ca fiind codul virtual pentru tasta F9, aa c trebuie s includei acest fiier n fiierul script de resurse:#include Primul i al treilea tip de acceleratori sunt rareori folosite. Dac vrei s le folos totui, acordai o atenie deosebit diferenierii majusculelor de minuscule. Windo1 face verificrile de coresponden cu "char" sau nCode n funcie de caracterul aps Dac adugai cuvntul cheie SHIFT, Windows verific dac a fost apsat tasta Sh Aceast situaie produce uneori rezultate neateptate. De exemplu, dac "char" e "A", acceleratorul este apelat atunci cnd apsai tasta A i este apsat tasta Sh sau este activ Caps Lock, dar nu ambele deodat. Dac folosii "A" cu SHIFT, trebi s apsai tastele A i Shift simultan, dar acceleratorul nu poate fi apelat n nici un dac este activ Caps Lock. La fel, acceleratorul "a" este apelat dac tasta A este aps fr tasta Shift, sau dac tasta A este apsat mpreun cu tasta Shift, iar Caps L< este activ. Acceleratorul "a" cu SHIFT este apelat numai dac tasta A este aps mpreun cu tasta Shift, iar Caps Lock este activ.Atunci cnd definii un accelerator pentru un articol de meniu, este bine includei combinaia de taste n textul articolului. Caracterul tab (\t) separ textul accelerator, a