|
Aplicatie1() : TApplication() { }
|
səhifə | 10/18 | tarix | 12.09.2018 | ölçüsü | 1,36 Mb. | | #81721 |
| Aplicatie1() : TApplication() { };
void InitMainWindow(); };
void Aplicatie1::InitMainWindow()
{
MainWindow = new TFrameWindow(0,"Test",new Fer1);
};
int
OwlMain(int,char* [])
{
return Aplicatie1().Run();
}
Compilati,construiti,link-ati si apoi executati aplicatia.In fereastra
Test executati alternativ click-uri de mouse cu butonul drept sau stang.
Nu este necesar sa rescrieti toata fila.Puteti copia fila precedenta si
apoi adaugati doar metodele nou introduse pentru clasa Fer1.In general,
programele si aplicatiile se pot dezvolta prin modificarea,actualizarea
sau transformarea unor aplicatii precedente.
-61-
Observati elementele noi din program: fila header "owl/dc.h",cele
doua functii destinate pentru controlul butoanelor mouse si tabela de
control a evenimentelor Windows denumita RESPONSE_TABLE.
Fila header asigura tot ce este necesar pentru a putea
executa functii si operatii de tip grafic.Deschideti fila si observati
clasele definite in aceasta fila.Cea mai importanta este clasa TDC in
care sunt incluse atat contextul de dispozitiv grafic cat si principalele
functii grafice.Celelalate clase (TWindowDC,TDesktopDC,TClientDc,TPaintDC,
TMetaFileDc,TCreatedDC,TIC,TMemoryDC,TDibDC,TPrintDC) contin seturi de
metode specializate pentru diverse situatii speciale.Trebuie remarcat
faptul ca pentru fiecare clasa,contextul de dispozitiv este detectat auto-
mat de catre constructorul clasei.Dupa derivarea unui obiect nu mai este
necesar sa tineti evidenta acestui factor.Toate functiile membru se pot
apela direct.In exemplul de mai sus,au fost utilizate doar functiile
Rectangle() si TextOut().
Urmatorul element de noutate il reprezinta modul de interpretare si
control al evenimentelor de tip Windows.Toate programele care realizeaza
o interfata grafica de tip Windows exploateaza mesajele sistemului de
operare Windows.Pentru fiecare operatie executata in sistem,Windows emite
un mesaj specializat.Mesajele Windows sunt denumite dupa operatia care a
determinat emiterea mesajului la care se adauga prefixul WM_.Principalele
mesaje Windows sunt: WM_ACTIVATE,WM_CANCELMODE,WM_CHAR,WM_CHILDACTIVATE,
WM_CLEAR,WM_CLOSE,WM_COMMAND,WM_COPY,WM_CREATE,WM_DELETEITEM,WM_ENABLE,
WM_GETTEXT,WM_INITMENU,WM_KEYDOWN,WM_KEYUP,WM_LBUTTONDOWN,WM_LBUTTONUP,
WM_MENUSELECT,WM_MOUSEMOVE,WM_MOVE,WM_PAINT,WM_PASTE,WM_POWER,WM_QUIT,
WM_RBUTTONDOWN,WM_RBUTTONUP,WM_SIZE,WM_TIMER,WM_UNDO,WM_USER,WM_VSCROLL.
Lista completa este mult mai lunga.Manualul Help din C++ nu contine lista
acestor evenimente,dar puteti utiliza manualul Help din Borland Pascal,sau
orice alta sursa de documentare.Modul de interceptare si interpretare al
acestor mesaje este diferit de la un program la altul.In Pascal trebuie
sa scrieti o bucla continua in care sa fie preluate toate mesajele si sa
adaugati o conditie oarecare de selectie.In Delphi,eveniemetele sunt
rezolvate integral cu ajutorul utilitarului Object Inspector,iar in Visual
C++ evenimentele sunt ordonate sub forma unei grile denumita "message map".
In OWL,evenimentele sunt ordonate sub forma de tabel de corespondenta,
denumit RESPONSE_TABLE,in care la fiecare eveniment de tip Windows consi-
derat a fi semnificativ se asociaza o anumita functie de raspuns prin care
se declanseaza o anumita serie de operatii specifice.In acest fel,dintre
toate evenimentele Windows,se vor selecta doar cele care au semnificatie
pentru aplicatia respectiva.De exemplu,daca in exercitiul de mai sus exe-
cutati diverse deplasari ale indicatorului mouse,se vor declansa o serie
intreaga de mesaje de tip WM_MOUSEMOVE.Aceste mesaje vor fi ignorate de
catre aplicatie.Singurele mesaje cu semnificatie sunt WM_LBUTTONDOWN si
respectiv WM_RBUTTONDOWN,adica cele care au fost incluse in RESPONSE_TABLE
Pentru fiecare astfel de evenimet,trebuie sa fie definita o functie
de raspuns la eveniment si un macro de identificare a evenimentului.Prin
conventie,functia de raspuns la evenimet are acelasi nume ca si mesajul
Windows corespunzator,la care se adauga si prefixul "Ev".Exemplu: functia
care raspunde la mesajul WM_PAINT va fi denumita EvPaint().Dupa prefix,
prima litera din numele mesajului va fi scrisa cu majuscula,iar restul
vor fi scrise cu litere mici.
-62-
Pentru identificarea fiecarui mesaj,se va defini un macro specializat.
Numele acestui macro va fi format din numele mesajului,la care se va
adauga si prefixul "EV_".In acest caz toate literele vor fi scrise cu
majuscule.Exemplu: pentru mesajul WM_PAINT macroul de identificare va fi
EV_WM_PAINT.
Asadar,pentru fiecare mesaj Windows se poate scrie un macro care il
identifica si o functie care executa o serie de comenzi in momentul in
care mesajul a fost receptionat.
Editarea tabelei de raspuns la evenimentele Windows se face in patru
etape succesive:
1.Se declara tabela cu: DECLARE_RESPONSE_TABLE(numele clasei)
2.Definitia incepe cu: DEFINE_RESPONSE_TABLEx(clasa,clase receptive)
3.Se introduc macrourile de identificare a mesajelor (gen EV_WM_PAINT)
4.Se termina definitia tebelei cu: END_RESPONSE_TABLE
In etapa a doua,x reprezinta numarul de parametri,adica numarul de clase
care vor receptiona mesajul respectiv.Primul paramatru este clasa in care
este definit tabelul de raspunsuri,iar cel de al doilea parametru este
clasa care va receptiona mesajul.In exemplu,tabelul este definit in Fer1,
iar mesajul va fi receptionat de catre TWindow.In acest caz,exista o
singura clasa receptiva,adica un singur parametru,astfel incat definitia
va fi: DEFINE_RESPONSE_TABLE1(Fer1,TWindow).In cazul in care ar fi
existat si o alta clasa,in care exista o tabela de raspuns si in care se
vor receptiona mesajele,de exemplu o fereastra denumita TWindow2,definitia
ar fi fost de genul: DEFINE_RESPONSE_TABLE2(Fer1,TWindow,Twindow2).
Asadar,pentru fiecare mesaj exista o functie de raspuns si un macro de
identificare.In exemplu,daca se apasa butonul mouse stang,sistemul de
operare Windows va emite un mesaj de tip WM_LBUTTONDOWN.Acest mesaj va fi
interceptat si identificat de catre macroul EV_WM_LBUTTONDOWN,care va
declansa automat functia de raspuns EvLButtonDown().
Practic tabela de raspunsuri tine locul unei proceduri in care toate
mesajele emise de sistemul Windows sunt receptionate si filtrate prin
macrourile definite.Daca un mesaj corespunde cu macro-ul,se va declansa
automat functia corespunzatoare.
Prin acest mecanism,puteti programa orice fel de suita de algoritmi de
raspuns autoamt la un eveniment oarecare.Observati faptul ca un singur
mesaj Windows poate declansa simultan mai multe functii de raspuns,in
cazul in care exista mai multe clase(obiecte) care asteapta evenimentul
respectiv.De exemplu,o simpla apasare de buton poate declansa o serie
intreaga de functii de raspuns.Reciproc,este posibil ca raspunsul unei
anumite functii sa nu poata fi declansat decat in urma unei combinatii de
mesaje Windows(fiecare mesaj activeaza o functie care concura cu alte
functii pentru a forma raspunsul final).
Ca rezultat,fata de alte programe,OWL permite o interpretare extrem
de discriminativa a mesajelor Windows,fara riscul de a se declansa si
"raspunsuri accidentale".
Alegeti cu atentie mesajul Windows utilizat pentru declansarea unei
anumite functii.Exista si mesaje nediscriminative,care pot fi eliberate
de catre mai multe evenimente disticte.Daca RESPONSE_TABLE este mai ampla,
este bine sa faceti si o mica schema cu fiecare functie de raspuns si cu
fiecare macro care identifica mesajul,astfel incat sa nu existe mesaje
incrucisate sau macro-uri fara functie de raspuns.
-63-
Tot o tabela de comenzi se utilizeaza si pentru a monitoriza optiunile
unui meniu:
EXEMPLU: (vezi si OWL_ABC \ owl4 )
Deschideti un proiect nou,iar in fila .cpp introduceti un text de genul:
#include
#include
#include
#include
#include
#include
class Fer1 : public TApplication {
public:
Fer1() : TApplication("Editor:"){};
protected:
void InitMainWindow();
void CmFileNew();
void CmFileopen();
DECLARE_RESPONSE_TABLE(Fer1); };
DEFINE_RESPONSE_TABLE1(Fer1,TApplication)
EV_COMMAND(CM_FILENEW,CmFileNew),
EV_COMMAND(CM_FILEOPEN,CmFileOpen);
END_RESPONSE_TABLE;
void
Fer1::InitMainWindow()
{
MainWindow = new TFrameWindow(0,Name,new TEditFile);
MainWindow -> AssignMenu(IDM_EDITFILE);
MainWindow ->Attr.AccelTable = IDA_EDITFILE;
MainWindow ->SetIcon(this,201);
};
void Fer1::CmFileNew()
{
TEditFile* fila=TYPESAFE_DOWNCAST(MainWindow->GetClientWindow(),TEditFile);
CHECK(fila);
fila->NewFile();
};
void Fer1::CmFileOpen()
{
TEditFile* fila=TYPESAFE_DOWNCAST(MainWindow->GetClientWindow(),TEditFile);
CHECK(fila);
fila->Open();
};
int
OwlMain(int,char* [])
{
return Fer1().Run();
}
Pentru definitia meniului propriu zis,este necesara o fila de resurse
de tip .rc.Executati un click de mouse drept si stergeti din proiect fila
.def si fila .rc cu optiunea DeleteNode.Deschideti o fila noua(din File,cu
New si TextEdit) si introduceti urmatorul text:
-64-
#ifndef WORCKSHOP_INVOKED
#include
#endif
#include
#include
#include
Salvati fila cu numele de owl4.rc,apoi includeti fila in proiect cu
Add Node.Compilati,construiti si link-ati proiectul,apoi executati apli-
catia.Programul de mai sus,deschide un editor de text.Puteti deschide sau
edita orice fila de tip ASCI.
Pentru exemplul de mai sus,am ales un meniu gata definit in filele
editfile.rc si editfile.rh.In directorul INCLUDE\OWL exista mai multe
astfel de file cu extensia .rc si .rh.Puteti utiliza aceste file pentru
a utiliza meniurile predefinite.In program,meniul se incarca cu comanda
AssignMenu().
Pentru a atribui cate o functie la fiecare optiune din meniu,se va
declara si defini o tabela de raspunsuri.Toate optiunile exploateaza
mesajul Windows WM_COMMAND,la care se adauga cate o comanda specifica
pentru fiecare optiune.Numele comenzii se scrie cu majuscule si se adauga
prefixul "CM_".De exemplu,pentru FileOpen comanda va fi: CM_FILEOPEN.
Pentru fiecare comanda se va asocia si o functie de raspuns care va
executa o serie de operatii,in momentul in care se receptioneaza mesajul
WM_COMMAND + comanda specifica (Exemplu: WM_COMMAND + CM_FILEOPEN).Functia
va avea acelasi nume cu comanda optiunii + prefixul "Cm".Prima litera din
mumele functiei se va scrie cu litera mare (majuscula) iar restul litere-
lor se vor scrie cu litere mici.Exemplu: pentru comanda CM_FILEOPEN se
va utiliza functia de raspuns CmFileopen().In definitia tabelei de raspuns
fiecare astfel de pereche comanda/functie de raspuns va fi introdusa cu
o formula formata din prefixul EV_COMMAND + (comanda,functia).De exemplu,
pentru comanda CM_FILEOPEN si functia CmFileOpen() se va utiliza formula:
EV_COMMAND(CM_FILEOPEN,CmFileOpen)
Functia de raspuns trebuie sa fie de tip void (fara parametri).Nu este
absolut necesar,dar se prefera ca functiile de raspuns sa fie declarate
cu specificatorul "protected:",pentru a nu avea vizibilitate si in afara
clasei in care au fost declarate (se evita coruperea datelor).
Pentru a stabili un punct de intrare prioritar in tabela de raspunsuri
la mesaje,se poate utiliza o formula de genul: EV_COMMAND_ENABLE().In
acest caz,punctul de intrare respectiv va avea prioritate fata de cele-
lalte si va fi selectat implict la initializarea obiectului.De exemplu,
daca o bara de meniu contine mai multe optiuni,se poate utiliza aceasta
formula pentru ca una dintre optiuni sa fie selectata automat in momentul
constructiei obiectului respectiv.
Puteti utiliza exemplul owl4 pentru a deschide orice fila de tip text.
Alegeti optiunea File/Open iar pentru Files of type selectati "All Files"
si apoi deschideti orice fila de pe disc (preferabil cu extensia .txt).
Pentru a utiliza un meniu personalizat,se procedeaza in mod similar,dar
in fila de resurse va trebui sa definiti toate comenzile si sa introduceti
definitia meniului.Puteti utiliza si meniuri care au fost editate sub
forma de file de resurse,dar in alte programe sau limbaje de programare{
De exemplu : resurse Visual C++,resurse Pascal,resurse Delphi etc.).
Pentru a realiza un meniu grafic,puteti utiliza un program de genul:
-65-
EXEMPLU: (vezi si OWL_ABC \ owl5 )
Fila .cpp:
#include
#include
#include
#include
#define CM_PATRAT 201
#define CM_CERC 202
class Fer1 : public TWindow {
public:
Fer1();
protected:
void CmPatrat();
void CmCerc();
DECLARE_RESPONSE_TABLE(Fer1); };
DEFINE_RESPONSE_TABLE1(Fer1,TWindow)
EV_COMMAND(CM_PATRAT,CmPatrat),
EV_COMMAND(CM_CERC,CmCerc),
END_RESPONSE_TABLE;
Fer1::Fer1():TWindow(0,0,0){};
void Fer1::CmPatrat()
{
TClientDC dc1(*this);
TPen pen1(RGB(250,0,0),10);
dc1.SelectObject(pen1);
dc1.Rectangle(50,50,200,200);
MessageBox("Patrat","text:",MB_OK);
}
void Fer1::CmCerc()
{
TClientDC dc2(*this);
TPen pen2(RGB(0,0,250),10);
dc2.SelectObject(pen2);
dc2.Ellipse(70,70,180,180);
MessageBox("Cerc","text:",MB_OK);
};
class Aplicatie1 : public TApplication {
public:
Aplicatie1() : TApplication(){};
void InitMainWindow();
};
void Aplicatie1::InitMainWindow()
{
MainWindow = new TFrameWindow(0,"Meniu 2",new Fer1);
GetMainWindow() -> AssignMenu("GRAFIC");
};
int OwlMain(int,chat* [])
{
return Aplicatie1().Run();
};
-66-
Eliminati fila .def cu DeleteNode.
Inlocuiti fila .rc cu urmatoarea fila:
#define CM_PATRAT 201
#define CM_CERC 202
#ifdef RC_INVOKED
GRAFIC MENU
{
POPUP "&DESEN"
{
MENUITEM "&Patrat", CM_PATRAT
MENUITEM "&Cerc", CM_CERC
};
};
#endif
Compilati,construiti proiectul,verificati legaturile cu Link,apoi execu-
tati aplicatia.Puteti utiliza cele doua optiuni ale meniului,pentru a
desena fie un patrat,fie un dreptunghi.Observati ca fata de exemplul owl3
am introdus si cate un obiect de tip TPen,pentru a putea modifica culoarea
si grosimea penitei de desenare.
In mod similar,puteti edita orice meniu.Puteti utiliza exemplul de
mai sus,sau orice alt exemplu functional,pentru a edita aplicatii moi.Nu
strica sa fiti putin "escroci" si sa efectuati doar operatiile necesare
pentru a transforma un exemplu anterior,dar numai dupa ce a-ti inteles
perfect modul de constructie pentru fiecare aplicatie.
In situatiile in care programul este editat "perfect" si totusi nu
functioneaza,trebuie reeditata fila .ide(fila proiect).Pentru acest scop,
deschideti un nou proiect,alegeti acceasi cale de acces si acelasi nume
pentru proiect,apoi suprascrieti proiectul.Proiectul nou deschis va
contine aceleasi file ca si proiectul anterior,dar va avea o fila .ide
noua.Compilati si construiti din nou,asigurati legaturile cu "Link" si
apoi executati aplicatia.
Pentru functiile grafice,regulile sunt aceleasi ca pentru API Windows,
dar sunt grupate intr-un singur obiect grafic,astfel incat sa fie cat mai
usor de apelat.Deschideti fila header si observati cu atentie
metodele obiectului TDC.Penita grafica este controlata de obiecte deri-
vate din clasa TPen,iar pensula(utilizata pentru a umple suprafetele)
este controlata de obiecte derivate din TBrush.Alte obiecte utile sunt
cele derivate din clasele TFont,TBitmap,TPallete,TIcon,TCursor,TRegion,
TDib,TMetaFilePict si TEnhMetaFilePict.
Pentru a putea utiliza un obiect de tip TPen,TBrush sau TFont se va
utiliza metoda SelectObject() iar pentru a reveni la valorile implicite
se pot utiliza functiile: RestorePen(),RestoreBrush(),RestoreFont()etc.
Pentru culoarea de fond se pot utiliza functiile: GetBkColor() si SetBk-
Color() iar pentru text GetTextColor() si SetTextColor(),etc.
Exista si o serie de functii care permit salvarea imaginilor grafice in
memoria clipboard si apoi utilizarea lor la nevoie,sau permit operatii
complexe cu metafile in care sunt arhivate datele necesare.Prin combinarea
acestor functii,se obtin efecte de animatie.Alte functii opereaza cu
resurse de tip Icon,Cursor,BitMap etc.
-67-
Unul dintre cele mai utilizate elemente ale unei interfete grafice este
butonul simplu.Obiectul de tip buton este definit in fila
si poate fi apelat ca un obiect oarecare.Pentru a crea oricare dintre
elementele interfetei trebuie apelat constructorul obiectului.Constructo-
rul poate fi apelat direct,sau cu ajutorul operatorului "new".
EXEMPLU: (vezi si OWL_ABC / owl6)
Deschideti un prooiect nou si introduceti in fila .cpp:
#include
#include
#include
#include
const uint16 ID_BUTTON = 101;
class Fer1 : public TWindow {
public:
Fer1();
protected:
void HandleButtonMsg();
DECLARE_RESPONSE_TABLE(Fer1);
};
DEFINE_RESPONSE_TABLE1(Fer1,TWindow)
EV_COMMAND(ID_BUTTON,HandleButtonMsg),
END_RESPONSE_TABLE;
Fer1::Fer1(): TWindow(0,0,0) {
new TButton(this,ID_BUTTON,"Buton 1",50,50,150,30,false);
};
void fer1::HandleButtonMsg()
{
TClientDC dc1(*this);
TBrush br1(RGB(0,250,0));
dc1.SelectObject(br1);
dc1.FillRect(100,100,200,200,br1);
MessageBox("Button1","text:",MB_OK);
};
class Aplicatie1 : public TApplication {
public:
Aplicatie1() : TApplication() {};
void InitMainWindow();
};
void Aplicatie1::InitMainWindow()
{
MainWindow = new TFrameWindow(0,"Test",new Fer1);
};
int OwlMain(int,char* [])
{
return Aplicatie1().Run();
};
Pentru controlul operatiilor declansate de apasarea butonului se declara
Dostları ilə paylaş: |
|
|