kategória | ||||||||||
|
||||||||||
|
||
Ebben a feladatban olyan egyszerű grafikai alkalmazást készítünk, melynek segítségével vonalas rajzokat, alakzatokat készíthetünk az egér bizonyos eseményeinek hatására. A programkészítés fő lépései a következők lesznek:
Az egérhez kapcsolódó események kezelése
Eszköztár készítése gyorsító gombokkal
Toll és ecset beállítás
Státuszsor készítése
Bitmap-re történő rajzolás
Grafika nyomtatása
Munka grafikus állományokkal
A vágólap grafikus tartalmának használata
Négy olyan egérhez kapcsolódó esemény van, amelyekre az alkalmazásban reagálhatunk. A következő három önálló esemény: egérgomb lenyomása , felengedése és az egér mozgatása. A negyedik, az egérrel történő kattintás azonban egy kicsit eltér az előzőektől, mert az bizonyos esetekben speciális billentyű kombináció eredményeként is generálható (pl. Enter leütése modális dialógusablakban). Ebben a feladatban csak az önálló egéreseményekkel foglalkozunk.
Az alkalmazásban az egér által kiváltott események hatására alakzatokat fogunk rajzolni: az egérgomb lenyomására kezdjük, felengedésére befejezzük a rajzot. A fix kiindulópont és a felengedés pillanatáig változó végp 111d34b ont között folyamatosan új és új alakzatokat kell rajzolni, az előző állapotokat pedig törölni kell. Elsőként egy szakaszt próbálunk megjeleníteni a fenti technikával. Később pedig más alakzatokat is.
A Delphi három önálló egéreseményének: (OnMouseDown, OnMouseMove és OnMouseUp) öt-öt paramétere van. Ezek a következők:
Paraméter Jelentés
Sender Az objektum, mely detektálta az eseményt.
Button A lenyomott egérgomb: mbLeft, mbMiddle, vagy mbRight.
Shift Speciális billentyűk állapotát adja vissza az esemény pillanatában: Alt, Ctrl és Shift billentyűk.
X, Y A pont koordináta, ahol az esemény történt.
A legtöbb esetben a koordináták értéke az elsődleges, de sokszor az egérgombokat is figyelni kell, hogy melyik generálta az eseményt.
Valahányszor a felhasználó lenyom egy egérgombot, akkor egy OnMouseDown esemény játszódik le. Ebben a feladatban a lenyomás hatására kezdjük majd el a rajzolást.
Azért, hogy vizsgálni tudjuk az eseménykezelőt, próbáljunk meg egy rövid szöveget kiírni a lenyomás helyszínén. Az X és Y paraméterek segítségével a TextOut metódust hívjuk meg a szöveg megjelenítésére:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Canvas.TextOut(X, Y, IntToStr(X)+', '+IntToStr(Y));
end;
Teszteljük a kódot.
A megoldandó feladatban az egérgomb lenyomása csak a szakasz kiinduló pontját azonosítja. Ezért elsőként módosítsuk az eseménykezelőt:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo(X, Y);
end;
Az OnMouseUp esemény akkor történik, amikor felengedjük az egérgombot.
A feladatban egy szakaszt jelenítünk meg a felengedést lekezelő eljárásban:
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Canvas.LineTo(X, Y);
end;
Futás során azonban csak akkor láthatjuk a szakaszokat, ha már felengedtük az egérgombot.
Az OnMouseMove esemény akkor történik, amikor a felhasználó mozgatja az egeret.
Készítsük el a következő eseménykezelőt az egér OnMouseMove eseményéhez:
procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Canvas.LineTo(X, Y);
end;
Ekkor azonban nem csak akkor készül rajz ha lenyomott az egérgomb, hanem az egér minden megmozdítása egy-egy rövid szakaszt eredményez. Kézenfekvő, hogy el kell tárolni egy változóban azt, hogy lehetséges-e a rajzolás.
A Drawing Boolean változót deklaráljuk a form public változói között.
Hasonlóan deklaráljuk az Origin-nak és a MovePt-nak nevezett pontokat is:
type
TForm1 = class(TForm)
procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormMouseMove(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
public
Drawing: Boolean;
Origin, MovePt: TPoint;
end;
Módosítsuk az eseménykezelőket az alábbiak szerint, majd teszteljük a programot:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Drawing := True;
Canvas.MoveTo(X, Y);
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin
Canvas.LineTo(X, Y);
Drawing := False;
end;
procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
Canvas.LineTo(X, Y);
end;
Habár most már csak az egérgomb lenyomása és felengedése között rajzolunk, az eredmény mégsem megfelelő, mert nem a kiinduló pontot köti össze a rajzunk az aktuális ponttal. Ennek az az oka, hogy a LineTo eseménykezelő folyamatosan módosítja az aktuális rajzpoziciót. Az Origin és a MovePt éppen ezért a kezdő és közbenső pontokat fogja azonosítani.
Állítsuk be az Origin változó értékét úgy, hogy a mouse-down esemény eltárolja a kívánt kezdőpontot és a mouse-up esemény innen kezdi majd a vonal húzását:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Drawing := True;
Canvas.MoveTo(X, Y);
Origin := Point(X, Y);
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
Drawing := False;
end;
procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
end;
A továbbiakban már csak az előzőleg kirajzolt szakaszt kell mindig törölnünk. Az előző szakasz végpontjának eltárolására használjuk a MovePt korábban már deklarált változót.
Állítsuk be a MovePt pontot a közbenső szakaszok végpontjának, így törölhetjük az előző szakaszt a MovePt és az Origin pontok ismeretében:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Drawing := True;
Canvas.MoveTo(X, Y);
Origin := Point(X, Y);
MovePt := Point(X, Y);
end;
procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
Canvas.Pen.Mode := pmNotXor; Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(MovePt.X, MovePt.Y);
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
end;
MovePt := Point(X, Y);
Canvas.Pen.Mode := pmCopy;
end;
A toll módjának pmNotXor-ra állítása biztosítja a pixelek folyamatos törlését ha nem háttérszínűek voltak azok, illetve beállítását ellenkező esetben. A pmCopy-ra való visszaállítás eredményezi, hogy az egérgomb felengedése után a toll kirajzolja az utolsó szakaszt.
A többi alakzatot is hasonló technikával kell majd kirajzolni. Ehhez azonban előbb lehetőséget kell biztosítani az alakzatok közötti választásra.
Az eszköztár (tool bar) egy panel, amely rendszerint a form tetején a menüsor alatt helyezkedik el és vezérlő eszközöket, többnyire gyorsító gombokat tartalmaz.
Az eszköztár elkészítése érdekében a következőket kell megoldani:
Helyezzünk egy Panel komponenst a form-ra.
Állítsuk be a panel Align tulajdonságát alTop-ra. Ennek a beállításnak a hatására a panel állandó magassága mellett a szélessége megegyezik folyamatosan a form kliensterületének a szélességével, ha átméretezzük az ablakot.
Helyezzünk el gyorsító gombokat és más vezérlő elemeket a panelra.
A mintafeladat megoldásához készítsünk elő egy eszköztárat egy panel komponens használatával. Töröljük a Caption tulajdonságát.
A későbbiekben fogjuk elhelyezni a gyorsító gombokat és újabb eszköztárakat is létre fogunk hozni.
Az eszköztárak készítéséhez a Delphi speciális gombokat (speed button) biztosít. A gyorsító gomboknak nem szokott felirata lenni, hanem csak egy kis grafika (glyph) jelenik meg rajtuk. A gyorsító gombnak háromféle funkciója lehet:
Szabályos nyomógombként funkcionálhat.
Ki - és bekapcsolhatóak, ha rákattintunk.
Rádiógombként is használhatóak.
Gyorsító gombok eszköztáron való alkalmazásakor négy feladatot kell megoldanunk:
A gyorsító gombot az eszköztárra kell helyeznünk.
Grafikát (glyph) kell hozzárendelnünk a gombhoz.
A kezdeti feltételeket be kell állítanunk.
Csoportosítani kell a gyorsító gombokat.
Helyezzünk hat gyorsító gombot az eszköztárra az alábbi ábra szerinti elrendezésben és változtassuk meg a nevüket, ahogy az jelezve van.
Az alapértelmezett magassága az eszköztárnak 41 pixel, a gyorsító gombnak 25. Ha a gombok Top tulajdonságát 8-ra állítjuk, akkor éppen középen helyezkednek el függőleges irányban a panelen.
Minden gyorsító gombon célszerű elhelyezni egy olyan grafikus ábrát, amely a gomb funkciójára utal. Ha egy képet rendelünk a gombhoz, akkor a gomb működése során jelzi, hogy a gomb benyomott-e vagy sem. Lehetőség van azonban arra, hogy különböző képeket rendeljünk a gomb különböző állapotaihoz. Általában tervezési időben rendelünk képet a gyorsító gombhoz, futási időben pedig a különböző képeket cserélhetjük.
A kép (glyph) hozzárendelése a gyorsító gombhoz a következő módon történik tervezési időben:
Kiválasztjuk a gombot
Az objektum felügyelőben a Glyph tulajdonság érték oszlopában duplán kattintunk.
A Delphi megnyitja a képszerkesztőt és a Load paranccsal tölthetünk be képet., amit majd az <OK> gombbal rendelhetjük a gyorsító gombhoz.
Készítsünk és/vagy rendeljünk az ábrának megfelelő képeket a gyorsító gombokhoz.
Ahhoz, hogy egy gyorsító gomb lenyomott állapotban jelenjék meg, állítsuk a Down tulajdonságát True-ra.
Mivel az elkészítendő alkalmazásban a vonal az alapértelmezett rajzolási alakzat, állítsuk a LineButton Down tulajdonságát True-ra.
A gyorsító gombok egy halmaza gyakran reprezentál egymást kölcsönösen kizáró választásokat. Ekkor a gombokat csoportba kell foglalni és ha a csoport valamelyik elemére kattintunk, kiválasztjuk azt, akkor a többi gomb kiemelt állapotban kell hogy megjelenjék. A csoportbasorolást a GroupIndex tulajdonság ugyanolyan értékre történő beállításával valósíthatjuk meg.
A rajzolási alakzatokat megjelenítő gombok kizáró választásokat testesítenek meg, ezért rendeljük a GroupIndex tulajdonságukhoz az 1 értéket.
Gyakran előforduló feladat, hogy olyan csoportban szereplő gombot kell készítenünk, mely más gomboktól függetlenül benyomható illetve kikapcsolható. Ezt a funkciót az AllowAllUp tulajdonság beállításával generálhatjuk. Ha ezt a tulajdonságot True-ra állítottuk, akkor minden a csoportban elhelyezkedő gombra is arra áll és lehetővé teszi azt, hogy mindig csak egy gomb legyen kiválasztott, vagy a kiválasztottságot meg tudjuk szüntetni.
Mind a tollhoz, mind az ecsethez tartozó gomb AllowAllUp property-jét állítsuk True-ra, majd rendeljünk a PenButton-hoz 2-es GroupIndex értéket, a BrushButton-hoz 3-t.
A grafikus programban folyamatosan tudnunk kell, hogy a felhasználó milyen rajzeszközt választott. Egy felsorolt típust deklarálunk erre a célra.
A form típus deklarációs részéhez adjuk a TDrawingTool típus deklarációját:
type
TDrawingTool = (dtLine, dtRectangle, dtEllipse, dtRoundRect);
TForm1 = class(TForm)
Megjegyzés: a Delphi konvenciói szerint a típusok deklarációját T-vel kezdjük, a hasonló konstansokat (pl. felsorolt típus elemei) pedig 2 karakteres előtaggal, (a dt jelentése: "drawing tool").
A form deklarációjához rendeljük a DrawingTool változót, amely az aktuális rajzolási eszközt fogja jelenteni.
public
Drawing: Boolean;
Origin, MovePt: TPoint;
DrawingTool: TDrawingTool;
end;
Mivel az objektumok mezői a zéró értékkel lesznek inicializálva, így a DrawingTool értéke indításkor dtLine lesz.
A rajzolási eszközök változtatásához készítsük el a következő eseménykezelőket, amelyek megváltoztatják a DrawingTool változó értékét annak megfelelően, hogy melyik gyorsító gombot nyomtuk meg.
procedure TForm1.LineButtonClick(Sender: TObject);
begin
DrawingTool := dtLine;
end;
procedure TForm1.RectangleButtonClick(Sender: TObject);
begin
DrawingTool := dtRectangle;
end;
procedure TForm1.EllipseButtonClick(Sender: TObject);
begin
DrawingTool := dtEllipse;
end;
procedure TForm1.RoundedRectButtonClick(Sender: TObject);
begin
DrawingTool := dtRoundRect;
end;
A rajzolási eszközök beállítása utáni lépés az lesz, hogy a legelsőként megírt vonalszakasz rajzolásához hasonló eseménykezelőket készítsünk különböző rajzeszközök esetében is.
A megfelelő alakzat kirajzolásához módosíthatnánk az eseménykezelőket az alábbiak szerint:
procedure TForm1.FormMouseUp(Sender: TObject);
begin
case DrawingTool of
dtLine:
begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y)
end;
dtRectangle:
Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
dtEllipse:
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
dtRoundRect:
Canvas.RoundRect(Origin.X, Origin.Y, X, Y, (Origin.X - X) div 2, (Origin.Y - Y) div 2); end;
Drawing := False;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
Canvas.Pen.Mode := pmNotXor;
case DrawingTool of
dtLine:
begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(MovePt.X, MovePt.Y);
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
end;
dtRectangle:
begin
Canvas.Rectangle(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
end;
dtEllipse:
begin
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
end;
dtRoundRect:
begin
Canvas.RoundRect(Origin.X, Origin.Y, X, Y, (Origin.X - X) div 2,
(Origin.Y - Y) div 2);
Canvas.RoundRect(Origin.X, Origin.Y, X, Y, (Origin.X - X) div 2,
(Origin.Y - Y) div 2);
end;
end;
MovePt := Point(X, Y);
end;
Canvas.Pen.Mode := pmCopy;
end;
Mivel azonban ismétlődő részek vannak a kódban, ezért deklaráljunk egy alakzatrajzoló eljárást és ezt hívjuk majd a fenti rutinok módosított változatában.
A form objektum deklaráció public részéhez írjuk be a következő DrawShape eljárást:
type TForm1 = class(TForm)
public
procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);
end;
Az implementation részben határozzuk meg a rutin működését:
procedure TForm1.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);
begin
with Canvas do
begin
Pen.Mode := AMode;
case DrawingTool of
dtLine:
begin
MoveTo(TopLeft.X, TopLeft.Y);
LineTo(BottomRight.X, BottomRight.Y);
end;
dtRectangle:
Rectangle(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
dtEllipse:
Ellipse(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
dtRoundRect:
RoundRect(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y,
(TopLeft.X - BottomRight.X) div 2, (TopLeft.Y - BottomRight.Y) div 2);
end;
end;
end;
Az eddigi eseménykezelőket pedig módosítsuk a DrawShape eljárás hívásával az alábbiak szerint:
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
DrawShape(Origin, Point(X, Y), pmCopy);
Drawing := False;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
DrawShape(Origin, MovePt, pmNotXor);
MovePt := Point(X, Y);
DrawShape(Origin, MovePt, pmNotXor);
end;
end;
A program fejlesztésének alábbi szakaszában a rajzolási színek és stílusok beállítása érdekében az alábbi tevékenységeket végezzük el:
Rejtett eszköztár elkészítése és annak be-, illetve kikapcsolása
A toll stílusának megváltoztatása
A toll színének módosítása
A toll vastagságának állítása
Az ecset stílusának módosítása
Az ecset színének szabályozása
Rejtett eszköztár készítéséhez a már megismert módszer szerint hozzunk létre egy eszköztárat (Ne felejtsük el a panel Align tulajdonságát alTop-ra állítani!) és állítsuk be Visible property-t False-ra.
Készítsünk egy PenBar és egy BrushBar nevű rejtett eszköztárakat, amint azt az alábbi ábra mutatja. A gyorsító gombokon kívül használjuk a következő komponenseket: ColorGrid, ScrollBar, és Label a PenBar esetében és ColorGrid a BrushBar estében
A komponensek beállítása a következő legyen:
Component Property Value
SolidPen Glyph SOLID.BMP
Down True
DashPen Glyph DASHED.BMP
DotPen Glyph DOTTED.BMP
DashDotPen Glyph DASHDOT.BMP
DashDotDotPen Glyph DASHDOT2.BMP
ClearPen Glyph CLEAR.BMP
PenColor BackgroundEnabled False
GridOrdering go8x2
Height 30
Top 5
Width 144
PenWidth LargeChange 10
Top 12
PenSize FocusControl PenWidth
Caption 1
Top 13
SolidBrush Glyph FSOLID.BMP
Down True
ClearBrush Glyph FCLEAR.BMP
HorizontalBrush Glyph FHORIZ.BMP
VerticalBrush Glyph FVERT.BMP
FDiagonalBrush Glyph FDIAG.BMP
BDiagonalBrush Glyph BDIAG.BMP
CrossBrush Glyph CROSS.BMP
DiagCrossBrush Glyph DCROSS.BMP
BrushColor BackgroundEnabled False
GridOrdering go8x2
Height 30
Top 5
Width 144
Ha több eszköztárat alkalmazunk egy programban, akkor előfordul, hogy bizonyos eszköztárakat rendre el akarunk rejteni, ki akarjuk kapcsolni azokat. (Előfordul, hogy ezeken az eszköztárakon egy-egy bezárás gomb is szerepel.)
Ebben az alkalmazásban a fő eszköztár toll és ecset gombjának beállításával fogjuk az imént elkészített eszköztárakat ki-, illetve bekapcsolni:
procedure TForm1.PenButtonClick(Sender: TObject);
begin
PenBar.Visible := PenButton.Down;
end;
procedure TForm1.BrushButtonClick(Sender: TObject);
begin
BrushBar.Visible := BrushButton.Down;
end;
A toll stílusa meghatározza, hogy milyen vonalat rajzolhatunk: tömör vonal, szaggatott vonal, pont-vonal, stb.
A feladatban egyetlen eseménykezelőt fogunk elkészíteni a lehetséges vonal beállításokhoz, és a Sender paraméter vizsgálatának függvényében rendeljük a megfelelő konstans értéket a toll stílusához.
Osszuk meg a következő eseménykezelőt a toll stílus gombjaihoz. Az eseménykezelő neve SetPenStyle legyen, amit természetesen az objektum felügyelő segítségével állítsunk be:
procedure TForm1.SetPenStyle(Sender: TObject);
begin
with Canvas.Pen do
begin
if Sender = SolidPen then Style := psSolid
else if Sender = DashPen then Style := psDash
else if Sender = DotPen then Style := psDot
else if Sender = DashDotPen then Style := psDashDot
else if Sender = DashDotDotPen then Style := psDashDotDot
else if Sender = ClearPen then Style := psClear;
end;
end;
A toll színének megváltoztatásához a toll Color tulajdonságát kell beállítani. A felhasználó a ColorGrid használatával fogja beállítani a színeket.
Készítsük el a következő eseménykezelőt a ColorGrid-en való kattintáshoz:
procedure TForm1.PenColorClick(Sender: TObject);
begin
Canvas.Pen.Color := PenColor.ForegroundColor;
end;
A toll vastagságának állításához a toll Width tulajdonságát kel állítani. A gördítősáv használatával ez a feladat egyszerűen megoldható.
Kezeljük a gördítősáv (scroll bar) OnChange eseményét a következők szerint:
procedure TForm1.PenWidthChange(Sender: TObject);
begin
Canvas.Pen.Width := PenWidth.Position;
PenSize.Caption := IntToStr(PenWidth.Position);
end;
Az ecset stílusa azt határozza meg, hogy milyen mintákat használhatunk az alakzatok kitöltéséhez. Az előre definiált konstansok segítségével speciális hatásokat érhetünk el: (bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross).
Válasszuk ki a nyolc ecset-stílus gombot és készítsük el a következő SetBrushStyle közös eseménykezelőt az OnClick kezelésre:
procedure TForm1.SetBrushStyle(Sender: TObject);
begin
with Canvas.Brush do
begin
if Sender = SolidBrush then Style := bsSolid
else if Sender = ClearBrush then Style := bsClear
else if Sender = HorizontalBrush then Style := bsHorizontal
else if Sender = VerticalBrush then Style := bsVertical
else if Sender = FDiagonalBrush then Style := bsFDiagonal
else if Sender = BDiagonalBrush then Style := bsBDiagonal
else if Sender = CrossBrush then Style := bsCross
else if Sender = DiagCrossBrush then Style := bsDiagCross;
end;
end;
Az ecset színe határozza meg az alakzat szinét.
Az ecset eszköztárán elhelyezkedő ColorGrid komponenshez készítsük el a következő eseménykezelőt:
procedure TForm1.BrushColorClick(Sender: TObject);
begin
Canvas.Brush.Color := BrushColor.ForegroundColor;
end;
A státusz sor az ablakok alján szokott megjelenni és rendszerint szövegek megjelenítésére alkalmazzák. Panel komponensek segítségével könnyen készíthetünk státusz sorokat.
Státusz sor készítése céljából adjunk egy panelt a form-ra, nevezzük StatusBar-nak és állítsuk be az Align tulajdonságát alBottom-ra. Töröljük a panel Caption mezejének tartalmát.
Helyezzünk két további panelt (OriginPanel és CurrentPanel) a státusz sorra. Az egyiket igazítsuk balra (alLeft), a másikat pedig a megmaradt kliens területhez (alClient). Állítsuk be a kívánt 3-D effektusokat a BevelInner és BorderWidth tulajdonságokkal, majd módosítsuk az alábbi eseménykezelőket:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Drawing := True;
Canvas.MoveTo(X, Y);
Origin := Point(X, Y);
MovePt := Origin;
OriginPanel.Caption := Format('Origin: (%d, %d)', [X, Y]);
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
DrawShape(Origin, MovePt, pmNotXor);
MovePt := Point(X, Y);
DrawShape(Origin, Point(X, Y), pmNotXor);
end;
CurrentPanel.Caption := Format('Current: (%d, %d)', [X, Y]);
end;
Bár gyakran előfordul, hogy direkt a form-ra rajzolunk, ennél jóval általánosabb, hogy egy alkalmazásban valamilyen bitmap-re kell rajzolnunk. A bitmap-ek nagyon hatékony lehetőséget biztosítanak olyan funkciókhoz, mint másolás, nyomtatás, mentés, stb. A bitmap természetesen eltérő méretű lehet, mint a form: lehet nagyobb, vagy kisebb. Egy gördítő box-ot (scroll box) helyezve a form-ra, és ebbe helyezve egy image komponenst, szinte tetszőleges méretű képet hatékonyan kezelhetünk, szükség esetén gördíthetünk..
Ebben az alkalmazásban az eszköztárak és a státusz sor közötti egész területet gördíthető részként fogjuk használni. Ezért helyezzünk egy scroll box komponenst a form-ra és állítsuk az Align tulajdonságát alClient-re, biztosítván azt, hogy a kép kitöltse szükség esetén a form teljes munkaterületét.
Az image control egy olyan komponens, amely lehetővé teszi, hogy bitmap, vagy metafile képet tartalmazzon. A méretét vagy kézzel, vagy futás közben állíthatjuk be.
Helyezzünk egy image control-t a form-ra úgy, hogy az a scroll box-ban helyezkedjék el. Állítsuk be az image tulajdonságait a következők szerint:
Tulajdonság Érték
Name Image
AutoSize True
Left 0
Top 0
Amikor egy image komponenst helyezünk a form-ra az még nem tartalmaz képet. Csak a kép "tartóját" határozza meg. Az image control Picture tulajdonságát állíthatjuk tervezési időben, ha az a célunk, hogy mindig ugyanazt a képet tartalmazza. Szabályozhatjuk azonban futási időben is, ha valamely háttértárolón elhelyezkedő képet kell megjeleníteni, vagy amennyiben rajzolni szeretnénk rá. Ekkor futási időben kell egy üres bitmap-et létrehoznunk.
Az alkalmazás indításakor egy üres bitmap-nek kell megjelennie. Ezért a form OnCreate eseménykezelőjében hozzunk létre egy bitmap objektumot és az image Picture.Graphic tulajdonságához rendeljük azt hozzá:
procedure TForm1.FormCreate(Sender: TObject);
var
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
Bitmap.Width := 200;
Bitmap.Height := 200;
Image.Picture.Graphic := Bitmap;
end;
A hozzárendeléssel az image komponens lesz a bitmap tulajdonosa és így nem kell majd nekünk felszabadítani a futtatás végén.
Ha most teszteljük az alkalmazást, akkor már egy a szükség szerint gőrdítősávokkal szabályozható rajzolási területünk van, a rajzolási tevékenységek azonban nem látszanak, mert az alkalmazás még a form-ra rajzol.
Két dolgot kell megoldanunk annak érdekében, hogy a bitmap-re rajzoljunk a form helyett. Használjuk az image control canvas-át a form canvas-a helyett és az egér eseménykezelőit is az image control-hoz kell, hogy rendeljük.
Cseréljük le a "Canvas " string minden előfordulását "Image.Canvas "-ra. majd az objektum felügyelőben az image control OnMouseDown eseményéhez rendeljük FormMouseDown eseménykezelőt. Hasonlóan járjunk el az OnMouseMove és az OnMouseUp események esetében is. Ha szeretnénk, akkor a form eseménykezelői közül eltávolíthatjuk a már feleslegessé vált fenti három eljárást.. (Mivel a form sosem fogja megkapni az eseményeket, így nem szükséges e módosítás).
Az alkalmazás vezérléséhez készítsük el a következő főmenüt.
Helyezzünk egy MainMenu komponenst a form-ra az alábbi beállításokkal:
&File &Edit
&New Cu&t
&Open... &Copy
&Save &Paste
Save &as...
- <hyphen>
E&xit
A File|Exit parancshoz (OnClick) írjuk meg a következő eseménykezelőt:
procedure TForm1.Exit1Click(Sender: TObject);
begin
Close;
end;
Amikor a menürendszert használjuk, akkor észrevehetjük, hogy bizonyos esetekben felesleges vonalak jelennek meg a rajzon miután a menüelemre kattintottunk. Ennek az az oka, hogy a Windows néha egy mouse-up üzenetet küld.
Módosítsuk az OnMouseUp eseménykezelőt, ellenőrizzük a Drawing változó beállítását rajzolás előtt:
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
DrawShape(Origin, Point(X, Y), pmCopy);
Drawing := False;
end;
end;
Grafikus képek kinyomtatása egyszerű feladat Delphi-ben. A Printers unit-ot soroljuk fel a form uses-ai között. E unitban vannak deklarálva a Printer objektum, amely rendelkezik canvas tulajdonsággal és a kinyomtatandó lapot reprezentálja. A grafikus kép kinyomtatása érdekében másoljuk a képet a Printer canvas-ára.
Ha a File menü Print elemére kattintunk, akkor a következő eljárás futtatásával nyomtathatjuk ki a képet:
procedure TForm1.Print1Click(Sender: TObject);
begin
with Printer do
begin
BeginDoc;
Canvas.Draw(0, 0, Image.Picture.Graphic);
EndDoc;
end;
end;
A feladat ezen részében az alábbiakat oldjuk meg:
Kép betöltése
Kép mentése
Kép helyettesítése
Helyezzünk egy-egy open-file, save-file dialog box-ot a form-ra. A CurrentFile string típusú változót pedig a form public változói közé vegyük fel. Ebben a változóban tároljuk majd az aktuális kép nevét.
Grafikus file betöltése érdekében használjuk az image control Picture objektumának LoadFromFile metódusát.
A File|Open menü OnClick eseményéhez készítsük el a következő eseménykezelőt:
procedure TForm1.Open1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
CurrentFile := OpenDialog1.FileName;
Image.Picture.LoadFromFile(CurrentFile);
end;
end;
A Delphi Picture objektuma különböző formátumokat biztosít, ha menteni akarunk. Mindehhez a SaveToFile metódust kell csak meghívnunk. Ezen eljárás paramétere a fájl neve. Ha egy új képet szeretnénk menteni, vagy egy meglévőt más néven szeretnénk tárolni, akkor lehetőséget kell biztosítani, hogy a felhasználó beállíthassa az állomány nevét.
A File|Save és File|Save As menükhöz készítsük el az alábbi kezelőket:
procedure TForm1.Save1Click(Sender: TObject);
begin
if CurrentFile <> '' then
Image.Picture.SaveToFile(CurrentFile)
else
SaveAs1Click(Sender);
end;
procedure TForm1.SaveAs1Click(Sender: TObject);
begin
if SaveDialog1.Execute then
begin
CurrentFile := SaveDialog1.FileName;
Save1Click(Sender);
end;
end;
Ha egy image control Picture objektumához egy új grafikát rendelünk, akkor a régi grafika helyettesítődik. A helyettesítés előtt biztosítani kell, hogy a felhasználó beállíthassa a kép alapvető méreteit, vagy valamilyen alapértelmezett méreteket használhat. Ehhez készítsük el az alábbi form-ot, a hozzátartozó unit-ot nevezzük BMPDlg-nak, a form-ot pedig NewBmpForm-nak. Az edit box-okat az ábrán látható nevekkel azonosítsuk.
Adjuk a BMPDlg unit-ot a projektünkhöz és hivatkozzunk a főform uses részben a BMPDlg unit-ra is.
Ezután írjuk meg a következő eseménykezelőt a File|New parancs OnClick eseményéhez:
procedure TForm1.New1Click(Sender: TObject);
var
Bitmap: TBitmap;
begin
with NewBMPForm do
begin
ActiveControl := WidthEdit;
WidthEdit.Text := IntToStr(Image.Picture.Graphic.Width);
HeightEdit.Text := IntToStr(Image.Picture.Graphic.Height);
if ShowModal <> idCancel then
begin
Bitmap := TBitmap.Create;
Bitmap.Width := StrToInt(WidthEdit.Text);
Bitmap.Height := StrToInt(HeightEdit.Text);
Image.Picture.Graphic := Bitmap;
CurrentFile := '';
end;
end;
end;
Megjegyzés: Ha egy új bitmap-et rendelünk a Graphic tulajdonsághoz, akkor automatikusan lebomlik a régi bitmap és az új tulajdonosa lesz a Picture objektum.
A Windows Clipboard-ját használhatjuk alkalmazások közötti adatcserére grafikák esetében is. A Delphi Clipboard objektuma egyszerű kezelési lehetőséget biztosít.
A ClipBrd unit-ot soroljuk fel a uses részben.
A vágólapra másoláshoz rendeljük a képet a Clipboard objektum Assign metódusával a vágólaphoz.
Az alkalmazásban az Edit|Copy menün történő kattintásra reagáljunk a következő eljárással:
procedure TForm1.Copy1Click(Sender: TObject);
begin
Clipboard.Assign(Image.Picture);
end;
A kivágás hasonló a másoláshoz, de törölni kell a grafikát a forrásról, például a rajzolási terület fehérre festésével.
Az Edit|Cut menü OnClick eseményéhez rendeljük az alábbi eseménykezelőt:
procedure TForm1.Cut1Click(Sender: TObject);
var
ARect: TRect;
begin
Copy1Click(Sender);
with Image.Canvas do
begin
CopyMode := cmWhiteness;
ARect := Rect(0, 0, Image.Width, Image.Height);
CopyRect(ARect, Image.Canvas, ARect);
CopyMode := cmSrcCopy;
end;
end;
Ha a Windows vágólap bitmap grafikát tartalmaz, akkor beilleszthetjük azt bármely image objektumba. Elsőként hívjuk meg a Clipboard HasFormat metódusát, annak leellenőrzésére, hogy grafika van-e a vágólapon. A HasFormat Boolean értékű függvény és True-val tér vissza, ha a vágólap tartalma olyan formátumú, mint amit a paraméterben átadtunk a függvénynek. Ezután egyszerűen hozzárendelhetjük a vágólap tartalmát a bitmap-hez.
A Clipboard tartalmát az Edit|Paste menün való kattintás hatására fogjuk beilleszteni:
procedure TForm1.PasteButtonClick(Sender: TObject);
var
Bitmap: TBitmap;
begin
if Clipboard.HasFormat(CF_BITMAP) then
try
Bitmap.Assign(Clipboard);
Image.Canvas.Draw(0, 0, Bitmap);
finally
Bitmap.Free;
end;
end;
end;
Találat: 1750