Exemplu de aplicatie fereastra Vom prezenta o aplicatie fereastra extrem de simpla ce contine un text centrat si ajustabil la dimensiunile ferestrei, precum si un buton si un dreptunghi pozitionate fix. Imaginea icon din coltul din stanga sus a ei a fost de asemenea modificat. Invitam cititorul ca dupa ce implementeaza aplicatia pe baza programelor ce urmeaza, sa vada cum se comporta fereastra la redimensionari. Atentie, daca fereastra are focus si se apasa o tasta, sau daca se apasa (click) butonul STOP, aplicatia se termina. Pentru elaborarea aplicatiei, trebuie create patru fisiere: - fisierul cu imaginea iconului; in exemplul nostru winicon.ico; - un fisier header ce contine denumirile codificate ale resurselor folosite; in exemplul nostru resource.h; - un fisier in care sunt descrise resursele folosite; in exemplul nostru res.rc; - un program sursa C++ in care se descrie functionarea aplicatiei fereastra; in exemplul nostru primWin.cpp. Pentru implementare se poate folosi un mediu de dezvoltare, de ex. DevStudio pentru Visual C++ 6.0. Pe scurt, manevrele necesare asupra mediului sunt: - Meniul File / New / selecteaza Win32Application; - Se fixeaza numele proiectului (de exemplu primWin); - Se fixeaza directorul in cere se va dezvolta proiectul (de exemplu e:\Florin) - Se alege generarea unui “Empty Project” - Dupa “File View”, prin click-uri dreapta pe subdirectoarela corespunzatoare se adauga la proiect cele patru fisiere numite mai sus. In continuare descriem pe scurt fiecare dintre fisiere. Fisierul winicon.ico poate fi creat cu un editor specializat de iconuri, de exemplu cu ResourceWorkShop sau SdkPaint. Noi l-am creat cu instrumentul de creare de iconuri oferit de mediul DevStudio. In caz de minimizare, pe bara de taskuri (partea de jos a ecranului) apare acelasi icon urmat de textul: Cel mai simp . . . Fisierul resource.h are menirea de a atribui nume simbolice resurselor nou definite. Continutul lui este: #define IDI_ICON 100 #define IDC_BUTTON 101 In acest exemplu sunt introduse doua astfel de resurse: un icon cu codul 100 si un buton cu codul 101. Astfel de resurse trebuie de fapt codificate cu numere intregi, distincte si cu valoarea cel putin 100. Codificarile sunt folosite atat in fisierul de resurse (res.rc) cat si in programul propriu-zis (primWin.cpp). Analizand continutul celor doua fisiere se poate observa ca fiecare resursa apare exact odata in fiecare dintre fisiere. Programatorul se poate lipsi de acest fisier daca scrie, in cele doua fisiere, numerele 100 si 101 in locul numelor lor simbolice (evident, eliminand si cele doua #include “resource.h”). Practica programarii arata insa ca este mai potrivita atribuirea de nume simbolice si operarea cu acestea. O resursa Windows este o structura de date care defineste o portiune vizibila pe ecran a unui program. O astfel de resursa este de regula materializata printr-un fisier de un anumit tip. Principalele tipuri de resurse Windows sunt: acceleratori, bitmapuri (harti de biti), cursoare, ferestre de dialog (dialog boxes), fonturi, iconuri, meniuri, tabele de stringuri, resurse definite de utilizatori. Fisierul res.rc defineste resursele folosite. El poate fi obtinut fie manual de catre programator, fie prin intermediul unui editor special de resurse. Textul lui sursa este urmatorul: #include "resource.h" IDI_ICON ICON DISCARDABLE "winicon.ico" In acest exemplu se specifica doar legatura dintre numele simbolic al iconului (IDI_ICON) cu fisierul winicon.ico in care se afla imaginea iconului. Programul primWin.cpp este scris in C++ si este prezentat mai jos. #include #include #include "resource.h" char szappname[]="Primul exemplu de aplicatie fereastra"; HWND hControl; HINSTANCE hInst; long FAR PASCAL WndProc(HWND, WPARAM, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszcmdline, int ncmdshow) { WNDCLASS wnd; MSG msg; HWND hwnd; hInst=hInstance; if (!hPrevInstance) { wnd.style = CS_HREDRAW | CS_VREDRAW; wnd.lpfnWndProc = WndProc; wnd.cbClsExtra = 0; wnd.cbWndExtra = 0; wnd.hInstance = hInstance; wnd.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH); wnd.lpszMenuName = NULL; wnd.lpszClassName = szappname; if (!RegisterClass(&wnd)) return FALSE; } hwnd = CreateWindow(szappname, "Cel mai simplu program", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!hwnd) return (FALSE); ShowWindow(hwnd, ncmdshow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } long FAR PASCAL WndProc(HWND hwnd, WPARAM message, WPARAM wparam, LPARAM lparam) { HDC hdc; PAINTSTRUCT ps; RECT rect; char text[] = "Programul afiseaza un text\ \ncentrat si ajustabil in fereastra,\ \nun dreptunghi si un buton in pozitii fixe.\ \nLa un click pe buton sau \ la apasarea unei taste in fereastra ==> STOP"; switch (message) { case WM_CREATE: hControl=CreateWindow("button","STOP",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 0,0,60,20,hwnd,(HMENU)IDC_BUTTON,hInst,NULL); case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); DrawText(hdc, text, strlen(text), &rect, DT_CENTER | DT_EXTERNALLEADING | DT_NOCLIP | DT_WORDBREAK); GetClientRect (hwnd, &rect); MoveToEx(hdc, 40, 60, NULL); LineTo(hdc,100,60); LineTo(hdc,100,90); LineTo(hdc,40,90); LineTo(hdc,40,60); EndPaint(hwnd, &ps); return(0); case WM_COMMAND: if (LOWORD(wparam)==IDC_BUTTON) exit(0); case WM_KEYDOWN: exit(0); case WM_DESTROY: PostQuitMessage(0); return(0); } return DefWindowProc(hwnd, message, wparam, lparam); } Si acum cateva scurte comentarii asupra programului. Dupa cele doua include, este declarat un string care constituie numele aplicatiei (format aici din 5 cuvinte). Urmeaza declararea unei functii WndProc, a carei definiri se va face mai tarziu in program. Ea este de fapt functia fereastra a aplicatiei. Dupa ea este definita functia WinMain. Aceasta este obligatorie pentru fiecare program Windows, asa cum main este obligatoriu pentru fiecare program C. Functia are patru parametri, semnificatia carora este: - hInstance este indicatorul catre instanta curenta a programului. - hPrevInstance este indicator catre instanta anterioara a programului. Daca nu exista instante anterioare, atunci acest parametru are valoarea NULL. - lpszcmdline este pointer catre sirul care contine parametrii liniei de comanda. - ncmdshow este un intreg intre 1 si 7 care indica dimensiunea afisarii initiale a ferestrei: 1 inseamna marime naturala, 7 inseamna icon iar celelalte sunt intermediari. In interiorul functiei sunt declarate trei date: - wnd este pointer spre clasa fereastra; - msg este pointer spre o structura de date MSG iar - hwnd este handle pentru fereastra curenta. Prima instructiune fixeaza parametrii clasei de ferestre. Instructiunea if care o precede asigura ca operatia se executa doar pentru prima instanta a clasei. Atribuirea valorilor pentru cele 10 campuri ale clasei inseamna: - Stilul sa permita redimensionare orizontala si verticala. - Functia fereastra este WndProc (declarata mai sus si urmand a fi definita). - Nu se solicita octeti suplimentari nici pentru clasa nici pentru fereastra. - Se fixeaza instanta clasei creatoare. - Iconul este incarcat din fisierul indicat de IDI_ICON. - Cursorul este standard, sub forma unei sageti. - Culoarea fondului (pensula) este alba. - Fereastra nu are meniu. - Numele aplicatiei este cel fixat (“Primul exemplu de aplicatie fereastra”). Fixarea parametrilor se incheie cu inregistrarea clasei. Daca inregistrarea s-a facut cu succes, urmeaza executia instantei curente a programului. In acest scop se apeleaza functia CreateWindow. Parametrii transmisi acesteia, in ordine, au semnificatiile: - Numele clasei de ferestre. - Numele ferestrei, care va apare pe bara de titlu a ferestrei. Pentru butoane, caute de dialog, optiuni etc. acesta va fi chiar numele inscris pe obiectul respectiv. - Stilul ferestrei (sunt multe posibilitati, noi am ales-o pe cea mai simpla). - Urmeaza patru valori implicite (CW_USEDEFAULT) pentru coordonatele initiale ale coltului din stanga sus al ferestrei precum si pentru latimea si inaltimea acesteia.. - Primul parametru NULL este indicator catre fereastra parinte, deci aceasta fereastra nu are parinte. - Al doilea parametru NULL indica spre meniul principal al ferestrei. Daca un astfel de meniu specific pentru fereastra nu exista, atunci se va lua drept meniu principal meniul clasei. - hInstance este handle spre instanta program care se va executa in fereastra. - Ultimul parametru este pointer spre date suplimentare, necesare la deschiderea mai multor ferestre document. In caz de creare cu succes al ferestrei se apeleaza ShowWindow pentru desenarea ferestrei si UpdateWindow pentru a se asigura posibilitatea redimensionarii / mutarii acesteia. Urmeaza bucla de mesaje (pe care am descris-o mai sus) si instructiunea de terminare a programului. Ultima parte a programului defineste functia fereastra WndProc cu cei patru parametri ai ei. Acestia sunt de fapt primele patru campuri din structura MSG prezentata mai sus. Cele patru date locale ale acestei functii inseamna: - hdc este indexul la tabela de “contexte dispozitiv”; - ps este o structura care descrie desenarea (PAINTSTRUCT); - rect este structura care descrie portiunea dreptunghiulara in care se executa fereastra; - text este pointerul spre textul care se va afisa centrat in interiorul ferestrei. Functia actioneaza in functie de mesajul primit. Primul mesaj, WM_CREATE, provoaca crearea butonului. Se precizeaza tipul obiectului (button), titlul (STOP), cateva atribute, dimensiunile, resursa etc. Mesajul WM_PAINT afiseaza textul in fereastra cu atributele de comportare, dupa care deseneaza un dreptunghi avand diagonala (40,60 – (100,90). - BeginPaint indica inceperea desenarii. - GetClientRect intoarce limitele curente ale zonei client ale ferestrei.; - DrawText afiseaza in contextul hdc, textul indicat de text cu lungimea specificata a acestuia, in zona indicata de rect si cu patru atribute: centrat pe orizontala, cu spatiu rezervat pentru text plus distanta normala intre doua linii, fara trunchierea textului daca acesta nu incape in fereastra, trecerea la o noua linie in fereastra se face la nivel de cuvant. - MoveToEx fixeaza unul dintre colturile dreptunghiului, dupa care cele 4 LineTo traseaza laturile dreptunghiului. - EndPaint incheie afisarea ferestrei. Functia fereastra isi incheie activitatea anuntand sistemul de acest lucru prin mesajul DefWindowProc.