You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VirtualStringTree实现选中与未选中行自定义背景色的问题

VirtualTreeView 自定义行背景色(含选中态、动态过渡)解决方案

核心思路

放弃之前尝试的OnBeforeCellPaint/OnDrawText等事件,改用**OnAfterItemPaint**事件实现整行背景绘制。该事件在控件完成基础绘制后触发,既支持选中/未选中行,又能结合toFullRowSelect实现无间隙的整行着色,完美适配多选模式下的自定义需求。

关键设置

确保控件的TreeOptions配置正确:

  • PaintOptions包含toFullRowSelect(整行选中)
  • SelectionOptions包含toMultiSelect(启用多选)

具体实现代码

1. 绑定OnAfterItemPaint事件处理整行背景

procedure TMainForm.VSTAfterItemPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
var
  Job: TJob;
  BgColor: TColor;
  IsNodeSelected: Boolean;
begin
  // 获取当前节点绑定的业务数据
  Job := TJob(Sender.GetNodeData(Node)^);
  IsNodeSelected := Sender.IsSelected(Node);

  // 根据Job状态+选中状态计算背景色
  case Job.Status of
    jsStopped:
      begin
        // 停止状态保留默认样式
        BgColor := IfThen(IsNodeSelected, clHighlight, clWindow);
      end;
    jsRunningInfinite:
      begin
        // 无限运行状态:未选中浅绿,选中深绿
        BgColor := IfThen(IsNodeSelected, $00336600, $0099CC66);
      end;
    jsRunningLimited:
      begin
        // 有限时长运行:绿→红动态过渡,选中态更明亮
        if IsNodeSelected then
          BgColor := RGB(Round(255 * Job.Progress), Round(255 * (1 - Job.Progress)), 0)
        else
          BgColor := RGB(Round(180 * Job.Progress), Round(180 * (1 - Job.Progress)), 0);
      end;
  end;

  // 填充整行背景(ItemRect为整行范围,因toFullRowSelect生效)
  TargetCanvas.Brush.Color := BgColor;
  TargetCanvas.FillRect(ItemRect);

  // 可选:保留水平网格线,需调整填充范围(若启用toShowHorzGridLines)
  // ItemRect.Bottom := ItemRect.Bottom - 1;
  // TargetCanvas.FillRect(ItemRect);
  // TargetCanvas.Pen.Color := clSilver;
  // TargetCanvas.MoveTo(ItemRect.Left, ItemRect.Bottom);
  // TargetCanvas.LineTo(ItemRect.Right, ItemRect.Bottom);
end;

2. 动态过渡色的定时更新

用TTimer定时更新有限时长任务的进度并重绘对应节点,保证颜色动态变化:

procedure TMainForm.ProgressTimerTimer(Sender: TObject);
var
  Node: PVirtualNode;
  Job: TJob;
  ElapsedRatio: Double;
begin
  Node := VST.GetFirst;
  while Node <> nil do
  begin
    Job := TJob(VST.GetNodeData(Node)^);
    if Job.Status = jsRunningLimited then
    begin
      // 计算已运行时间占总时长的比例(0=刚启动,1=即将结束)
      ElapsedRatio := Min(1, (Now - Job.StartTime) / Job.TotalDuration);
      Job.Progress := ElapsedRatio;
      // 仅重绘状态变化的节点,提升性能
      VST.RepaintNode(Node);
    end;
    Node := VST.GetNext(Node);
  end;
end;

注意事项

  • 若需保留列分隔线,可在填充背景后手动绘制竖线,或调整FillRect的左右边界留出间隙
  • 多选模式下,IsSelected会准确返回每个节点的选中状态,不同选中节点可根据自身Job状态显示差异化颜色
  • 停止状态的行直接复用系统默认选中/未选中色,保持界面一致性

内容的提问来源于stack exchange,提问作者Molochnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:15:32