VirtualTreeView - 同一节点内的不同文本颜色

8
我正试图创建一个类似于以下示例的 TVirtualStringTree 视图:

Folder view with different font colors

在上面的示例中,我展示了我想要实现的一些可能情况。 FolderA 文本加粗,并在同一节点后面有红色的非加粗文本。我正在寻找制作这种格式输出的方式。

但如果这太难或太麻烦了,我将满足于 FolderBFolderC 类型的输出——这可能可以用两列来实现,一列包含文件夹名称,另一列包含文件数目。

FolderD 只是一个没有文件的文件夹示例,其输出(文本未加粗且没有数字)如上所示。

我正在寻找任何制作此效果的方向,因为 VirtualTreeView 每个节点只能设置单一颜色或加粗设置。任何关于如何朝着 FolderAFolderBFolderC 的方向移动的提示或建议都会非常感激,这样我就有了一个起点。Delphi 或 C++ Builder 示例都可以(最终代码将在 C++ Builder 中编写)。


1
您可以处理 OnMeasureTextWidth 事件来提供整个文本的宽度,并在 OnDrawText 事件处理程序中呈现两个文本。但我个人会使用2列,这将允许用户始终看到计数。 - TLama
@TLama,我同意双列布局确实有其优点,很可能我以后会转换到那种布局。但是此时此刻,我需要一个快速解决方案,“toShowStaticText”正好满足我的需求。很遗憾我只能接受一个答案,因为你们两个的答案都是好的解决方案。 - Coder12345
1
我无论如何也看不到在处理OnPaintText和在两列的情况下切换Column会更加复杂。 - TLama
@TLama 好的,也许我没有表达清楚 - “FolderA” 是第一选择,B 和 C 变体只是计划 B 或 C,如果 A 不起作用。 “快速” 部分是因为我不需要引入一些额外的代码来处理列(不是 VirtualTree 代码,那个确实相当简单,但是其他一些额外的东西)。我真的很感激你提供的答案,如果你将其作为附加答案添加,我肯定会点赞它(我相信其他人也会更喜欢它,所以它肯定会得到更多的赞!)。 - Coder12345
1个回答

13

您可以简单地使用toShowStaticText (StringOptions)选项:

implementation

type
  PNodeRec = ^TNodeRec;
  TNodeRec = record
    Name: WideString;
    Count: Integer;
    IsBold: Boolean;
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Node: PVirtualNode;
  NodeRec: PNodeRec;
  I: Integer;
begin
  VirtualStringTree1.TreeOptions.StringOptions := 
    VirtualStringTree1.TreeOptions.StringOptions + [toShowStaticText];
  VirtualStringTree1.NodeDataSize := Sizeof(TNodeRec);
  // Populate some data
  for I := 1 to 10 do
  begin
    Node := VirtualStringTree1.AddChild(nil);
    NodeRec := VirtualStringTree1.GetNodeData(Node);
    Initialize(NodeRec^);
    NodeRec.Name := 'Node' + IntToStr(I);
    NodeRec.Count := I;
    NodeRec.IsBold := I mod 2 = 0;
  end;
end;

procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  NodeRec: PNodeRec;
begin
  NodeRec := PNodeRec(TVirtualStringTree(Sender).GetNodeData(Node));
  if TextType = ttNormal then
    CellText := NodeRec^.Name
  else // ttStatic
    CellText := Format('(%d)', [NodeRec^.Count]);
end;

procedure TForm1.VirtualStringTree1PaintText(Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType);
var
  NodeRec: PNodeRec;
begin
  NodeRec := PNodeRec(TVirtualStringTree(Sender).GetNodeData(Node));
  if TextType = ttNormal then
  begin
    if NodeRec^.IsBold then
      TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold];
  end
  else // ttStatic
    TargetCanvas.Font.Color := clRed;
end;

输出:

输入图片描述


太容易了!我刚试了一下,效果非常好,非常感谢!现在唯一的小问题是静态部分在右侧有点多(就像多了一个空格之类的)。ttStatic的左边距(或ttNormal的右边距)也可以调整吗? - Coder12345
1
我不知道是否有内置的类似功能(但我也在使用相当旧的VT版本)。您可以在“PaintText”事件上处理绘图(而不是处理“ttStatic”的“GetText”)。您拥有Canvas + TargetCanvas。按您希望的位置放置文本。 - kobik
3
您有TextMargin属性,它会影响普通文本和静态文本。 - kobik
1
在当前版本中进行自定义文本绘制;不要在OnPaintText事件中绘制(最多为画布准备字体)。在OnDrawText事件中绘制(不要忘记将DefaultDraw设置为False)。除此之外,您可能需要重新测量节点文本矩形(例如,在OnMeasureTextWidth事件中测量宽度),以匹配您的可变字体设置和要呈现的文本(这就是我的答案所涉及的内容)。 - TLama

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接