2013. február 3., vasárnap

OwnerDraw listbox

A minap arra gondoltam, hogy készítek egy programot, ami képes leellenőrizni fájlok MD5 ellenőrzőösszegét, illetve saját maga is képes lesz majd előállítani ellenőrző összeget. Első körben azt szeretettem volna megvalósítani, hogy egy pici (32x32 pixel) ikon jelenjen meg a listában, amiben kijelzi a program, hogy a fájl, amit ellenőrzött, az nem sérült e. Én egy Listbox komponenssel akartam megvalósítani a dolgot. Sajnos a Listbox alapban nem támogatja a képek ilyen formán való beszúrását, ezért kicsit utána kellett nézni az interneten, hogy miképpen valósítható meg a dolog.

Mint kiderült a komponens stílusát be lehet állítani lbOwnerDrawVariable típusra, és így már leprogramozható, hogy képek is kerüljenek a lista soraiba. Ehhez a Listbox két eseményét kellett megírjam. Az egyik az OnMeasureItem, amit lényegében csak arra használok, hogy beállítsam a lista sormagasságát. Illetve mivel egy ImageList is lett a Formra dobva, ebben ugyanis kényelmesebb az ikonokat tárolni, így ennek a magasságát vettem alapul a Listbox sormagasságának beállításához. A kód így alakult:

procedure TForm1.lbListaMeasureItem(Control: TWinControl; Index: Integer; var AHeight: Integer);
begin
  AHeight:=IMGL.Height+4;
end;


A másik esemény, az OnDrawItem, amely a kirajzolást végzi, egy hangyányit komplikáltabb, de ez sem veszélyes. Ami okozott egy kis meglepetést, hogy fel kellett vegyek egy külön változót az állapot tárolására a Listbox minden egyes sorához, mert ha ezt nem teszem, akkor minden egyes kirajzolásnál az utolsó beállított dizájn fog megjelenni a lista minden egyes során. Ami sajnos nem jó, lévén valahogy jelezni kell, ha valamelyik fájl MD5 ellenőrző összege nem egyezik meg a hasheket tartalmazó fájlban foglaltakkal. A kód ezért így alakult:

procedure TForm1.lbListaDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState);
var
  CenterText: integer;
begin
  with (Control as TListBox) do
  begin
    if fState[Index] then Canvas.Brush.Color:=$00D5FFD5;
    if not fState[Index] then Canvas.Brush.Color:=$00D5D5FF;

    Canvas.FillRect(ARect);

    if fState[index] then IMGL.Draw(Canvas,ARect.Left + 4, ARect.Top+4, 0)
    else if not fState[index] then IMGL.Draw(Canvas,ARect.Left + 4, ARect.Top+4, 1);

    CenterText:=(ARect.Bottom-ARect.Top-Canvas.TextHeight(Items[Index])) div 2;

    Canvas.TextOut(ARect.Left+IMGL.Width+8,ARect.Top+CenterText,Items.Strings[index]);
  end;
end;


Mint az látható a fState nevű tömb az, ami az egyes sorok állapotát tárolja és ennek függvényében van beállítva az egyes sorok háttérszíne (Canvas.Brush.Color), illetve az ImageList Draw eljárása is ennek függvényében rajzol ki más más ikont a lista sorainak elejére. A CenterText változóban kiszámoljuk, hogy mennyit kell majd hozzáadni a lista adott sorában a szöveg tetejéhez, hogy az középre essen. A szöveg kiírásáért a Canvas.TextOut sor felel.

A program természetesen még közel sincsen kész, ez csak amolyan "tech demo", hogy kipróbáljam, hogy mit lehet kihozni belőle. Kellemes dolog, hogy a Lazarus ilyesmire is képes és nem egy ördöngösség a megvalósítás.
Végezetül álljon itt egy rövid videó, hogy a "tech demo" hogy vizsgázott egy próba alkalmával (a youtube-on megtekinthető jobb minőségben is a videó).



Nincsenek megjegyzések:

Megjegyzés küldése