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

Tipy a triky v Delphi, díl 45. - Obrázkový ComboBox; Jak zabránit překreslení okna aplikace?; Název a identifikační číslo CD disku

Jan Šindelář - 19.6.2002

Obrázkový ComboBox

Ukážeme si, jak vylepšit klasický ComboBox tím, že k jednotlivým položkám rozbaleného seznamu přiřadíme obrázky (ikonky). Každá položka pak bude mít vlevo vlastní ikonu a vedle ní bude samotný text dané položky.

Jak toho dosáhnout? Poměrně snadno tím, že se o vykreslení budeme starat sami prostřednictvím události OnDrawItem. Nejprve je však třeba nastavit styl ComboBoxu na csOwnerDrawFixed nebo csOwnerDrawVariable (podle toho, zda budou jednotlivé řádky mít fixní či proměnlivou velikost).

Poté naplňte ComboBox nějakými testovacími daty. Prostě několik řádků hodnot. Jednotlivé obrázky budou potom k položkám přiřazeny z ImageListu, který rovněž přidejte na formulář a pochopitelně naplňte několika (vhodně malými) obrázky.

Vlastní obsluha události OnDrawItem pak vypadá takto:

procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;  Rect: TRect; State: TOwnerDrawState);
var
ComboBox : TComboBox;
bitmap : TBitmap;
begin
ComboBox := (Control as TComboBox);
bitmap := TBitmap.Create;
try
  ImageList1.GetBitmap(Index, bitmap);
  with ComboBox.Canvas do
  begin
    FillRect(Rect);
    if Bitmap.Handle <> 0 then Draw(Rect.Left + 2, Rect.Top, Bitmap);
    Rect := Bounds(Rect.Left + ComboBox.ItemHeight + 2, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
    DrawText(handle, PChar(ComboBox.Items[Index]), length(ComboBox.Items[index]), Rect, DT_VCENTER+DT_SINGLELINE);
  end;
finally
  bitmap.Free;
end;
end;

Jednotlivé "řádky" (položky) ComboBoxu jsou identifikovány svým indexem (parametr Index), který je jako obvykle počítán od nuly. Kvůli zjednodušení příkladu je tentýž index zároveň určující pro to, který obrázek z ImageListu bude pro danou položku použit. V reálných aplikacích si pochopitelně na základě hodnoty daného řádku můžete přiřadit patřičný vhodný obrázek libovolně.

Máte-li k dispozici Delphi verze 6 (stačí i Personal verze zdarma), pak je situace mnohem jednodušší, neboť vše řeší nová komponenta ComboBoxEx.

Jak zabránit překreslení okna aplikace?

Následující tip patří opět k těm velmi krátkým, jednoduchým a velmi málo používaným. Pokud tedy z nějakého důvodu chcete zabránit systému v překreslování okna vaší aplikace, stačí použít následující příkaz:

SendMessage(Handle, WM_SetRedraw, 0, 0);

Pro opětovné zapnutí překreslování použijte tyto parametry:

SendMessage(Handle, WM_SetRedraw, 1, 0);

Až budete tento tip zkoušet, dejte si pozor, aby se vám aplikace "neztratila". Nejenže se okno nebude překreslovat (tj. pokud jej překryjete oknem jiné aplikace a poté znovu odkryjete, bude vidět plocha Windows), ale nebude ani reagovat na klikání myši. Nelze jej tak ani uchopit nebo klikat na objekty na formuláři (nehledě na to, že i kdyby se vám "nějak" podařilo myší okno uchopit, těžko byste jej díky nepřekreslování někam viditelně přenesli). Aplikace však samozřejmě reaguje na klávesnici, takže lze mezi jednotlivými prvky (i když třeba nejsou vidět) přecházet například tabulátorem.

Název a identifikační číslo CD disku

Na závěr tu máme jednoduchou funkci na zjišťování základních informací o vloženém CD – název a ID disku. Jako parametr se předává písmenko mechaniky CD (včetně dvojtečky). Pokud bude jako parametr předán disk jiného typu (například pevný disk či disketová mechanika), funkce vrátí prázdný řetězec.

function GetCDInfo(WhichDrive: string): string;
var
  VolumeName: array[0..255] of char;
  FileSystemType: array[0..255] of char;
  SerialNum: DWORD;
  MaxFilenameLength: DWORD;
  Flags: DWORD;
begin
  if (GetVolumeInformation(PChar(WhichDrive), VolumeName, 256, @SerialNum, MaxFilenameLength, Flags, FileSystemType, 256)) then
  Result := (IntToHex(SerialNum shr 16, 3) + IntToHex((SerialNum shl 16) shr 16, 4)) + ` - ` + VolumeName;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(GetCDinfo(`e:`));
end;