從Delphi5開始,Delphi集成開發環境中的Object Inspector就使用了圖形化的風格來顯示某些屬性。比如Cursors、Colors、Fonts和Image List等等屬性就是這種類型。第一次看到這樣的效果,的確令人感到神奇,各種字體的名稱可以直接以這種字體的樣式顯示出來,在選擇字體的時候真是很方便。這種效果是如何實現的呢,其實就是使用了組件的“自繪”(Ower-drawing)方法。在Delphi中想要實現這樣的功能是很方便的,現在我們就開始一段神奇的“圖形化組件”之旅吧,Let's Draw!
要建立一個自繪的ComboBox組件,我們先要把它的Style屬性設為cs_OwnerDrawFixed或者cs_OwnerDrawVariable,如果在ComboBox組件中的所有元素都是相等高度的,例如字符或圖標,那麼就使用cs_OwnerDrawFixed;如果在ComboBox組件中的各個元素不是相等高度的,例如不同大小的位圖,那麼就使用 cs_OwnerDrawVariable屬性。ComboBox組件會接收到WM_MEASUREITEM消息,從而觸發OnMeasureItem事件。Windows就不再對該組件進行繪制了,取而代之的是我們用發送WM_DRAWITEM的方式對它進行重繪。
下面我們用兩個實例來說明完整的繪制過程:
1、顯示顏色的Combobox:
(圖一)
第一步,我們把顏色的名字加入ComboBox的Item屬性中(這一步是在Form.OnCreate事件中完成的),所有的顏色的名稱將被加入一個常量(Colors)中,代碼如下:
const Colors:array[0..17] of TColor=
(clAqua, clBlack, ..., clWhite, clYellow) ;//一部分顏色的名稱被省略了
第二步,繪制各元素,它的代碼並不復雜,我們可以把顏色名稱與各元素關聯起來,用這種顏色在Combobox中繪制矩形並著色,代碼如下:
procedure TForm1.ColorComboDrawItem (Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
with Control as TComboBox do
begin //填充矩形
Canvas.Brush.Color := TColor(Colors[Index]);
Canvas.FillRect(Rect);
Canvas.TextOut(Rect.Left,Rect.Top,ColorToString(Colors[Index]))
end;
end;
2、所見即所得的字體Combobox:
(圖二)
雖然這個看起來很復雜,甚至有人可能會認為要用一張張字體的圖片才能實現,實際上並非如此。大家一定還記得在Delphi中有一個TScreen類,這次就要用到它了。
第一步,系統字體並不像顏色名稱那樣少,如果還是用上面對付顏色的方法來對付字體,也許得干上整整一天,特別是那些美術字體的愛好者們,我們用下面的程序來填充:
for i := 0 to Screen.Fonts.Count-1 do
FontCombo.Items.Add(Screen.Fonts.Strings[i]);
第二步,繪制字體:
procedure TForm1.FontComboDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
with (Control as TComboBox).Canvas do
begin
Font.Name := Screen.Fonts.Strings[Index];
FillRect(Rect);
TextOut(Rect.Left,Rect.Top,PChar(Screen.Fonts.Strings[Index]))
end;
end;
上面的“自繪”方法並不僅僅可以用在ComboBox上,也可用在其它的Windows公共組件上,比如ListView、TreeView、TabControl、StatusBar等等,只要你發揮想像力,在編程的領域沒有什麼是絕對的禁區,再加上Delphi這柄倚天劍,真的會有這樣的感歎,“沒有它做不到,只有你想不到”!