Práca s myšou

Krátke opakovanie - čo vieme o udalostiach

Udalosť (anglicky event) ovplyvňuje ďalší beh programu - príklady udalostí:

* kliknutie na tlačidlo - naše programy čosi vykonali pri stlačení tlačidla
* pohyb myšou (naučíme sa dnes)
* stlačenie tlačidla na klávesnici.

Okrem kliknutia vie tlačidlo reagovať aj na iné udalosti:


Zoznam udalostí, na ktoré dokáže komponent reagovať sa zobrazuje na záložke Events v okne Inšpektora.

Všimnite si, že:

* každá udalosť má svoj názov (v ľavom stĺpiku) - napríklad OnClick
* vedľa sa nachádza prázdne políčko alebo meno funkcie, ktorá sa vykoná, keď udalosť nastane - napríklad, pri kliknutí na tlačidlo sa vykoná "formulárová" funkcia Button1Click
* názov funkcie môžeme v Inšpektore zmeniť.

Príklad, v ktorom využijeme nový komponent - posuvnú lištu (ScrollBar, nachádza sa na záložke Standart):

* umožňuje nastavovať číselné hodnoty;
* posuvná lišta má pre nás niekoľko zaujímavých vlastností:
o Min ... najmenšia hodnota (minimálnu hodnotu necháme 0)
o Max ... najväčšia hodnota, akú sa bude dať nastaviť (Max zmeníme na 255)
o Position ... hodnota, ktorá je na posuvnej lište práve nastavená.

Keď počas behu programu zmeníme hodnotu na posuvnej lište, vznikne s názvom udalosť OnChange (pri zmene):


Názov funkcie, ktorá sa vykonáva pri vzniku udalosti OnChange, môžeme vymyslieť sami alebo, ak dvojklikneme myšou do prázdneho políčka, C++Builder vymyslí vhodný názov funkcie.

V okne s programom vznikne funkcia - dopíšeme jej telo:

void __fastcall TForm1::ScrollBar1Change(TObject *Sender)
{
TCanvas * g=Image1->Canvas;
g->Brush->Color=TColor(RGB(ScrollB ar1->Position, 0, 0));
g->Rectangle(0, 0, Image1->Width, Image1->Height);
}

Môžeme použiť viacero posuvných líšt, ktorými budeme nastavovať červenú, zelenú a modrú zložku farby:


Do formulára vložíme ďalšie dve posuvné lišty. Aj im nastavíme vlastnosť Max na hodnotu 255.

Všetky tri posuvné lišty nastavíme tak, aby sa pri zmene hociktorej lišty volala funkcia ScrollBarChange (v Inšpektore treba nastaviť všetkým trom lištám udalosť OnChange na hodnotu ScrollBarChange):

void __fastcall TForm1::ScrollBarChange(TObject *Sender)
{
TCanvas * g=Image1->Canvas;
g->Brush->Color=TColor(RGB(
ScrollBar1->Position, // červená zložka
ScrollBar2->Position, // zelená zložka
ScrollBar3->Position)); // modrá zložka
g->Rectangle(0, 0, Image1->Width, Image1->Height);
}


Udalosti myši

Udalosti, ktoré súvisia s myškou:

* OnMouseDown ... vznikne pri stlačení tlačidla myši
* OnMouseMove ... vznikne pri pohybe myši
* OnMouseUp ... vznikne pri pustení tlačidla myši

Vďaka mechanizmu udalostí sa s myšou pracuje elegantne - vieme zistiť:

* že nastal pohyb myšou
* ktoré tlačidlo myši bolo stlačené alebo pustené
* aktuálnu polohu myši

Vytvoríme jednoduchý kresliaci program:

* do formulára obrázok Image1
* v Inšpektore zobrazíme udalosti Image1
* obrázku Image1 nastavíme udalosť OnMouseMove (pri pohybe myši) tak, aby sa volala funkcia:

void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{

}

Táto funkcia sa zavolá vždy, keď pohýbeme myšou ponad obrázok Image1 (inak udalosť nevzniká). Funkcia má aj niekoľko parametrov:

* X, Y určujú polohu myši nad obrázkom Image1 (X==0, Y==0 v ľavom hornom rohu)
* Shift informuje o tom, ktoré tlačidlá myši sú stlačené.

Doplníme telo tejto funkcie tak, aby sa pri pohybe myši kreslil malý krúžok:
void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
TCanvas * g=Image1->Canvas;
g->Ellipse(X-5, Y-5, X+5, Y+5);
}

Program upravíme tak, aby sa kreslilo iba vtedy, keď je stlačené ľavé tlačidlo myši:
void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
TCanvas * g=Image1->Canvas;
if (Shift.Contains(ssLeft)) g->Ellipse(X-5, Y-5, X+5, Y+5);
}

Testom: Shift.Contains(ssLeft) zistíme, či je stlačené ľavé tlačidlo myši.


Kresliaci program

Namiesto krúžkov budeme jednotlivé pozície myšky postupne spájať čiarou:

* stlačení tlačidla myši (udalosť OnMouseDown) nastavíme grafické pero (príkaz MoveTo) na začiatok čiary
* pri pohybe myši (udalosť OnMouseMove) nakreslíme z predchádzajúceho bodu úsečku (príkaz LineTo).

void __fastcall TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
TCanvas * g=Image1->Canvas;
g->MoveTo(X, Y);
}

void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
TCanvas * g=Image1->Canvas;
if (Shift.Contains(ssLeft)) g->LineTo(X, Y);
}

Program vylepšíme tak, aby sme mohli meniť farbu čiary - vytvoríme jednoduchú paletu farieb:


V okne sa nachádzaj aj druhý obrázok Image2, ktorý zobrazuje paletu farieb.

Farbu z palety budeme vyberať tak, že sa myšou klikne do obrázka Image2 (treba obslúžiť udalosť OnMouseDown pre Image2). Paletu farieb môžeme nakresliť ako obrázok v niektorom kresliacom programe (Paint, Skicár, LogoMotion) a nahrať zo súboru do komponentu Image2 (vlastnosť Picture - v Inšpektore treba kliknúť na ). Alebo ju môžeme po spustení programu nakresliť programovo - ako náhodne zafarbené štvorčeky:
TCanvas *g;
TCanvas *f;

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
int x=0;
g=Image1->Canvas;
f=Image2->Canvas;
while (x<Image2->Width) {
f->Brush->Color=TColor(RGB(random( 256), random(256), random(256)));
f->Rectangle(x, 0, x+16, 16);
x=x+16;
}
}

//-------------------------------------- -------------------------------------

void __fastcall TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
g->MoveTo(X, Y);
}

void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if (Shift.Contains(ssLeft)) g->LineTo(X, Y);
}

void __fastcall TForm1::Image2MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
g->Pen->Color=f->Pixels[X][Y];
}

Zápisom f->Pixels[X][Y] zistíme farbu bodu so súradnicami X, Y v obrázku Image2.


Kreslenie gumených čiar

Kreslenie gumených čiar:

* stlačením tlačidla myši určíme začiatok úsečky;
* ťahaním myšou so stlačeným tlačidlom určujeme druhý koniec úsečky;
* pustením tlačidla sa kreslenie ukončí.

Čiaru budeme počas ťahania a pri každej zmene polohy myši prekresľovať:

* zmažeme nakreslenú čiaru - prekreslíme ju bielou farbou;
* nakreslíme čiernu čiaru s novými koncovými súradnicami.

int ZacX, ZacY, KonX, KonY;

void __fastcall TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
ZacX=X;
ZacY=Y;
KonX=X;
KonY=Y;
}

void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if (!Shift.Contains(ssLeft)) return;
g->Pen->Color=clWhite;
g->MoveTo(ZacX, ZacY);
g->LineTo(KonX, KonY);
KonX=X;
KonY=Y;
g->Pen->Color=clSilver;
g->MoveTo(ZacX, ZacY);
g->LineTo(KonX, KonY);
}

void __fastcall TForm1::Image1MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
g->Pen->Color=clBlack;
g->MoveTo(ZacX, ZacY);
g->LineTo(KonX, KonY);
}

Náš program nebude úplne dokonalý - pri vykresľovaní gumenej čiary sa budú nakreslené časti obrázka premazávať bielou farbou. Porozmýšľajte, ako by ste tento problém vyriešili.