Clasa "BUTTON" t9k18ks
Asa cum a rezultat din laboratorul anterior aceasta clasa de ferestre este predefinita, fiind specifica unor ferestre "copil" ale ferestrei
aplicatiei sau ferestrelor de dialog. Dintre toate clasele predefinite aceasta este cea
mai bogata in elemente de control. Definitia standard a clasei este: un control
de tip buton este o mica fereastra copil reprezentind un "buton" pe care
utilizatorul il poate comuta actionind asupra lui cu mouse-ul. Controalele de tip buton pot fi folosite independent sau in grupuri, si pot fi sau nu "etichetate"
cu un text.
In mod tipic acestea isi schimba aspectul atunci cind sint actionate de catre utilizator.
Specificitatea fiecarui buton este data de stilul atasat ferestrei sale.
Stilurile sau tipurile de butoane sint definite in continuare.
Butoanele de apasare au un aspect tridimensional fiind "luminate"
pe o parte si umbrite pe cealalta. In majoritatea cazurilor contin un text centrat
in mijloc desemnind functia pe care o indeplinesc. BS_PUSHBUTTON- este stilul
unui buton obisnuit de apasare ce transmite la actionarea asupra sa mesajul
WM_COMMAND parintelui sau ca dealtfel toate celelalte controale active.
BS_DEFPUSHBUTTON- este identic cu butonul anterior doar ca are in jur un chenar mai gros (semnificind ca el are focalizarea mesajelor de intrare input focus). Utilizatorul poate actiona acest buton prin simpla apasare a tastei ENTER. Acest stil este util cind propunem o actiune sau optiune implicita (default).
Casutele de marcaj functioneaza ca un buton cu "memorie". Ele pot
fi comutate intre doua sau uneori trei stari. Se folosesc cu precadere la setarea
unor optiuni (flag-uri) de tip da-nu sau da-nesemnificativ-nu.
BS_CHECKBOX-La actionare butonul isi informeaza parintele care apoi trebuie sa-i comande inapoi cum sa-si modifice marcajul (pune sau sterge "X"
din patratel).
BS_AUTOCHECKBOX- este similar unei casute de marcaj, exceptind faptul ca marcajul este automat modificat de catre buton. El actioneaza ca un comutator: la prima actionare pune "X" pentru ca la urmatoarea sa-l
stearga.
BS_3STATE- este similar cu casuta de marcaj doar ca mai are o stare, a treia, in care aspectul sau este gri. De obicei se foloseste pentru a indica
dezactivarea comutatorului.
BS_AUTO3STATE- similar casutei de marcaj cu trei stari doar ca isi schimba aspectul ciclic prin starile de marcat, gri si normal (demarcat).
Butoanele radio se numesc asa de la functionarea similara cu cea a butoanelor pentru selectia lungimii de unda la aparatele de radio cu claviatura
Este deci evident ca sint butoane cu doua pozitii si se folosesc de obicei in
grup, "apasarea" unuia dintre ele provocind "ridicarea"
celorlalte din grup, deci pentru pentru optiuni mutual-exclusive. Sint reprezentate printr-un cerculet gol pentru buton inactiv si plin pentru buton activ. Evident ca si
in cazul acestora se obisnuieste etichetarea cu un text semnificind optiunea.
BS_RADIOBUTTON- este butonul radio simplu, care dupa ce-si informeaza parintele trebuie sa i se spuna cum sa se repicteze.
BS_AUTORADIOBUTTON- este butonul radio cel mai utilizat deoarece stie sa se "umple" singur daca este actionat si sa dezactiveze celelalte
butoane radio din grup.
Stilul de butoane casuta sau radio pot fi combinate cu stilul
BS_LEFTTEXT in acest fel fiind posibila atasarea etichetei in partea stinga
a desenului butonului propriu-zis.
Caseta de grupare
BS_GROUPBOX-nu este practic un buton ci un element coordonator (sau ierarhizant) a mai multor butoane simple. La butoanele din grup se ajunge de
exemplu prin tasta TAB iar in grup, trecerea de la un buton la altul se face
cu ajutorul sagetilor. Caseta este reprezentata printr-un chenar dreptunghiular
care poate avea o eticheta in coltul stinga-sus. De obicei se foloseste pentru
a grupa butoanele radio.
Butoane personalizate
BS_OWNERDRAW-acest stil specifica un buton care este desenat dupa cum doreste programatorul. Asta inseamna de fapt ca procedura ferestrei parinte,
deci proprietarul (owner-ul) controlului respectiv, trebuie sa il si deseneze atunci
cind e cazul. Pentru aceasta el este instiintat la crearea controlului de dimensiunile
lui prin mesajul WM_MEASUREITEM, iar cind este cazul sa-si modifice aspectul
prin
WM_DRAWITEM. Aceste mesaje sint generate de nucleul Winndows.
Mesajele parintelui catre butonul copil
Chiar daca nu pare de o utilitate imediata totusi in windows.h sint definite cinci mesaje specifice pe care o fereastra le poate trimite butoanelor
sale. Toate aceste mesaje incep evident cu un BM_(button message). Cu aceasta
ocazie vom face cunostinta si cu un mesaj de uz general pe care programatorii
de la Microsoft l-au numit WM_USER. Trebuie stiut ca toate mesajele definite
in mod specific pentru diferitele schimburi de informatii sint unsigned mai mici de 32767 urmatoarea valoare fiind chiar acest mesaj. De aici in sus pina la
65535 utilizatorul (adica programatorul) poate sa-si defineasca propriile sale
mesaje cu care sa comunice ferestrele aplicatiilor sale; de exemplu:
#define MY_TERMMESSAGE WM_USER+9999
Pe acest principiu sint si mesajele catre butoane, definite in headerul
windows.h:
#define BM_GETCHECK (WM_USER+0)
#define BM_SETCHECK (WM_USER+1)
#define BM_GETSTATE (WM_USER+2)
#define BM_SETSTATE (WM_USER+3)
#define BM_SETSTYLE (WM_USER+4)
Primele doua se folosesc pentru a afla respectiv a pozitiona marcajul intr-o casuta sau buton radio. Iata in urmatorul exemplu cum s-ar putea face
comutarea unui buton de acest tip (stil):
SendMessage(LOWORD(lParam),BM_SETCHECK,
(WORD)!SendMessage(LOWORD(lParam),BM_GETCHECK,0,0L),0L);
Aceasta se va face evident pe parcursul tratarii unui WM_COMMAND de la butonul in cauza, cind LOWORD(lParam) nu este nimeni altul decit handle-ul controlului respectiv (vezi labor anterior). Inca o observatie - castul de
(WORD) inaintea negarii rezultatului intors de la al doilea mesaj este necesar
deoarece functia SendMessage intoarce un long iar cel de-al treilea parametru
al ei este un WORD.
Urmatoarele doua mesaje sint specifice butoanelor de apasare: primul setind starea butonului, al doilea aflind-o. Iata cum se poate vizualiza apasarea
respectiv depresarea unui buton, al carui handle sa fie hwndButton, fara sa-l actionam cu mouse-ul sau cu tasta SPACE:
butonul este apasat (de omul invizibil):
SendMessage(hwndButton,BM_SETSTATE,0,0L);
Mesajul BM_GETSTATE returneaza, dupa cum era firesc, TRUE daca butonul este apasat, si FALSE daca este in starea normala (neapasat).
Ultimul dintre mesaje, BM_SETSTYLE, poate provoca o adevarata harababura in interfata deoarece este capabil sa schimbe style-ul unui buton dupa ce acesta a fost creat. In general nu se foloseste.
Mesajele butonului copil catre parinte
Ca orice copil, butonul il informeaza pe parintele sau daca "pateste"
ceva. Informarea se face prin acel submesaj, de care am amintit in labor anterior, al mesajului propriu-zis care este WM_COMMAND. Acest sub-mesaj se numeste mesaj de notificare sau aducere la cunostinta (notification message) si poate
fi in cazul butoanelor unul din urmatoarele (definite in windows.h) :
BN_CLICKED informeaza ca a fost actionat (s-a facut un clic pe el). Acest mesaj poate apare pentru fiecare stil de buton. Ca urmare in jurul sau, sau
a textului sau, apare un contur cu linie punctata semnificind ca butonul are input
focus. In aceasta stare toate mesajele de tastatura sint captate de el insa
acestea nu sint interpretate cu exceptia SPATIULUI echivalent cu clic pe mouse si evident cu exceptia acceleratorilor. La fel este si mesajul BN_DBLCLICKED
care specifica un clic dublu pe buton. Celelalte mesaje de notificare sint utilizate doar de butoanele personalizate indicind modul in care butonul trebuie redesenat.
Acestea sint BN_PAINT pentru starea normala, BN_HILITE pentru buton apasat
BN_UNHILITE pentru buton depresat dar cu input focus si BN_DISABLE pentru buton invalidat. In cazul unui astfel de buton pentru a fi pictat este necesara determinarea contextului sau grafic, lucru posibil pe baza handle-ului ferestrei ce poate fi preluat din parametrul lParam.
Functii de gestiune a ferestrelor
-efecte in lumea butoanelor-
Etichetele sau inscriptionarile butoanelor sint echivalente textului din titlul unei ferestre normale. Acest text se poate deci modifica in concordanta, folosind functii deja cunoscute. Set-WindowText() seteaza textul butonului,
GetWindowText() intoarce textul butonului iar GetWindowTextLenght() returneaza lungimea acestui text.
Afisarea unui buton poate fi controlata intr-o maniera similara cu cea a ferestrelor. Deci ShowWindow() afiseaza sau sterge butonul de pe ecran,
IsWindowVisible() informeaza asupra starii de afisare a unui buton, EnableWindow() valideaza/invalideaza functionarea unui buton (un buton de apasare invalidat
are textul gray),IsWindowEnable() afla starea de validare a unui buton.
Cedarea controlului catre alte elemente de control din fereastra, se face prin modificarea focus-ului folosind functia SetFocus().
#include <windows.h>
#include "w5.h"
HANDLE hInst;
HWND hMainWnd;
char *szAppName = "w5";
DWORD ver; int ver31;
char *bmpnamesa4i= A
"win30u",
"win30d",
"win31u",
"win31d"
S;
void DrawControl(HWND hWnd,LPDRAWITEMSTRUCT lpInfo);
BOOL InitFirstInstance (HANDLE); long FAR PASCAL MainWndProc(HWND, unsigned int, WORD, LONG);
#pragma argsused
BOOL InitFirstInstance(HANDLE hInstance)
A
WNDCLASS wc;
wc.lpszClassName =szAppName;
wc.style =CS_HREDRAW | CS_VREDRAW;
wc.hCursor =LoadCursor(NULL, IDC_ARROW);
wc.hIcon =LoadIcon(hInstance,"Icon" );
wc.lpszMenuName ="Menu";
wc.hbrBackground =GetStockObject(WHITE_BRUSH);
wc.hInstance =hInstance;
wc.lpfnWndProc =(WNDPROC)MainWndProc;
wc.cbClsExtra =0;
wc.cbWndExtra =DLGWINDOWEXTRA;
return RegisterClass( &wc );
S
#pragma argsused int PASCAL WinMain(HANDLE hInstance , HANDLE hPrevInstance, LPSTR lpszCmdLine,
int cmdShow )
A
MSG msg; hInst = hInstance; if( !hPrevInstance ) A if ( !InitFirstInstance( hInstance ) ) A return 1;
S
S hMainWnd = CreateDialog( hInst, szAppName, 0, NULL ); if ( !hMainWnd ) return 1;
ShowWindow( hMainWnd, cmdShow );
UpdateWindow( hMainWnd );
while( GetMessage( &msg, NULL, 0, 0 ) ) A
TranslateMessage( &msg );
DispatchMessage( &msg );
S
return msg.wParam;
S
#pragma argsused long FAR PASCAL MainWndProc( HWND hWnd, unsigned message, WORD wParam, LONG
lParam )
A int i;
PAINTSTRUCT ps;
RECT r; int check;
switch( message ) A case WM_CREATE: ver31=(HIBYTE(LOWORD(GetVersion()))==10) ?
1 : 0; break; case WM_DRAWITEM:
DrawControl(hWnd, ( LPDRAWITEMSTRUCT )lParam );
SendMessage( GetDlgItem(hWnd, IDR_31 ), BM_SETCHECK, ver31, 0 );
SendMessage( GetDlgItem( hWnd, IDR_30 ), BM_SETCHECK,
1 - ver31, 0 ); break; case WM_COMMAND: switch( wParam ) A case IDC_BUTTON: if( SendMessage( GetDlgItem( hWnd, ICB_BEEP ), BM_GETCHECK,
0, 0 ) )
MessageBeep( -1 ); break; case IDR_30: ver31 = 0;
SendMessage( GetDlgItem( hWnd, IDR_30 ),
BM_SETCHECK, 1, 0L );
SendMessage( GetDlgItem( hWnd, IDR_31 ),
BM_SETCHECK, 0, 0L );
GetWindowRect( hWnd, &r );
InvalidateRect( hWnd, &r, FALSE ); break; case IDR_31: ver31 = 1;
SendMessage( GetDlgItem( hWnd, IDR_31 ),
BM_SETCHECK, 1, 0L );
SendMessage( GetDlgItem( hWnd, IDR_30 ),
BM_SETCHECK, 0, 0L );
GetWindowRect( hWnd, &r );
InvalidateRect( hWnd, &r, FALSE ); break; case ICB_BEEP: check = (SendMessage( GetDlgItem( hWnd,
ICB_BEEP ), BM_GETCHECK, 0, 0 ) ) ? 0 : 1;
SendMessage( GetDlgItem( hWnd, ICB_BEEP ),
BM_SETCHECK, check, 0 ); break;
S break; case WM_DESTROY:
PostQuitMessage( 0 ); break;
S return DefWindowProc( hWnd, message, wParam, lParam );
S
#pragma argsused void DrawControl( hWnd, lpInfo )
HWND hWnd;
LPDRAWITEMSTRUCT lpInfo;
A
HBITMAP hbm, hOldbm; int bmp;
HDC hMemDC;
if( lpInfo->CtlType != ODT_BUTTON ) return; switch(lpInfo->CtlID) A case IDC_BUTTON: bmp = ver31 * 2; break; default: return;
S if( lpInfo->itemState & ODS_SELECTED ) bmp += 1; hbm = LoadBitmap( hInst, bmpnamesabmpi ); if( !hbm ) return; if( ( lpInfo->itemAction & ODA_DRAWENTIRE )
|| ( lpInfo->itemAction & ODA_SELECT ) ) A hMemDC = CreateCompatibleDC( lpInfo->hDC ); hOldbm = SelectObject( hMemDC, hbm ); if( hOldbm ) A
BitBlt( lpInfo->hDC,
( lpInfo->rcItem ).left,
( lpInfo->rcItem ).top,
( lpInfo->rcItem ).right ( lpInfo->rcItem ).left,
( lpInfo->rcItem ).bottom ( lpInfo->rcItem ).top, hMemDC,
0, 0,
SRCCOPY );
SelectObject( hMemDC, hOldbm );
S
DeleteDC( hMemDC );
S
DeleteObject( hbm );
S
---------------------------------------------------------------------
NAME w5
DESCRIPTION 'OwnerDraw Button Exemple'
STUB 'WINSTUB.EXE'
EXETYPE WINDOWS
CODE MOVEABLE
DATA MOVEABLE MULTIPLE PRELOAD
HEAPSIZE 4800
STACKSIZE 10240
EXPORTS MainWndProc @1
---------------------------------------------------------------------
#define ICB_BEEP 1004
#define IDC_BUTTON 1001
#define IDR_31 1002
#define IDR_30 1003
---------------------------------------------------------------------
#include "w5.h"
Icon ICON "icon.ico"
w5 DIALOG 15, 23, 125, 133
STYLE WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
CLASS "w5"
CAPTION "OwnerDraw Button"
FONT 10, "Arial"
BEGIN
CONTROL "Version", -1, "button", BS_GROUPBOX |
WS_CHILD | WS_VISIBLE, 2, 90, 60, 36
CONTROL "Sound", 102, "button", BS_GROUPBOX |
WS_CHILD | WS_VISIBLE, 63, 90, 60, 36
CONTROL "Text", IDC_BUTTON, "BUTTON", BS_OWNERDRAW |
WS_CHILD | WS_VISIBLE | WS_TABSTOP, 12, 7, 102, 81
RADIOBUTTON "Windows 3.1", IDR_31, 7, 100, 52, 12, WS_CHILD | WS_VISIBLE
| WS_TABSTOP
RADIOBUTTON "Windows 3.0", IDR_30, 7, 110, 53, 12, WS_CHILD | WS_VISIBLE
| WS_TABSTOP
CHECKBOX "Beep on click", ICB_BEEP, 66, 103, 54, 12, WS_CHILD | WS_VISIBLE
| WS_TABSTOP
END
win30u BITMAP "300.bmp"
win30d BITMAP "300s.bmp"
win31u BITMAP "3010.bmp"
win31d BITMAP "3010s.bmp"
EDITare
Dintre toate controalele predefinite clasa celor de editare -"edit" pare sa fie cea mai simpla dar sub unele aspecte si cea mai complexa. In principiu acest control reprezinta o fereastra specializata in introducerea si afisarea de texte precum si manipularea acestora. Mai precis intr-o zona rectangulara definita la crearea ferestrei de editare avem posibilitatea introducerii unui text, vizualizarii lui, mutarii mouse-ului in diverse regiuni ale textului, selectarea unor zone de text, mutarea lor in alta pozitie,stergere, lucrul interactiv cu 'Clipboard'-ul etc.
Pentru a intelege mai bine aceasta clasa de controale predefinite vom urmari doua aplicatii care fac acelasi lucru, prima intr-o modalitate "clasica", mai apropiata de ceea ce stiam din DOS, controland deci tastatura, afisarea
textului , mutarea in text si functiile primare de editare, a doua folosind
aceasta clasa specifica.
Masina de scris "mecanica"
Acest program este doar o demonstratie sumara a muncii pe care trebuie sa ne-o asumam atunci cand dorim realizarea unui editor de texte. Iata cum stau
lucrurile in aceasta privinta :
Primele simplificari: sa nu ne complicam cu stilul caracterelor folosite in afisarea textului , cu operatiile de incarcare , salvare in fisier, cu lucrul pe blocuri si alte asemenea idei care ne-ar putea deturna de la a realiza o "simpla masina de scris" . Exista insa cateva probleme ce
nu pot fi ocolite si asupra lor ne vom concentra atentia.
1. Prima este tratarea minimala dar consistenta a tastaturii(si asta stim s-o facem caci a fost prezentata intr-un labor anterior). Pentru aceasta ne vom aminti ca exista mesajul WM_KEYDOWN care aduce procedurii de fereastra codul virtual al tastei apasate, cod ce poate fi folosit in simularea diferitelor functii specifice editarii cum ar fi salt la inceputul textului
sau la sfarsitul sau, pozitionarea la stanga sau la dreapta, sus sau jos fata de pozitia de inserare curenta , stergere.
2. Pentru a vizualiza punctul de introducere a textului ne vom folosi de un indicator special care evident nu poate fi cel de mouse. In Windows aceasta se numeste 'caret', tradus -cursor. Exista in interfata API Windows
cinci functii esentiale care se ocupa de gestiunea cursoarelor:
'CreateCaret' - care creaza un cursor asociat unei ferestre;
'SetCaretPos' - fixeaza cursorul in fereastra la o pozitie data;
'ShowCaret' - afiseaza cursorul;
'HideCaret' - ascunde cursorul;
'DestroiCaret' - distruge cursorul;
Exista de asemenea functiile:
'GetCaretPos' - returneaza pozitia cursoruli;
'SetCaretBlinkTime' - modifica frecventa de clipire a cursorului;
'GetCaretBlinkTime' - returneaza frecventa de clipire.
Din pacate cursorul nu poate fi creat odata cu fereastra, deci procesind mesajul WM_SETFOCUS, respectiv distrugerea cursorului cand fereastra pierde focalizarea intrarilor, anuntata de mesajul WM_KILLFOCUS. Aceasta este regula principala atunci cand tratam un cursor.
Mai exista cateva reguli: dupa crearea unui cursor cu CreateCaret trebuie apelata functia ShowCaret pentru a-l face vizibil; cursorul trebuie ascuns inainte de a desena pe spatiul ferestrei, cu exceptia cazului in care se proceseaza mesajul WM_PAINT, folosind functia HideCaret. Ca in multe alte cazuri cand este vorba de "obiecte" ale contextului grafic aceste functii decrementeaza
respectiv incrementeaza un contor de ascundere asociat, obiectul fiind vizibil doar daca
acesta este 0. Deci pentru fiecare Hide trebuie apelat un Show pentru a reface vizibilitatea cursorului.
Ultima observatie legata de cursor este aceea ca pozitia in fereastra este gestionata in pixeli (coordonatele fiind relative la coltul stinga-sus al zonei de lucru, cum de alfel este normal intr-o interfata grafica).
3. Sa nu scapam din vedere cel mai important lucru. Acest program daca vrea sa simuleze o masina de scris trbuie sa trateze caracterele. Acestea vin spre procedura ferestre cand ea focalizeaza intrarea. Mesajul WM_CHAR va fi deci tratat corespunzator iar prin caractere speciale cu o anumita semnificatie pentru editarea de texte s-au prevazut cateva procesari, pentru backspace, tab, enter si escape.
4. Pentru a afla caracteristicile grafice ale fontului sistem, cu care va fi afisat textul, s-a preluat in structura TEXTMETRIC aceste informatii cu functia GetTextMetrics din care intereseaza deocamdata doar latimea respectiv
inaltimea fontului.
5. Afisarea in fereastra se realizeaza cu TextOut(hDC,x,y,pszbuff,nc) o functie care deseneaza textul in contextul grafic hDC al ferestrei, la o pozitie precizata (x,y) dintr-un buffer al carui pointer este pszbuff, un numar nc de
caractere.
6. Deoarece textul se deseneaza in fereastra aplicatiei, orice mutare sau modificare de dimensiuni semnalizata prin mesajele WM_SIZE, WM_MOVE trebuie procesate.
Programul acesta nu-si propune sa "emuleze" complet o fereastra de editare. El s-a propus doar pentru a sugera cat de mult este de lucru pentru a implementa cateva doar din facilitatile unui control de editare.
Masina de scris "electronica"
Folosind clasa "edit" vom construi acum o noua aplicatie care cu
un efort de programare mult mai mic va acoperi toate functionalitatile necesare si evident multe alte facilitati.
Sa facem deci cunostinta cu EDIT.
Atributele - style
Peste tot in Windows atunci cand e vorba de introdus un sir de caractere avem la dispozitie un control ce accepta o singura linie de text. Acesta este stilul de baza al clasei, dar daca dorim, la crearea controlului putem preciza
ES_MULTILINE si vom avea un control multi-linie. Asa cum s-a vazut la controalele statice de etichetare, avem si aici posibilitatea alinierii textului in fereastra la stanga, centru sau dreapta, prin adaugarea stilului de ES_LEFT
(implicit), ES_CENTER respecti ES_RIGHT. Daca vrem ca in cazul unui text ce depaseste marimea ferestrei sa se execute automat defilarea ferestrei inspre directia solicitata nu trebuie decat sa imbunatatim parametrul ce defineste stilul cu ES_AUTOHSCROLL penru defilarea automata orizontala si/sau
ES_AUTOVSCROLL pentru cea verticala. Asa cum s-a vazut in labor despre barele de defilare acestea pot fi atasate unei ferestre prin precizarea stilului
WS_HSCROLL, WS_VSCROLL. Cum controlul este si el o fereastra este normal sa-i putem da si astfel de atribute. In mod implicit un control de editare nu are chenar dar daca ii dorim unul este suficient sa-i adaugam stilul WS_BORDER.
In fine daca dorim ca o selectie de text sa ramana afisata in fereastra chiar daca controlul nu mai are focalizare, avem la dispozitie atributul WS_NOHIDENSEL.
Mesaje de notificare
Ca orice fereastra copil, si controlul de editare comunica cu parintele sau prin mesaje de informare sau notificare asupra evenimentelor ce se petrec in el. Aceste mesaje vin cum este normal prin WM_COMMAND. Ele sunt:
EN_SETFOCUS-controlul a castigat focus-ul
EN_KILLFOCUS-controlul a pierdut focus-ul
EN_CHANGE-continutul se va schimba
EN_UPDATE-continutul s-a schimbat
EN_ERRSPACE-s-a depasit spatiul de memorie alocat
EN_MAXTEXT-s- depasit spatiul de insertie text
EN_HSCROLL-s-a actionat asupra barei de defilare orizontale
EN_VSCROLL-s-a actionat asupra barei de defilare verticale
Exemplul trateaza doar informarea despre depasirea de memorie alocata afisand o avertizare. Controlul de editare memoreaza textul in heap-ul local al instantei curente a aplicatiei. Continutul este limitat la aproximativ
32 KB de text, limita la care functioneaza si cunoscutul accesoriu "Notepad" din WINDOWS tocmai datorita faptului ca se foloseste de acest tip de control.
Un programator profesionist vede deja in aceasta valoare faptul ca lungimea
este de tip int. Desi in modul de definire DEF a acestui exemplu se rezerva doar 1 KB pentru heap-ul local, extensia lui daca este necesara se va face automat de catre nucleu.
Mesaje catre control
Parintele unui control de editare are la dispozitie un grup inprensionant de mesaje specifice pentru controlul unei ferestre de editare ce-i apartine
si pe care o numim hWndEdit. Exista de asemenea acele functii cu caracter general
ce pot aduce, transmite sau detecta lungimea unui text asociat unei ferestre.
Daca pentru ferestrele de aplicatii acest text este chiar titlul, pentru un control de editare el este continutul sau. Deci GetWindowText(hWndEdit, pszBuff,cbMax) aduce in bufferul cu adresa pszBuff maximul cbMax caractere din fereastra hWndEdit, returnind numarul de caractere efectiv tratate. O alta functie din aceiasi categorie este GetWindowTextLength(hWndEdit) care returneaza lungimea textului dintr-un control. In fine avem si functia
SetWindowText(hWndEdit,pszBuff) de modificare a textului din control cu textul de la adresa pszBuff. Aceste functii nu fac altceva decit sa trimita controlului masajele WM_GETTEXT,WM_GETTEXT_LENGTH si respectiv WM_SETTEXT prin intermediul SendMessage(). In continuare vom parcurge alte trei mesaje cu o specificitate aparte. Desi au un caracter general ele sunt folosite cu precadere in editare. Este vorba de transferul cu Clipboard-ul, aceasta facilitate intriseca a nucleului de a pastra temporar ceva, in cazul nostru text. Cele trei mesaje se refera la zona de text selectata cu mouseul sau cu Shift + sageti de la tastatura. Cele trei masaje se regasec in toate aplicatiile care au un mesaj de editare, deci Cut, Paste si Copy.
SendMessage(hWndEdit,WM_CUT,0,0L) "taie" selectia din textul controlului si o depoziteaza in Clipboard. SendMessage(hWndEdit,WM_COPY,0,0L) copiaza selectia din textul controlului si o depoziteaza in Clipboard iar SendMessage
(hWndEdit,WM_PASTE,0,0L) aduce din Clipboard textul la pozitia cursorului sau in locul selectiei curente. Tastele de accelerare pentru aceste operatii si altele specifice meniului Edit sunt definite in specificatiile CUA
Advanced Interface Design:
Alt+BkSpace Undo-Reface
Del Clear-Sterge
Ctrl+Ins Copy -Copiaza in Clipboard
Shift+Del Cut-Taie si pune in Clipboard
Shift+Ins Paste-Aduce din Clipboard
Mesajele specifice controalelor de editare au prefixul EM si sunt urmatoarele
EM_CANUNDO stabileste daca se poate reface starea dinaintea ultimei operatii
EM_EMPTYUNDOBUFFER sterge flag-ul de refacere
EM_FMTLINES comuta utilizarea sfirsitului de linie soft
EM_GETFIRSTVISIBLELINE determina care este prima linie vizibila dintr-un control
EM_GETHANDLE primeste handle-ul memoriei alocate de control pentru text
EM_GETLINE returneaza linia curenta intr-un control multi-linie
EM_GETLINECOUNT detemina numarul de linie
EM_GETMODIFY afla daca continutul s-a modificat
EM_GETPASSWORDCHAR returneaza un caracter in mod parola
EM_GETRECT returneaza dreptunghiul ce delimiteaza controlul
EM_GETSEL preia sirul selectat
EM_GETWORDBREAKPROC gaseste functia care gestioneaza sfirsitul de linie
EM_LIMITTEXT determina capacitatea limita a controlului de limitare
EM_LINEFROMCHAR returneaza indexul din contorul de caracter
EM_LINEINDEX returneaza pozitia caracterului in linia data
EM_LINELENGTH returneaza lungimea liniei
EM_LINESCROLL defileaza textul intr-un control multi-linie
EM_REPLACESEL inlocuieste selectia curenta
EM_SETHANDLE furnizeaza controlul handle-ul zonei de memorie locala care contine textul
EM_SETMODIFY incarca flag-ul de modificare al controlului
EM_SETPASSWORDCHAR modifica carcterul de parola al controlului
EM_SETREADONLY aduce controlul in stare read-only
EM_SETRECT fixeaza dreptunghiul de formare a controlului
EM_SETRECTNP identic cu anteriorul doar ca se redeseneza fereastra
EM_SETSEL selecteaza un text intr-un control multi-linie
EM_SETTABSTOPS fixeaza pozitiile de tabulare intr-un control multi-linie
EM_SETWORDBREAKPROC furnizeaza controlului adresa unei proceduri personale de tratare a sfirsitului de linie
EM_UNDO reface starea controlului dinaintea ultimei operatii.
===============================================================================
#include <windows.h>
#define BUFF(x,y) (pBuff+y*cxBuff+x) char szAppNameai="Masina de scris I"; lHANDLE hInst; long FAR PASCAL WndProc(HWND, WORD, WORD, LONG);
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
A
HWND hWnd;
MSG msg;
WNDCLASS wndClass; hinst=hInstance; if(!hPrevInstance)A
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpszClassNAme =szAppNAme;
wndClass.lpfnWndProc =(WNDPROC)WndProc;
wndClass.cbClsExtra =0;
wndClass.cbWndExtra =0;
wndClass.hInstance =hInst;
wndClass.hIcon =LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor =LoadCursor(NULL, IDC_ARROW);
wndClass.lpszMenuName =NULL;
wndClass.hbrBackground =GetStockObject(WHITE_BRUSH);
RegisterClass(&wndClass);
S hWnd=CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, GetSystemMetrics(SM_CXSCREEN)/2, GetSystemMetrics(SM_CYSCREEN)/2,
NULL, NULL, hInst, NULL);
ShowWindow(hWnd, cmdShow);
while (GetMessage(&msg, NULL, 0, 0))A
TranslateMessage(&msg);
DispatchMessage(&msg);
S return msg.wParm;
S long FAR PASCAL WndProc(HWND, hWnd, Word, message wParam, LONG lParam)
A static char *pBuff=NULL; static int cxChar, cyChar, cxClient, cyClient, cxBuff, cyBuff, xCaret, yCaret;
HDC hDC; int x, y, i;
PAINTSTRUCT ps;
TEXTMETRIC tm; switch(message) A case WM_CREATE: hDC=GetDC(hWnd);
SelectObject(hDC,GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hDC,&tm); cxChar=tm.tmAveCharWidth; cyChar=tm.tmHeight;
ReleaseDC(hWnd, hDC); break; case WM_SIZE: cxClient=LOWORD(lParam); cyClient=HIWORD(lParam); cxBuff=max(1, cxClient/cxChar); cyBuff=max(1, cyClient/cyChar); if(pBUFF != NULL) free(pBuff); if((LONG)cxBuff*cyBuff > 65535l ||
(pBuff=malloc(cxBuff*cyBuff) )==NULL
MessageBox(hWnd, "nu pot aloca memorie suficienta",
"eroare:", MB_ICONEXCLAMATION | MB_OK);
/*Identic cu sursa alaturata ...doar ca...*/
char szAppNameai = ''Masina de scris II '';
long FAR PASCAL Wnd Proc( HWND hWnd, WORD mesagge, WORD wParam, LONG lParam)
A static HWND hWndEdit;
switch(message) A caseWM_CREATE: hWndEdit = CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE |
WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_LEFT | WS_MULTILINE |
ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0, 0, 0, 0, hWnd, 1,
((LPCREATESTRUCT)lParam)->hInstance, NULL ); break; case WM_SETFOCUS:
SetFocus(hWndEdit); break; case WM_SIZE:
MoveWindow(hWndEdit,0 ,0, LOWORD(lParam),
HIWORD(lParam), NULL); break; case WM_DESTROY:
PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam);
S return 0;
S else for(y=0;y < cyBuff; y++) for(x=0; x<cxBuff; x++)
BUFF(x,y)=' '; xCaret = yCaret = 0; if(hWnd == GetFocus())
SetCaretPos(xCaret*cxChar, yCaret*cyChar); break; case WM_SETFOCUS:
CreateCaret(hWnd, NULL, cxChar, cyChar);
ShowCaret(hWnd);
SetCaretPos(xCaret*cxChar, yCaret*cyChar); break; case WM_KILLFOCUS:
HideCaret(hWnd);
DestroyCaret(); break; case WM_KEYDOWN: switch(wParam)A case VK_HOME: xCaret=0; break; case VK_END: xCaret=cxBuff-1; break; case VK_PRIOR: yCaret=0; break; case VK_NEXT: yCaret=cyBuff-1; break; case VK_LEFT: xCaret=max(xCaret-1, 0); break; case VK_RIGHT: xCaret=max(xCaret+1, cxBuff-1); break; case VK_UP: yCaret=max(yCaret-1, 0); break; case VK_DOWN: yCaret=min(yCaret+1, cyBuff -1); break; case VK_DELETE: for(x=xCaret; x<cxBuff-1; x++)
BUFF(x, yCaret)=BUFF(x+1, yCaret);
BUFF(cxBuff-1, yCaret)= ' ';
HideCaret(hWnd); hDC=GetDC(hWnd);
SelectObject(hDC, GetStockObject(
SYSTEM_FIXED_FONT));
TextOut(hdc, xCaret*cxChar, yCaret*cyChar,
&BUFF(xCaret, yCaret), cxBuff-cxChar);
ShowCaret(hWnd);
ReleaseDC(hWnd, hDC); break;
SetCaretPos(xCaret*cxChar, yCaret*cyChar); break; case WM_CHAR: for(i=0;i < LOWORD(lParam); i++) A switch(wParam) A case '\b': if(xCaret>0) A xCaret--;
SendMessage(hWnd, WM_KEYDOWN, VK_DELETE, 0L);S break; case '\t': do A
SendMessage(hWnd, WM_CHAR, ' ', 1L);
S while(xCaret%8 != 0); break; case '\r': xCaret=0; case '\n': if(++yCaret == cyBuff) yCaret=0; break; case '\x1B': for(y=0; y<cyBuff; y++) for(x=0; x<cxBuff; x++)
BUFF(x,y)= ' '; xCaret=0; yCaret=0;
InvalidateRect(hWnd, NULL, FALSE); break; default:
BUFF(xCaret, yCaret) = (char)wParam;
HideCaret(hWnd); hDC=GetDC(hWnd);
SelectObject(hDC, GetStockObject(
SYSTEM_FIXED_FONY));
TextOut(hDC, xCaret*cxChar, yCaret*cyChar,
&BUFF(xCaret, yCaret), 1);
ShowCaret(hWnd);
ReleaseDC(hWnd, hDC); if(++xCaret==cxBuff) A xCaret=0; if(++yCaret==cyBuff) yCaret=0; S break;
S
S
SetCaretPos(xCaret*cxChar, yCaret*cyChar); break; case WM_PAINT: hDC=BeginPaint(hWnd, &ps);
SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT)); for(y=0; y<cyBuff; y++)
TextOut(hDC, 0, y*cyChar, &BUFF(0,y), cxBuff);
EndPaint(hWnd,&ps); break; case WM_DESTROY:
PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam);
S return 0;
S