天天看點

使非标準 Win32 控件或自畫控件也具有 Windows XP 的界面風格

這裡先說說兩個概念:Theme(主題)和 Visual Style 。Theme 最早出現在 Microsoft Plus! for Windows 95 中,是 Windows 中 Wallpaper、Cursors、Fonts、Sounds 、Icons 等的設定值集合。Visual Style 在 Windows XP 中才被引入,Visual Style 規定了 Contorls 的外觀,另外還包括使用這些外觀的一套 API 。使用 Visual Style 必須要 ComCtl32.dll 6,而 ComCtl32.dll 6 是不能被分發到以前版本的 Windows 中的,是以隻能在 Windows XP 下使用 Visual Style。

    Delphi 7 (後面簡稱 7 吧)對 Visual Style 提供了較好的支援。首先 7 将那個 Menifest 封裝成了 VCL - TXPMenifest,另外增加了 UxTheme.pas 單元,裡面是對 Visual Style 的一套 API 及其結構、常數等的引用聲明(大概有 47 個API 函數),更重要的是 7 還增加一個 Themes.pas 單元,裡面是對這套 API 的更進一步的簡化和封裝,7 下的 Win32 控件對 Visual Style 的支援較 Delphi 6有了很大改觀,就是這個單元的功勞。

    一般來說要使 7 下編譯的程式在 Windows XP 具有 Visual Style ,隻需在主窗體上放入 VCL - TXPMenifest 即可,但對于一些非标準或是自畫的控件,還是經典的界面。這裡就說一下如何用 Themes.pas 中提供的方法使這些控件具有 Visual Style 。

    Themes.pas 中隻有一個類:TThemeServices 。這個類有一個重要的屬性: ThemesEnabled (Boolean 類型),就是判斷在目前程式能不能使用 Visual Style ,這個屬性隻有在程式使用了 TXPMenifest 并且在 Windows XP 下運作并且使用了 Windows XP 的主題(即桌面主題不是 Windows 經典)才為 True ,由于程式要運作在以前版本的 Windows 下,是以你的程式也得提供這個屬性為 False 時的處理過程(一般就是原有的處理過程)。還要提一下這個類封裝的幾個重要函數:DrawEdge 用來畫控件邊界的,DrawElement 用來畫整個界面的,DrawText 用來寫字的。這個類還處理了 WM_THEMECHANGED 消息,這樣當我們在改變桌面主題後,程式會自動調整外觀。再說一下我們最常用到的一個函數(多态函數):GetElementDetails ,這個函數的傳回值在上面的幾個 DrawXXX 函數中要用到,這個函數的輸入值是 24 個枚舉類型中的元素,這 24 個枚舉類型在 Themes.pas 單元開頭定義(從第二個 TThemedButton 開始直到 TThemedWindow)。最後,我們不去直接使用這個類,在 Themes.pas 單元中有一函數:

function ThemeServices: TThemeServices;

傳回值就是這個類,是以我們直接使用這個方法,7 的 VCL 裡都是這樣做。

    好,下面就來個簡單的例子。Delphi 的 TPanel 控件不是标準控件,我們就來在它上面實作一下 Visual Style 。在 Delphi 7 中建立一工程,在主窗體上放入 TXPMenifest ,在 Unit1 單元引用 Themes 單元,在

TForm1 = class(TForm)

前面加入下代碼(主要是重載 TCustomPanel 的 Paint 方法):

TVSPanel = class(TCustomPanel)

private

  //

protected

  procedure Paint; override;

public

end;

重載的 Paint 方法實作如下:

procedure TVSPanel.Paint;

var

  Details: TThemedElementDetails;

begin

  inherited;

  if ThemeServices.ThemesEnabled then

  begin

    Details := ThemeServices.GetElementDetails(tbPushButtonHot);   {這裡畫個按鈕處于 Hot 狀态下的樣子}

    PerformEraseBackground(Self, Canvas.Handle);      {擦除畫按鈕時的背景}

    ThemeServices.DrawElement(Canvas.Handle, Details, ClientRect);

    ThemeServices.DrawText(Canvas.Handle, Details, Caption, ClientRect,

      DT_EXPANDTABS or DT_VCENTER or DT_CENTER or DT_SINGLELINE, 0);

  end;

TCustomPanel 的改動完成,再就是在主窗體的 Create 事件中執行個體化 TVSPanel ,代碼如下:

procedure TForm1.FormCreate(Sender: TObject);

  APanel: TVSPanel;

  APanel := TVSPanel.Create(Application);

  APanel.Left := 100;

  APanel.Top := 100;

  APanel.Width := 200;

  APanel.Height := 30;

  APanel.Caption := '具有 Button 風格的 Panel';

  APanel.Parent := Self;

    好了,運作看看 Visual Style 效果是不是出來了。我的程式裡用 THintWindow 做了個浮動視窗并且加上了 Visual Style ,效果還不錯,如果再細緻點的話,就做出和 Windows XP 下微軟拼音輸入法那個浮動條完全相同的界面了。

    另外,還有幾個重要的東西沒有提及,比如 Part 和 State ,大家可以查 MSDN ,在 User Interface Design and Development \ Windows Shell \ Shell Refrence \ Visual Styles Refrence 裡

繼續閱讀