在Delphi的UniGUI框架开发中,UniDBGrid作为数据展示的核心组件,其可视化效果的优化直接关系到用户体验。其中单元格和行的条件性着色是最常用的功能之一,它能够通过颜色变化直观地突出关键数据,实现数据可视化预警。下面我将结合多年Delphi开发经验,详细解析实现原理和实战技巧。
UniDBGrid的着色机制主要通过OnDrawColumnCell事件实现,该事件在渲染每个单元格时触发。开发者可以在此事件中通过Attribs.Color属性动态修改单元格背景色。需要注意的是,UniGUI基于Web技术,与传统VCL的绘图机制有所不同,所有颜色值需要使用HTML格式的十六进制表示法。
行着色是最简单的条件着色方式,适用于整行统一变色的场景。典型实现代码如下:
delphi复制procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
begin
// 检查行条件
if Column.Grid.DataSource.DataSet.FieldByName('status').AsString = '紧急' then
begin
Attribs.Color := $FFCCCC; // 浅红色背景
Attribs.Font.Color := $CC0000; // 深红色文字
end
else
begin
Attribs.Color := $FFFFFF; // 默认白色背景
Attribs.Font.Color := $000000; // 默认黑色文字
end;
end;
关键提示:Attribs对象不仅包含Color属性,还可以设置Font.Color来改变文字颜色,实现更好的视觉效果对比。
实际业务中往往需要更复杂的条件判断。建议将复杂逻辑封装到独立方法中,保持事件处理代码的简洁:
delphi复制function GetRowColor(ADataSet: TDataSet): TColor;
begin
Result := clWhite; // 默认颜色
if ADataSet.FieldByName('priority').AsInteger > 3 then
Result := $CCFFFF // 高优先级-浅蓝色
else if ADataSet.FieldByName('due_date').AsDateTime < Now() then
Result := $FFCCCC; // 过期-浅红色
end;
procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
begin
Attribs.Color := GetRowColor(Column.Grid.DataSource.DataSet);
end;
当需要对特定列应用特殊着色规则时,需要检查Column.FieldName属性:
delphi复制procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
begin
// 库存列特殊处理
if Column.FieldName = 'stock_quantity' then
begin
if Column.Field.AsInteger < 10 then
Attribs.Color := $FFEEEE // 低库存警告色
else if Column.Field.AsInteger > 100 then
Attribs.Color := $EEFFEE; // 高库存提示色
end;
end;
对于不依赖特定字段名,只根据单元格内容判断的通用方案:
delphi复制procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
var
cellValue: string;
begin
cellValue := VarToStr(Value);
if cellValue = '已完成' then
Attribs.Color := $E8F5E9 // 绿色系
else if cellValue = '已取消' then
Attribs.Color := $EFEBE9 // 灰色系
else if cellValue = '处理中' then
Attribs.Color := $FFF8E1; // 黄色系
end;
直接在代码中使用十六进制颜色值不利于维护。建议定义颜色常量单元:
delphi复制unit GridColors;
interface
const
COLOR_HIGH_PRIORITY = $FFCCCC;
COLOR_MEDIUM_PRIORITY = $FFFFCC;
COLOR_LOW_PRIORITY = $CCFFCC;
COLOR_WARNING = $CCFFFF;
COLOR_ERROR = $FFCCFF;
implementation
end.
频繁的条件判断和着色操作可能影响网格渲染性能,特别是大数据量时:
减少数据集访问:避免在OnDrawColumnCell中多次访问DataSet.FieldByName,改为在BeforeShow事件中预先获取字段引用。
条件短路优化:将最可能满足的条件放在前面判断。
启用缓存:设置UniDBGrid.ClientEvents.ExtEvents.Properties添加buffered: true配置。
delphi复制procedure TMainForm.UniDBGrid1BeforeShow(Sender: TObject);
begin
// 预先获取字段引用
FStatusField := UniDBGrid1.DataSource.DataSet.FieldByName('status');
FPriorityField := UniDBGrid1.DataSource.DataSet.FieldByName('priority');
end;
procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
begin
// 使用预先获取的字段引用
if FPriorityField.AsInteger > 3 then
Attribs.Color := COLOR_HIGH_PRIORITY
else if FStatusField.AsString = 'expired' then
Attribs.Color := COLOR_WARNING;
end;
当颜色显示与预期不符时,通常是因为:
颜色格式问题:UniGUI使用HTML格式的RGB颜色值,与Delphi VCL的TColor不同。转换方法:
delphi复制function VclColorToHtml(AColor: TColor): string;
begin
Result := Format('#%.2x%.2x%.2x',
[GetRValue(AColor), GetGValue(AColor), GetBValue(AColor)]);
end;
透明度影响:某些主题会为单元格添加透明度,可通过设置强制不透明:
delphi复制Attribs.Style := 'background-color: #FF0000 !important;';
当数据变化需要刷新着色时,必须调用:
delphi复制UniDBGrid1.Refresh;
但频繁刷新会影响性能,建议配合定时器或手动刷新按钮使用。
结合着色功能实现状态仪表盘效果:
delphi复制procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
var
progress: Double;
begin
if Column.FieldName = 'completion_rate' then
begin
progress := Column.Field.AsFloat;
if progress < 0.3 then
Attribs.Color := $FFDDDD // 红色系
else if progress < 0.6 then
Attribs.Color := $FFF4DD // 橙色系
else if progress < 0.9 then
Attribs.Color := $FFFFDD // 黄色系
else
Attribs.Color := $DDFFDD; // 绿色系
// 添加文字百分比显示
Attribs.Text := Format('%.0f%%', [progress * 100]);
end;
end;
实现交替行着色和鼠标悬停效果需要结合CSS:
delphi复制procedure TMainForm.UniFormCreate(Sender: TObject);
begin
with UniDBGrid1.ClientEvents do
begin
UniEvents.Add(
'afterCreate=function afterCreate(sender){ '+
' sender.addCls("alternate-rows"); '+
' sender.on("mouseover", function(grid, row){ '+
' row.addCls("row-highlight"); '+
' }); '+
' sender.on("mouseout", function(grid, row){ '+
' row.removeCls("row-highlight"); '+
' }); '+
'}');
CSS.Add(
'.alternate-rows .x-grid-item:nth-child(even) { '+
' background-color: #F5F5F5; '+
'}'+
'.row-highlight { '+
' background-color: #E3F2FD !important; '+
'}');
end;
end;
在UniDBGrid的OnDrawColumnCell事件中,我们可以进一步强化这种效果:
delphi复制procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
var
grid: TUniDBGrid;
rowIndex: Integer;
begin
grid := Sender as TUniDBGrid;
rowIndex := grid.DataSource.DataSet.RecNo;
// 保留斑马线基础色
if Odd(rowIndex) then
Attribs.Style := Attribs.Style + 'background-color: #FAFAFA;';
// 业务逻辑着色...
end;
推荐使用在线工具检查颜色对比度:
当应用支持多主题时,着色应考虑主题兼容性:
delphi复制function GetThemeAwareColor(ABaseColor: string): string;
begin
if UniSession.Theme = 'neptune' then
Result := LightenColor(ABaseColor, 20%)
else if UniSession.Theme = 'triton' then
Result := DarkenColor(ABaseColor, 10%)
else
Result := ABaseColor;
end;
procedure TMainForm.UniDBGrid1DrawColumnCell(Sender: TObject;
const Value: Variant; const Column: TUniDBGridColumn;
Attribs: TUniCellAttribs);
begin
if Column.FieldName = 'status' then
begin
case Column.Field.AsString of
'active': Attribs.Color := GetThemeAwareColor('#E8F5E9');
'pending': Attribs.Color := GetThemeAwareColor('#FFF8E1');
// ...
end;
end;
end;
临时添加调试输出:
delphi复制UniSession.AddJS('console.log("Field: ' + Column.FieldName +
', Value: ' + VarToStr(Value) + '")');
使用Chrome开发者工具检查最终应用的CSS样式
创建测试按钮验证着色逻辑:
delphi复制procedure TMainForm.btnTestColorsClick(Sender: TObject);
begin
UniDBGrid1.DataSource.DataSet.DisableControls;
try
UniDBGrid1.DataSource.DataSet.First;
while not UniDBGrid1.DataSource.DataSet.Eof do
begin
UniDBGrid1DrawColumnCell(UniDBGrid1,
UniDBGrid1.DataSource.DataSet.FieldByName('test_field').AsVariant,
UniDBGrid1.Columns[0],
TUniCellAttribs.Create);
UniDBGrid1.DataSource.DataSet.Next;
end;
finally
UniDBGrid1.DataSource.DataSet.EnableControls;
end;
end;
delphi复制var
startTime: Cardinal;
begin
startTime := GetTickCount;
try
// 着色逻辑...
finally
UniSession.AddJS(Format('console.log("Render time: %dms")',
[GetTickCount - startTime]));
end;
end;
经过多个UniGUI项目的实践验证,以下着色方案最为可靠:
典型的企业级实现架构如下:
code复制Application
├── BusinessRules
│ └── GridColorSchemes.pas (业务着色逻辑)
├── UI
│ └── Grids
│ └── CustomerGrid.pas (自定义网格组件)
└── Infrastructure
└── ColorUtils.pas (颜色转换辅助函数)
对于需要频繁更新的实时监控界面,建议采用WebSocket推送更新指令,而非定时刷新整个网格。同时可以结合前端库如D3.js实现更复杂的数据可视化效果,通过UniGUI的CustomJS功能集成到Delphi应用中。