2012-06-07 9 views
8

Sto facendo custom TTreeView disegnando da zero utilizzando l'evento OnAdvancedCustomDrawItem e mi chiedo come visualizzare correttamente questa selezione e i rettangoli caldi sullo sfondo del mio proprietario: disegna gli elementi? Sono in stile Vista/7, quindi non posso semplicemente riempire lo sfondo di un colore solido.Come disegnare il rettangolo di selezione in stile TTreeView durante AdvancedCustomDrawItem?

enter image description here

ho cercato di disegnare i miei oggetti in cdPostPaint fase, ma se lascio DefaultDraw := True in cdPrePaint fase elaborare sfondo selezione, il disegno di default completa verifica, inclusi i testi degli articoli.

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

È necessario utilizzare l'API tema, l'unica area documentata di Windows. Buona fortuna arrivare ovunque con quello. Virtual Treeview sembra una buona opzione qui. Immagino che sia più facile da personalizzare. –

+0

@DavidHeffernan Nessuna possibilità di utilizzare il disegno TreeView standard? – Andrew

+0

Ovviamente. Ma senza documentazione, non è facile. –

risposta

12

Ecco la mia soluzione (testata).

Nota TreeView deve avere HotTrack := True per disegnare normalmente gli elementi caldi.

Ci deve essere anche un disegno aggiuntivo quando i temi non sono abilitati.

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

Bello. Potresti voler utilizzare alcuni dei metodi in Temi che racchiudono l'API di basso livello. Risparmiare dovendo pasticciare con maniglie del tema. –

+0

@DavidHeffernan Quando ho usato il wrapper 'Themes' per disegnare, non ha disegnato gli espansori in stile Vista e gli sfondi sfumati, non so perché. Forse volevano rendere 'Themes' indipendente dalla versione di Windows in modo che usassero alcune costanti compatibili. Controllerò il codice 'Themes' in seguito. – Andrew

+0

Se si potesse mostrare il codice di espansione disegni senza testo che sarebbe utile per gli altri che verranno dopo e non sanno come farlo. –

Problemi correlati