如何让 TVirtualStringTree 在禁用状态下显示图标?

tru*_*ger 2 delphi virtualtreeview tvirtualstringtree

我需要将目录中的文件显示到 TVirtualStringTree。所以,我使用 SHGetFileInfo 来获取文件的图标。但似乎我只能获得“正常”图标(以下屏幕截图的左侧)。如果是这样,TVirtualStringTree 可以将图标绘制为“禁用”吗?就像您禁用了 a 节点一样。请看屏幕截图:

在此处输入图片说明

更新

Soft Gems 论坛中有一个类似的帖子。我可以获得图标的矩形,然后自己绘制图标。我正在使用 TcxImageList,它可以轻松绘制“禁用”图标。我首先在 GetImageIndex 事件中分配了一个不存在的图像索引,所以我有一个空间来绘制图标。然后使用以下代码进行绘制。

procedure TfrmMain.tvSharesAfterItemPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); 
var 
  rImage: TRect; 
  OffsetLeft: Integer; 
begin 
    rImage  := ItemRect; 

    with TVirtualStringTree(Sender) do begin 
      if (toShowRoot in TreeOptions.PaintOptions) then 
        OffsetLeft := Indent * (GetNodeLevel(Node) + 1) 
      else 
        OffsetLeft := Indent * GetNodeLevel(Node); 

      Inc(rImage.Left, Margin + OffsetLeft); 
      Inc(rImage.Top, (NodeHeight[Node] - Images.Height) div 2); 
      rImage.Right  := rImage.Left + Images.Width; 
      rImage.Bottom := rImage.Top + Images.Height; 
    end; 

    // draw the "normal" or "disabled" icon here
    imageList.Draw(TargetCanvas, rImage.left, rImage.Top, ...);
  end; 
end;
Run Code Online (Sandbox Code Playgroud)

TLa*_*ama 5

没有直接的方法来绘制禁用的图像状态。我更愿意为图像的自定义绘制创建事件(I've suggested this as a new feature由于缺乏这种情况,现在用于虚拟树视图)。这是带有用于虚拟字符串树的插入类的示例。

对于灰度图像的自定义绘制,它使用code from this post. 当然,这不是永久使用的解决方案,您必须保持PaintImage方法代码与实际代码同步,因为该方法已被完全覆盖。

OnCustomDrawImage事件的参数计数指向该参数应该包装到某种结构中,但这只是一个展示它会是什么样子。这个新事件被触发两次;第一次绘制图像(DrawOverlay为 False),第二次用于叠加(DrawOverlay参数为 True):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DateUtils, StdCtrls, VirtualTrees, ImgList, CommCtrl;

type
  TCustomDrawImageEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode;
    ImageList: TCustomImageList; ImageIndex: Integer; TargetCanvas: TCanvas;
    X, Y: Integer; Style: Cardinal; DrawEnabled: Boolean; DrawOverlay: Boolean;
    var CustomDraw: Boolean) of object;
  TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
  private
    FOnCustomDrawImage: TCustomDrawImageEvent;
  protected
    function DoCustomDrawImage(Node: PVirtualNode; ImageList: TCustomImageList;
      ImageIndex: Integer; TargetCanvas: TCanvas; X, Y: Integer; Style: Cardinal;
      DrawEnabled: Boolean; DrawOverlay: Boolean): Boolean; virtual;
    procedure PaintImage(var PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex;
      DoOverlay: Boolean); override;
  published
    property OnCustomDrawImage: TCustomDrawImageEvent read FOnCustomDrawImage write FOnCustomDrawImage;
  end;

type
  TForm1 = class(TForm)
    VirtualStringTree1: TVirtualStringTree;
    ImageList1: TImageList;
    procedure FormCreate(Sender: TObject);
    procedure VirtualStringTree1GetImageIndex(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
      var Ghosted: Boolean; var ImageIndex: Integer);
  private
    procedure VirtualTreeCustomDrawImage(Sender: TBaseVirtualTree; Node: PVirtualNode;
      ImageList: TCustomImageList; ImageIndex: Integer; TargetCanvas: TCanvas;
      X, Y: Integer; Style: Cardinal; DrawEnabled: Boolean; DrawOverlay: Boolean;
      var CustomDraw: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TVirtualStringTree }

type
  TCustomImageListCast = class(TCustomImageList);

function TVirtualStringTree.DoCustomDrawImage(Node: PVirtualNode;
  ImageList: TCustomImageList; ImageIndex: Integer; TargetCanvas: TCanvas; X,
  Y: Integer; Style: Cardinal; DrawEnabled: Boolean; DrawOverlay: Boolean): Boolean;
begin
  Result := False;
  if Assigned(FOnCustomDrawImage) then
    FOnCustomDrawImage(Self, Node, ImageList, ImageIndex, TargetCanvas, X, Y,
      Style, DrawEnabled, DrawOverlay, Result);
end;

procedure TVirtualStringTree.PaintImage(var PaintInfo: TVTPaintInfo;
  ImageInfoIndex: TVTImageInfoIndex; DoOverlay: Boolean);
var
  CutNode: Boolean;
  ExtraStyle: Cardinal;
  DrawEnabled: Boolean;
  PaintFocused: Boolean;
const
  Style: array[TImageType] of Cardinal = (0, ILD_MASK);
begin
  with PaintInfo do
  begin
    CutNode := (vsCutOrCopy in Node.States) and (tsCutPending in TreeStates);
    PaintFocused := Focused or (toGhostedIfUnfocused in TreeOptions.PaintOptions);
    if DoOverlay then
      GetImageIndex(PaintInfo, ikOverlay, iiOverlay, Images)
    else
      PaintInfo.ImageInfo[iiOverlay].Index := -1;
    DrawEnabled := not (vsDisabled in Node.States) and Enabled;
    with ImageInfo[ImageInfoIndex] do
    begin
      if (vsSelected in Node.States) and not (Ghosted or CutNode) then
      begin
        if PaintFocused or (toPopupMode in TreeOptions.PaintOptions) then
          Images.BlendColor := Colors.FocusedSelectionColor
        else
          Images.BlendColor := Colors.UnfocusedSelectionColor;
      end
      else
        Images.BlendColor := Color;
      if (ImageInfo[iiOverlay].Index > -1) and (ImageInfo[iiOverlay].Index < 15) then
        ExtraStyle := ILD_TRANSPARENT or ILD_OVERLAYMASK and
          IndexToOverlayMask(ImageInfo[iiOverlay].Index + 1)
      else
        ExtraStyle := ILD_TRANSPARENT;
      if (toUseBlendedImages in TreeOptions.PaintOptions) and PaintFocused
        and (Ghosted or ((vsSelected in Node.States) and
        not (toFullRowSelect in TreeOptions.SelectionOptions) and
        not (toGridExtensions in TreeOptions.MiscOptions)) or CutNode)
      then
        ExtraStyle := ExtraStyle or ILD_BLEND50;
      if (vsSelected in Node.States) and not Ghosted then
        Images.BlendColor := clDefault;

      // in this modified part of code, the new event OnCustomDrawImage
      // is fired once before the image is actually drawn and once when
      // the overlay is to be drawn; when you keep its CustomDraw param
      // in False value (what is, by default), the default drawing will
      // be done otherwise you need to take care of drawing by yourself

      // draw image default way when the CustomDraw parameter of the new
      // OnCustomDrawImage event remains False (what is, by default)
      if not DoCustomDrawImage(Node, Images, Index, Canvas, XPos, YPos,
        Style[Images.ImageType] or ExtraStyle, DrawEnabled, False)
      then
        TCustomImageListCast(Images).DoDraw(Index, Canvas, XPos, YPos,
          Style[Images.ImageType] or ExtraStyle, DrawEnabled);
      // draw overlay default way when the CustomDraw parameter of the new
      // OnCustomDrawImage event remains False (what is, by default)
      if PaintInfo.ImageInfo[iiOverlay].Index >= 15 then
      begin
        if not DoCustomDrawImage(Node, ImageInfo[iiOverlay].Images,
          ImageInfo[iiOverlay].Index, Canvas, XPos, YPos,
          Style[ImageInfo[iiOverlay].Images.ImageType] or ExtraStyle,
          DrawEnabled, True)
        then
          TCustomImageListCast(ImageInfo[iiOverlay].Images).DoDraw(
            ImageInfo[iiOverlay].Index, Canvas, XPos, YPos,
            Style[ImageInfo[iiOverlay].Images.ImageType] or ExtraStyle,
            DrawEnabled);
      end;
    end;
  end;
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  VirtualStringTree1.OnCustomDrawImage := VirtualTreeCustomDrawImage;
end;

type
  TImageListDrawParams = record
    cbSize: DWORD;
    himl: HIMAGELIST;
    i: Integer;
    hdcDst: HDC;
    x: Integer;
    y: Integer;
    cx: Integer;
    cy: Integer;
    xBitmap: Integer;
    yBitmap: Integer;
    rgbBk: COLORREF;
    rgbFg: COLORREF;
    fStyle: UINT;
    dwRop: DWORD;
    fState: DWORD;
    Frame: DWORD;
    crEffect: COLORREF;
  end;

procedure DrawDisabledImage(DC: HDC; ImageList: TCustomImageList; Index, X,
  Y: Integer);
var
  Options: TImageListDrawParams;
begin
  FillChar(Options, SizeOf(Options), 0);
  Options.cbSize := SizeOf(Options);
  Options.himl := ImageList.Handle;
  Options.i := Index;
  Options.hdcDst := DC;
  Options.x := X;
  Options.y := Y;
  Options.fState := ILS_SATURATE;
  ImageList_DrawIndirect(@Options);
end;

procedure TForm1.VirtualStringTree1GetImageIndex(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: Integer);
begin
  ImageIndex := 0;
end;

procedure TForm1.VirtualTreeCustomDrawImage(Sender: TBaseVirtualTree;
  Node: PVirtualNode; ImageList: TCustomImageList; ImageIndex: Integer;
  TargetCanvas: TCanvas; X, Y: Integer; Style: Cardinal; DrawEnabled: Boolean;
  DrawOverlay: Boolean; var CustomDraw: Boolean);
begin
  CustomDraw := True;
  if not DrawOverlay then
    DrawDisabledImage(TargetCanvas.Handle, ImageList, ImageIndex, X, Y);
end;

end.
Run Code Online (Sandbox Code Playgroud)

结果(我不得不说混合它会很好):

在此处输入图片说明