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
相关产品推荐
相关产品推荐

