[Grafika] [WebTip] [Fotografování] [Galerie] [MujMac] [Printing]
  Redakce: info (at) builder.cz   Inzerce: reklama (at) grafika.cz
Diskuzní fóra
.Net (68471)
ASP (1591)
ActiveX (168)
Allegro (136)
Assembler (3926)
C++ Builder (23160)
C/C++ (44499)
Databáze (30680)
Delphi (78808)
DelphiX (1655)
DirectX (1464)
Java (39508)
JavaScript (12598)
Matematické programy (2178)
OOP a UML (732)
OpenGL (6920)
Php (65224)
PowerBuilder (464)
Problémy a algoritmy (10473)
Programování v Linuxu (2000)
Právo a programování (3384)
Python (1353)
Ruby (136)
Visual Basic (12078)
Visual C++ (12956)
Wap (56)
Web (10895)
Web servery (5549)
Win32 (13553)
Windows CE (865)
XML/XSL (1860)
Textová inzerce
Služby Builder.cz
  • Bazar - koupím(0)
  • Bazar - prodám(0)
  • Hledám práci(0)
  • Nabízíme práci(0)
  • Projekty(0)
  • Tvorba her v DelphiX - 2. díl
    Tvorba her pod Delphi. Tentokrát detailní rozbor kreslení a práce s grafikou pod DelphiX.
    Tvorba her v DelphiX
    Předchozí díl: Tvorba her v DirectX v Delphi - 1. díl

    Následující díl: Tvorba her v DelphiX - 3. díl
    Autor: Václav Krejčí
    Rubrika: Delphi
    Publikováno: 09.10. 2000
     Tisk článku
    Poslat odkaz emailem
     

    V dnešním díle si ukážeme, jak pracovat v DelphiX s  canvasem, který je podobný canvasu ve windows, ale nabízí i nějaké ty specialitky. Nakonec vytvoříme ukázkový program, který sice nebude mít s hrou nic společného, ale zato bude plně využívat DirectX. Tak se do toho dáme.

    V delphiX kreslíme na povrch, který nazýváme surface. Kde se tedy vzal onen canvas? Jedná se o jednu z vlastností surface, a přistupujeme k němu pomocí DXDraw.surface.canvas a je velice podobný jako canvas ve windows (vzpomeňme na Form.canvas, nebo Image.picture.Bitmap.canvas). Pomocí něj můžeme kreslit jednoduché obrazce jako např. čtverce, obdélníky, kruhy, elipsy, polygony, kruhové výřezy, čáry, bezierovy křivky nebo třeba vyplňovat pixely. A právě s pixely začneme. Ještě jedna užitečná rada - pokud kreslíme na canvas, musíme ho nakonec uvolnit procedurou Release, jinak se nám program zhroutí !!!

    Pixel po pixelu...

    Jak každý asi ví, pixel je nejmenší částečka na monitoru, kterou můžeme vidět. Kolik je na obrazovce pixelů poznáme podle rozlišení obrazovky, takže např. při rozlišení 800x600 máme 800 pixelů na šířku a 600 na výšku. Celkově je to tedy 480 000 což je velice velké číslo, a proto je např. vyplňování obrazovky pixel po pixelu nevhodné, jelikož je to velice pomalé. Přístup po pixelu se hodí pouze pro vyplňování několika málo bodů, kdy určitému pixelu přiřadíme určitou barvu (např. Canvas.Pixels[10,20]:=clBlack vyplní bod x=10 a y=20 černou barvou). Ještě více se však hodí použití, pokud chceme získat barvu daného bodu, kdy postupujeme přesně obráceně - např. Form1.color:=DXDraw1.surface.canvas.pixels[20,20].

    Čáry a linky...

    Jako další máme čáry. Stejně jako všude kreslíme čáru procedurou LineTo(x,y), která kreslí čáru do bodu x,y. Odkud se bode čára kreslit určuje PenPos, a pokud tuto hodnotu chcete změnit, tak procedurou MoveTo(x,y). Kromě toho můžeme ještě měnit tloušťku čáry vlastností Canvas.Pen.Width, barvu vlastností Canvas.Pen.Color a styl vlastností Canvas.Pen.Style.

    Čtverce a obdélníky...

    Dále jsou tady čtverce a obdélníky. Kreslí se procedurou Rectangle(x1,y1,x2,y2), nebo pokud máme definovanou proměnnou typu TRect, můžeme vyžít Rectangle(Rect). Barvu, styl a šířku čáry můžeme měnit stejně jako u čar pomocí Canvas.Pen.Color,Style,Width... Výplň obdélníku se nastavuje ve vlastnosti Canvas.Brush a můžeme nastavit barvu (Color), styl (Style) a bitmapu (Bitmap), která má rozměry 8x8 pixelů.

    Kruhy a elipsy...

    Jelikož elipsy jsou hodně podobné obdélníkům (akorát že jsou kulaté), zmíním se o nich jen stručně. Kreslí se pomocí Ellipse(x1,y1,x2,y2), nebo Ellipse(Rect). Výplň a okraj elipsy se nastavuje stejně jako u obdélníků.

    Kulaté obdélníky...

    Teď si asi myslíte, že jsem se zbláznil, jelikož je něco jako kulatý čtverec ve světě normálním i počítačovém nemožné. Abych tedy uvedl věc na pravou míru -  mám na mysli obdélníky se zaoblenými rohy. V angličtině však toto nazývají RoundRect, což si někdo může přeložit jako... Ale k věci. Obdélníky se zaoblenými rohy kreslíme pomocí RoundRect(x1,y1,x2,y2,x3,y3). Proměnné x1,y1 a x2,y2 stejně jako u rectanglu určují hranice obdélníku a x3 a y3 určují, jak hodně bude obdélník zaoblený po ose x a y. Výsledek může vypadat např. takto (všimněte si, že po ose x je zaoblený méně než po ose y):

    Text...

    Jako další zde máme kreslení textu. To provedeme pomocí TextOut(x,y,text), kdy se na souřadnice x a y napíše text text. Vlastnosti fontu textu můžeme měnit v Canvas.Font, a to jméno fontu (Name), velikost (Size), styl (Style) a barvu (Color). S textem souvisí také dvě funkce TextHeight(Text) a TextWidth(Text), které vrací výšku (šířku) textu Text v pixelech.

    Polygon a Polyline...

    Jako poslední je zde polyline a polygon. Nejprve tedy Polyline. Jedná se o zjednodušení práce s čarami, abychom nemuseli při kreslení více čar pořád psát MoveTo a LineTo, nadefinujeme si proměnnou Points jako pole TPointů a poté nakreslíme Polyline pomocí Polyline(points). Pokud zadáme poslední bod stejný jako první, vznikne nám neuzavřený útvar. Naproti tomu polygon vytvoří vždy uzavřený útvar, i když poslední bod je jiný než první a vyplní jej nastavenou výplní (okraj a výplň opět měníme stejně jako u rectanglů). Pro kreslení polygonu použijeme Polygon(points).

    Praktická část:

    A konečně je zde již na začátku zmiňovaný program, ve kterém si odzkoušíme pár z výše uvedených věcí. Jedná se o to, že na povrch nakreslíme pár tlačítek, přes které pokud přejedeme myší dostanou focus a pokud myš stiskeme, tlačítko se stiskne. Nad toto nakreslíme také kurzor, ne však kopírováním obrázku kurzoru, ale kreslením polygonu. Zde je náhled na program:

    Vytvořte tedy nový projekt, Form1 přejmenujte na MainForm a na formulář přidejte komponentu DXDraw. Pokračujeme tím, že si definujeme proměnné. Do sekce public tedy přidáme následující kód:

    ClShadow,ClLight,ClNormal:TColor;
    ButtonStyle:array [0..5] of integer;
    MouseDown:boolean;
    Texty:array [0..5] of String;
    Recty:array [0..5] of TRect;

    Zde je vysvětlení jednotlivých položek: Proměnné ClShadow,ClLight a ClNormal jsou barvy, kterými budeme kreslit tlačítka. Označují normální barvu, barvu stínu a barvu světla. Dále je zde ButtonStyle, který určuje stav jednotlivých tlačítek. Pokud je 0, je tlačítko normální, při 1 má tlačítko focus a pokud je buttonStyle 2, je tlačítko stisknuté. Dále je zde proměnná MouseDown, která určuje, je-li stisknutá myš, pole Textů, ve kterém jsou uložený nápisy tlačítek a Recty, ve kterém jsou uloženy pozice jednotlivých tlačítek.

    Dále následuje kreslení kurzoru. Jak jsem již zmínil na začátku, budeme jej kreslit jako polygon, jelikož kurzor šipka je vlastně několik čar. Zde je obrázek, jak vypadá (oranžově jsou označeny body polygonu):

    Pro kreslení kurzoru si vytvoříme speciální proceduru, ve které si definujeme pole bodů pro polygon a pozici kurzoru typu TPoint. Funkcí GetCursorPos získáme pozice kurzoru, které pak převedeme pomocí ScreenToClient na pozici ve formuláři. Nadefinujeme si jednotlivé body polygonu a pak jej už jen nakreslíme. Zde je výpis procedury:

    Procedure DrawCursor; // kreslení kurzoru
    var CursorPos:Tpoint;
    Points: array [0..8] of TPoint;
    begin
    GetCursorPos(CursorPos);
    CursorPos:=MainForm.ScreenToClient(CursorPos);
    Points[0]:=Point(CursorPos.x,CursorPos.y);
    Points[1]:=Point(CursorPos.x+10,CursorPos.y+10);
    Points[2]:=Point(CursorPos.x+6,CursorPos.y+10);
    Points[3]:=Point(CursorPos.x+9,CursorPos.y+17);
    Points[4]:=Point(CursorPos.x+8,CursorPos.y+18);
    Points[5]:=Point(CursorPos.x+7,CursorPos.y+18);
    Points[6]:=Point(CursorPos.x+6,CursorPos.y+17);
    Points[7]:=Point(CursorPos.x+3,CursorPos.y+11);
    Points[8]:=Point(CursorPos.x,CursorPos.y+14);
    with MainForm.DXDraw1.Surface.Canvas do
    begin
    Pen.Color:=clBlack;
    Brush.Color:=clWhite;
    Brush.Style:=bsSolid;
    Polygon(Points);
    end;

    MainForm.DXDraw1.Surface.Canvas.release;
    end;

    Nyní zkuste přidat do procedury MainForm.OnCreate proc. ShowCursor(false); která zakáže zobrazování windowsovského kurzoru a na form přidejte komponentu DXTimer, ke které vytvořte proceduru OnTimer do které přidejte následující:

    procedure TMainForm.DXTimer1Timer(Sender: TObject; LagCount: Integer);
    var i:integer;
    begin
    // pokud nemůžeme na surface kreslit, tak pryč...
    if not DXDraw1.candraw then exit;

    // vymazání povrchu
    DXDraw1.Surface.Fill(0);

    // kreslení kurzoru
    DrawCursor;

    // a flip...
    DXdraw1.Flip;
    end;

    Projekt zkompilujte a spusťte pomocí F9 a pohněte myší - kurzor by se měl zobrazit. 

    To ale není ještě konec, jelikož my potřebujeme zobrazit tlačítka. K tomu, abychom je mohli kreslit, musíme vědět, jak vůbec vypadají. Zde je náhled:

    Vlevo nahoře jsou nakresleny jednotlivé barvy - světlá, normální a tmavá, dále vidíme tlačítko s focusem, normální tlačítko a stisknuté tlačítko. Celé toto budeme kreslit pomocí čtverců a čar. Vytvoříme si zase zvláštní proceduru, která již bude mít několik parametrů. Bude to x,y,width,height,style a text. V této proceduře budeme kreslit tlačítko podle stylu Style (0-normální,1-s focusem,2-stisknuté) široké Width a vysoké Height na pozici x,y. Navíc ještě budeme kreslit doprostřed text. Výpis celé procedury snad není ani třeba uvádět, jelikož je dost dlouhá, a v podstatě se v ní neustále opakuje MoveTo a LineTo.

    Nakonec stačí v proceduře OnCreate definovat bervy:

    ClShadow:=RGB(97,97,97);
    ClLiGht:=RGB(218,218,218);
    ClNormal:=RGB(171,171,171);

    A nastavení oblastí buttonů a textů buttonů:

    // nastavení oblastí
    for i:= 0 to 5 do
    begin
    Recty[i].Left:=10;
    Recty[i].Top:=30+ i * 35;
    Recty[i].Right:=Recty[i].Left+70;
    Recty[i].Bottom:=Recty[i].Top+30;
    end;

    // nastavení textů
    Texty[0]:='Tlačítko 0';
    Texty[1]:='Tlačítko 1';
    Texty[2]:='Tlačítko 2';
    Texty[3]:='Tlačítko 3';
    Texty[4]:='Tlačítko 4';
    Texty[5]:='Tlačítko 5';

    A do procedury DXTimer.OnTimer přidat kód, který zajistí zobrazení správné barvy pozadí a nakreslení tlačítek:

    // nakreslení barvy pozadí
    DXDraw1.Surface.Canvas.Brush.Color:=ClNormal;
    DXDraw1.Surface.Canvas.FillRect(rect(0,0,
    DXDraw1.surfacewidth,DXDraw1.surfaceHeight));
    DXDraw1.Surface.Canvas.Release;

    // kreslení tlačítka
    for i:= 0 to 5 do
    begin
    DrawButton(Recty[i].left,Recty[i].top,
    Recty[i].right-Recty[i].left,
    Recty[i].bottom-Recty[i].top,ButtonStyle[i],Texty[i]);
    end;

    A ještě přidat procedury, které zajistí, aby při pohybu myši nad tlačítko dostalo tlačítko focus a při stisku myši nad tlačítkem se tlačítko také stisklo:

    procedure TMainForm.DXDraw1MouseMove(Sender: TObject; Shift: TShiftState;
    X, Y: Integer);
    var i:integer;
    begin
    for i:=0 to 5 do
    begin
    if PtInRect(Recty[i],Point(x,y)) then
    begin
    ButtonStyle[i]:=1; // myč je nad tlačítkem -> tlačítko dostane focus
    if MouseDown then
    begin
    ButtonStyle[i]:=2; // myš je stisklá nad tlačítkem -> stisknout tlačítko
    end;
    end
    else
    ButtonStyle[i]:=0; // myš není nad tlačítkem -> zobrazit normální tlačítko
    end;
    end;

    procedure TMainForm.DXDraw1MouseDown(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
    begin
    MouseDown:=true;
    MainForm.DXDraw1MouseMove(nil,shift,x,y);  // volat proceduru OnMouseMove
    end;

    procedure TMainForm.DXDraw1MouseUp(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
    begin
    MouseDown:=false;   // myš již není stisknutá
    end;

    Nakonec projekt přeložte a spusťte a zkuste hýbnout myší nad jedno z tlačítek - mělo by dostat focus. Pokud tomu tak doopravdy je, gratuluji vám.

    Zde si můžete program stáhnout (200Kb)



    Hodnocení článku
    1 | 2 | 3 | 4 | 5
    Aktuální známka: 2.68
    (Počet známek: 5846)

    Komentáře k článku
    Jarda26.04.19:28Fce DrawButton
    Martin03.01.9:22SUPER!
    Mrakoplaš29.12.20:09Přímí přístup k paměti Canvas
    L*RĐ $@+@N30.08.18:15Odpověď: Přímý přístup k paměti Canvas
    Jan Hejda29.10.20:48Rychlé vykreslování
    Robert Vozdecky02.11.0:05RE: Rychlé vykreslování
    Honza18.10.9:24Jen tak dál
    iso13.10.22:01Super, ze konecne niekto napisal...
         





    info@builder.cz
    Vydává Grafika Publishing, s.r.o.
    Copyright (c) 1997-2002 Všechna práva vyhrazena