2012-06-07 32 views
8

我正在做自定義TTreeView使用OnAdvancedCustomDrawItem事件從頭開始繪製,我想知道如何在我的自繪項目的背景中正確渲染這些選擇和熱矩形?他們是Vista/7風格,所以我不能簡單地用純色填充背景。如何在AdvancedCustomDrawItem中繪製TTreeView的樣式選擇矩形?

enter image description here

我試圖在cdPostPaint階段吸取我的項目,但如果我離開DefaultDraw := TruecdPrePaint階段繪製選擇的背景下,發生完全默認繪圖,包括項目的文本。

procedure TForm1.TreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView; 
    Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, 
    DefaultDraw: Boolean); 
begin 
    case Stage of 
    cdPreErase: 
    begin 
     DefaultDraw := True; 
    end; 

    cdPostErase: 
    begin 
     DefaultDraw := True; 
    end; 

    cdPrePaint: 
    begin 
     // I thought this will paint only the selected/hot backgrounds, 
     // however this will paint whole item, including text. 
     DefaultDraw := True; 
    end; 

    cdPostPaint: 
    begin 
     DefaultDraw := False; 

     // painting my owner-draw text 
     // ......... 
    end; 
    end; 

    PaintImages := False; 
end; 
+0

您需要使用主題API,這是Windows最糟糕的記錄區域。祝你好運,隨時隨地。虛擬Treeview在這裏看起來很不錯。我想這很容易定製。 –

+0

@DavidHeffernan沒有機會使用標準TreeView的繪圖? – Andrew

+0

當然。但沒有文件,這並不容易。 –

回答

12

這是我的解決方案(測試)。

請注意,TreeView必須有HotTrack := True才能正常繪製熱門項目。

當主題未啓用時,還必須有額外的繪圖。

uses 
    UxTheme, 
    Themes; 

const 
    TreeExpanderSpacing = 6; 

procedure TForm1.DrawExpander(ACanvas: TCanvas; ATextRect: TRect; AExpanded: Boolean; 
    AHot: Boolean); 
var 
    ExpanderRect: TRect; 
    Graphics: IGPGraphics; 
    Points: array of TGPPoint; 
    Brush: IGPBrush; 
    Pen: IGPPen; 
    ThemeData: HTHEME; 
    ElementPart: Integer; 
    ElementState: Integer; 
    ExpanderSize: TSize; 
    UnthemedColor: TColor; 
begin 
    if ThemeServices.ThemesEnabled then 
    begin 
    if AHot then 
     ElementPart := TVP_HOTGLYPH 
    else 
     ElementPart := TVP_GLYPH; 

    if AExpanded then 
     ElementState := GLPS_OPENED 
    else 
     ElementState := GLPS_CLOSED; 

    ThemeData := OpenThemeData(TreeView1.Handle, VSCLASS_TREEVIEW); 
    GetThemePartSize(ThemeData, ACanvas.Handle, ElementPart, ElementState, nil, 
     TS_TRUE, ExpanderSize); 
    ExpanderRect.Left := ATextRect.Left - TreeExpanderSpacing - ExpanderSize.cx; 
    ExpanderRect.Right := ExpanderRect.Left + ExpanderSize.cx; 
    ExpanderRect.Top := ATextRect.Top + (ATextRect.Bottom - ATextRect.Top - ExpanderSize.cy) div 2; 
    ExpanderRect.Bottom := ExpanderRect.Top + ExpanderSize.cy; 
    DrawThemeBackground(ThemeData, ACanvas.Handle, ElementPart, ElementState, ExpanderRect, nil); 
    CloseThemeData(ThemeData); 
    end 
    else 
    begin 

    // Drawing expander without themes enabled 

    Graphics := TGPGraphics.Create(ACanvas.Handle); 
    Graphics.SmoothingMode := SmoothingModeHighQuality; 

    ExpanderRect := ATextRect; 
    ExpanderRect.Right := ATextRect.Left - TDPIAware.GetScaledSize(TreeExpanderSpacing96dpi); 
    ExpanderRect.Left := ATextRect.Left - TDPIAware.GetScaledSize(TreeExpanderSpacing96dpi) - 
     TDPIAware.GetScaledSize(Max(TreeExpanderCollapsedWidth96dpi, TreeExpanderExpandedWidth96dpi)); 

    if ASelected then 
     UnthemedColor := ColorToRGB(clHighlightText) 
    else 
     if AExpanded then 
     UnthemedColor := clBlack 
     else 
     UnthemedColor := clGray; 

    SetLength(Points, 3); 
    if AExpanded then 
    begin 
     Points[0] := TGPPoint.Create(ExpanderRect.Right, ExpanderRect.Top + 
     (ExpanderRect.Bottom - ExpanderRect.Top - TreeExpanderExpandedHeight96dpi) div 2); 
     Points[1] := TGPPoint.Create(ExpanderRect.Right, ExpanderRect.Top + 
     (ExpanderRect.Bottom - ExpanderRect.Top + TreeExpanderExpandedHeight96dpi) div 2); 
     Points[2] := TGPPoint.Create(ExpanderRect.Right - TreeExpanderExpandedWidth96dpi, 
     ExpanderRect.Top + (ExpanderRect.Bottom - ExpanderRect.Top + 
     TreeExpanderExpandedHeight96dpi) div 2); 
     Brush := TGPSolidBrush.Create(TGPColor.CreateFromColorRef(UnthemedColor)); 
     Graphics.FillPolygon(Brush, Points); 
    end 
    else 
    begin 
     Points[0] := TGPPoint.Create(ExpanderRect.Right - TreeExpanderCollapsedWidth96dpi, 
     ExpanderRect.Top + (ExpanderRect.Bottom - ExpanderRect.Top - 
     TreeExpanderCollapsedHeight96dpi) div 2); 
     Points[1] := TGPPoint.Create(ExpanderRect.Right, 
     ExpanderRect.Top + (ExpanderRect.Bottom - ExpanderRect.Top) div 2); 
     Points[2] := TGPPoint.Create(ExpanderRect.Right - TreeExpanderCollapsedWidth96dpi, 
     ExpanderRect.Top + (ExpanderRect.Bottom - ExpanderRect.Top + 
     TreeExpanderCollapsedHeight96dpi) div 2); 
     Pen := TGPPen.Create(TGPColor.CreateFromColorRef(UnthemedColor)); 
     Graphics.DrawPolygon(Pen, Points); 
    end; 
    end; 
end; 

procedure TForm1.TreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView; 
    Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, 
    DefaultDraw: Boolean); 
var 
    NodeRect: TRect; 
    NodeTextRect: TRect; 
    Text: string; 
    ThemeData: HTHEME; 
    TreeItemState: Integer; 
begin 
    if Stage = cdPrePaint then 
    begin 
    NodeRect := Node.DisplayRect(False); 
    NodeTextRect := Node.DisplayRect(True); 

    // Drawing background 
    if (cdsSelected in State) and Sender.Focused then 
     TreeItemState := TREIS_SELECTED 
    else 
     if (cdsSelected in State) and (cdsHot in State) then 
     TreeItemState := TREIS_HOTSELECTED 
     else 
     if cdsSelected in State then 
      TreeItemState := TREIS_SELECTEDNOTFOCUS 
     else 
      if cdsHot in State then 
      TreeItemState := TREIS_HOT 
      else 
      TreeItemState := TREEITEMStateFiller0; 

    if TreeItemState <> TREEITEMStateFiller0 then 
    begin 
     ThemeData := OpenThemeData(Sender.Handle, VSCLASS_TREEVIEW); 
     DrawThemeBackground(ThemeData, Sender.Canvas.Handle, TVP_TREEITEM, TreeItemState, 
     NodeRect, nil); 
     CloseThemeData(ThemeData); 
    end; 

    // Drawing expander 
    if Node.HasChildren then 
     DrawExpander(Sender.Canvas, NodeTextRect, Node.Expanded, cdsHot in State); 

    // Drawing main text 
    SetBkMode(Sender.Canvas.Handle, TRANSPARENT); 
    SetTextColor(Sender.Canvas.Handle, clBlue); 

    Text := Node.Text; 
    Sender.Canvas.TextRect(NodeTextRect, Text, 
     [tfVerticalCenter, tfSingleLine, tfEndEllipsis, tfLeft]); 

    // Some extended drawing... 

    end; 

    PaintImages := False; 
    DefaultDraw := False; 
end; 
+1

不錯。您可能想要使用主題中包含低級API的一些方法。保存與主題句柄混亂。 –

+0

@DavidHeffernan當我使用主題包裝進行繪製時,它沒有繪製Vista風格的擴展器和漸變背景,我不知道爲什麼。也許他們想讓'Themes'獨立於Windows版本,所以它們使用了一些兼容的常量。稍後我會檢查'Themes'代碼。 – Andrew

+0

如果您能夠顯示Drawing-expander-without-themes代碼,這對後來出現並且不知道該怎麼做的其他人有幫助。 –