Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 30. - Změna fontu bublinkové nápovědy; Jméno procesoru; Kolik paměti využívá daný proces; Zarovnání prvků v ListBoxu na pravou stranu; Hledání prvků v ListView

Jan Šindelář - 20.2.2002

Změna fontu bublinkové nápovědy

V našem seriálu už jsme si kdysi ukazovali, že lze celkem snadno změnit většinu parametrů bublinkové nápovědy (Hint), jako je barva podkladu či jednotlivé časové intervaly, kdy se nápověda objeví. Poněkud jsme však zapomněli na samotný text nápovědy, takže si dnes ukážeme, jak změnit jeho font a velikost. Vytvoříme si na to vlastní proceduru, kterou poté použijeme v události OnCreate hlavního formuláře (nebo formuláře, ve kterém budete tento "vylepšený" hint chtít použít). Zde je tedy příslušný kód:

type
TNasHint = class(THintWindow)
  constructor Create(AOwner: TComponent); override;
end;

.
.
.

constructor TNasHint.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  with Canvas.Font do
  begin
    Name  := `Verdana`;
    Size  := Size + 15;
    Style := [fsBold, fsItalic];
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
HintWindowClass  := TMyHintWindow;
end;

V naší ukázce je pro názornost zvolena poněkud větší velikost fontu, což v opravdové aplikaci asi nepoužijeme. Jak vidíte, není problém použít tučné písmo či kurzívu (nebo obojí zároveň), takže si můžete vymyslet téměř libovolnou kombinaci. Když navíc změníte barvu samotné "bubliny", jak jsme se naučili hned v prvním dílu seriálu, dostane vaše aplikace velmi osobitý a netradiční vzhled. Je však dobré se vyvarovat počátečního nadšení a vždy volit vkusné a hlavně dobře čitelné kombinace. Tento tip totiž není ani tak o efektu (důležitá je funkčnost aplikace, i kdyby vypadala sebelépe), jako spíše o pomoci uživateli, neboť ne každý má tak dobré oči a je schopen běžnou bublinkovou nápovědu přečíst. Proto by asi bylo vhodné (pokud se rozhodnete tento tip použít) ponechat volbu parametrů textu spíše na uživateli samotném prostřednictvím nastavení.

Jméno procesoru

Opět jeden z velmi krátkých a jednoduchým tipů. Jméno procesoru si zjistíme velmi snadno ze systémového registru, proto nezapomeňte na použití knihovny Registry. Samotný kód je pouze jednoduché čtení údajů z registru, jak jsme jej používali již mnohokrát při podobných příležitostech, takže pro pravidelné čtenáře by možná stačilo uvést jen větev, kde se údaj nachází. Nicméně pro úplnost je zde celá funkce a použití:

uses Registry;
.
.
.

function CPUname: string;
var
  Reg: TRegistry;
begin
  CPUname := ``;
  Reg := TRegistry.Create;
  try
    Reg.RootKey := HKEY_LOCAL_MACHINE;
    if Reg.OpenKey(`\Hardware\Description\System\CentralProcessor\0`, False) then
      CPUname := Reg.ReadString(`Identifier`);
  finally
    Reg.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(CPUname);
end;

Kolik paměti využívá daný proces

Tento tip si sice můžete vyzkoušet pouze pod systémy NT/2000/XP (tedy vyzkoušet ho můžete pochopitelně i pod systémy 9x, ale fungovat to nebude), přesto se může hodit. Jak tedy zjistit, kolik paměti si pro svou činnost (nebo nečinnost) bere vaše aplikace? Použijeme k tomu opět funkce API a konkrétně knihovny psAPI. Samotný kód vypadá takto:

uses psAPI;

.
.
.

procedure TForm1.Button1Click(Sender: TObject);
var
  pmc: PPROCESS_MEMORY_COUNTERS;
  cb: Integer;
begin
  cb := SizeOf(_PROCESS_MEMORY_COUNTERS);
  GetMem(pmc, cb);
  pmc^.cb := cb;
  if GetProcessMemoryInfo(GetCurrentProcess(), pmc, cb) then
    ShowMessage(IntToStr(pmc^.WorkingSetSize) + ` Bytes`)
  else
    ShowMessage(`Nelze zjistit údaj o využití paměti`);
  FreeMem(pmc);
end;

Zarovnání prvků v ListBoxu na pravou stranu

Další z dnešních tipů bude opět vizuálního charakteru. Při běžné práci s komponentou typu ListBox jsou prvky zarovnány k levému okraji. Co když ale potřebujete jiné zarovnání, například na pravou stranu? I toho lze mírnou úpravou dosáhnout. Nejprve musíte změnit styl ListBoxu na typ lbOwnerDrawFixed. Tím pádem se o vykreslování již nestará systém automaticky, ale musíme mu trošku pomoci, a sice událostí OnDrawItem. Zde je tedy kód:

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
  l: Integer; 
  t: String;
begin
  with ListBox1 do
  begin
    Canvas.FillRect(Rect);
    t := Items[Index]; 
    l := Rect.Right - Canvas.TextWidth(t) - 1;
    Canvas.TextOut(l, Rect.Top, t);
  end;
end;

Jak vidíte ze zdrojového kódu (doufám), pro přesné umístění textu je rozhodující parametr l, který určuje právě horizontální polohu. Proč odečítáme číslo jedna? To proto, aby text nebyl "nalepený" přímo na okraji rámečku. Ačkoliv zas tak hrozně to nevypadá, rozdíl je minimální. Důležité však je, že právě pomocí tohoto parametru l můžete dosáhnout libovolného vlastního umístění textu, například jej můžete vycentrovat a podobně. To již ponechám na vaší fantazii a potřebách.

Hledání prvků v ListView

Často se můžeme setkat s úlohou najít v ListView, který obsahuje velké množství dat, prvek požadovaných vlastností. Budeme nyní hovořit o ListView v podobě vsReport, který patří asi k nejčastějším. Pokud hledáme pouze mezi "hlavními" prvky, můžeme využít k tomu určenou metodu FindCaption, ale o tom zde hovořit nebudeme. Nás bude zajímat ten případ, kdy chceme též hledat mezi ostatními prvky (v ostatních sloupcích než v prvním), a k tomu právě slouží funkce, kterou si teď ukážeme.

function FindListViewItem(lv: TListView; const S: String; column: integer): TListItem;
var
  i: integer;
  found: Boolean;
begin
  Assert(Assigned(lv));
  Assert((lv.viewstyle = vsReport) or (column = 0));
  Assert(S <> ``);
  for i := 0 to lv.Items.Count - 1 do
  begin
    Result := lv.Items[i];
    if column = 0 then
      found := AnsiCompareText(Result.Caption, S) = 0
    else if column <= Result.SubItems.Count then
      found := AnsiCompareText(Result.SubItems[column - 1], S) = 0
    else
      found := False;
    if found then
      Exit;
  end;
  Result := nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
var lItem:TListItem;
begin
litem:=FindListViewItem(ListView1,`hledaný text`,1);
if lItem<>nil then ShowMessage(lItem.Caption+`  pozice:`+IntToStr(lItem.Index));
end;

Prvním parametrem je prohledávaný ListView, druhý parametr je vlastní text, který hledáme, a posledním parametrem je číslo sloupce, v němž hodláme hledat. Upozorňuji na to, že je zde (ostatně jak je v obdobných případech pravidlem) použito číslování od nuly, takže první sloupec (i první řádek) mají index nula.

Návratový parametr je typu TListItem, takže z něj získáte všechny potřebné informace o pozici a dalších vlastnostech nalezeného prvku. Nebude-li nalezen žádný prvek, bude vrácena "hodnota" nil. Hledání nerozlišuje velikost písmen a nalezen je pouze celý hledaný řetězec.

Nejdůležitějším výsledkem hledání tedy obvykle bude řádek, na kterém se prvek nachází (sloupec samozřejmě známe, protože je parametrem hledání). Tento výsledek pak již musíte vhodně zpracovat sami například tím, že nastavíte Focus na daný prvek, nastavíte viditelnost (MakeVisible), aby se hned zobrazil a uživatel nemusel složitě listovat, a podobně.