我有TListView
进行了一些修改。它包括每行的一些图标(几个,取决于项目),以及在满足某些条件时行的背景的可能性。
似乎渲染得很好。但是当我将鼠标移到窗口上时出现问题,似乎行正在重新渲染,这会产生不必要的延迟,更重要的是,它似乎会混淆可视化。如果我做某事(比如选择一行),它应该只重新绘制。
如何强行停止(鼠标悬停时看似令人耳目一新的行)?目前我正在使用AdvancedCustomDrawItem
来绘制。窗口对选择的项目作出反应也需要一秒钟,这似乎很无聊。
基本上,每行都有DrawText()
并在Sender.Canvas
上绘制图像。这无疑是一个缓慢的进展,但它现在有效,如果它只是在我将鼠标悬停在它们上面时似乎没有重绘行!事实上,如果我使用Aero主题,当您将鼠标悬停在它们上方时,这些行会变黑。
以下是AdvancedCustomDrawItem
上的事件代码:
procedure TfrmJobQueue.ListView1AdvancedCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
const
DT_ALIGN: array[TAlignment] of integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
var
r: TRect;
SL: TStringList;
TypeName: string;
I: Integer;
TypeState: integer;
x1,x2: Integer;
S: string;
begin
if Stage = cdPostPaint then begin
// Ways I tried to avoid it; but failed.
if cdsHot in State then
exit;
if cdsNearHot in State then
exit;
if cdsOtherSideHot in State then
exit;
if cdsMarked in State then
exit;
if cdsIndeterminate in State then
exit;
Sender.Canvas.Brush.Style := bsSolid;
if FRepLines.Items[Item.Index].IsAutoReport then begin
Sender.Canvas.Font.Color := clBlack;
Sender.Canvas.Brush.Color := clSkyBlue;
end else begin
Sender.Canvas.Font.Color := clBlack;
Sender.Canvas.Brush.Color := clWhite;
end;
if cdsSelected in State then begin
Sender.Canvas.Font.Color := clWhite;
Sender.Canvas.Brush.Color := clNavy;
end;
R := Item.DisplayRect(drBounds);
Sender.Canvas.FillRect(R);
Sender.Canvas.Brush.Style := bsClear;
if cdsFocused in State then
DrawFocusRect(Sender.Canvas.Handle, R);
x1 := 0;
x2 := 0;
for i := 0 to TListView(Sender).Columns.Count - 1 do
begin
inc(x2, Sender.Column[i].Width);
r.Left := x1;
r.Right := x2;
if i = 0 then
S := Item.Caption
else
S := Item.SubItems[i-1];
if DT_ALIGN[Sender.Column[i].Alignment] = DT_LEFT then
S := ' ' + S;
DrawText(Sender.Canvas.Handle,
S, length(S), r,
DT_SINGLELINE or DT_ALIGN[Sender.Column[i].Alignment] or
DT_VCENTER or DT_END_ELLIPSIS);
x1 := x2;
end;
r := Item.DisplayRect(drIcon);
SL := TStringList.Create;
SL.CommaText := FRepLines.Value(Item.Index, 'TypeState');
r.Left := Sender.Column[0].Width + Sender.Column[1].Width + Sender.Column[2].Width + Sender.Column[3].Width
+ Sender.Column[4].Width;
for I := 0 to SL.Count - 1 do begin
if GetTypeImagesIndex(SL.Names[I]) = -1 then
continue;
// FRepLines is a collection of items containing more information about each row.
if FRepLines.Value(Item.Index, 'State') <> '1' then begin // no error
TypeName := SL.Names[I];
TypeState := StrToIntDef(SL.Values[TypeName], 0);
// State*Images are TImageList.
if TypeState = 0 then
StateWaitingImages.Draw(Sender.Canvas, r.Left + 17*I, r.Top,
GetTypeImagesIndex(TypeName))
else
StateDoneImages.Draw(Sender.Canvas, r.Left + 17*I, r.Top,
GetTypeImagesIndex(TypeName));
CreateIconToolTip(StrToIntDef(FRepLines.Value(Item.Index, 'RepJob'), -1),
TypeName, r.Left + 17*I, ListView1.ViewOrigin.Y + r.Top,
Format(TranslateString('RepQTypeState'),
[TranslateString(Format('RepQTypeStateN%s', [TypeName])),
TranslateString(Format('RepQTypeState-%d', [TypeState]))]));
end;
end;
end;
end;
代码的一些解释:
列表是报告列表(报告队列)。我正在介绍“AutoReports”(或UI中的预定报告)的概念,我想用浅蓝色背景(clSkyBlue
)突出显示。
除了该背景,它还在状态列上绘制了一些图标,指示报告所处的阶段,以及报告的格式(PDF,Excel和HTML等格式),以及是否已打印和/或通过电子邮件发送。如果此类事件已已订购,则仅显示图标,因此图标数量可变。
等待状态图像是完成状态图像的灰色版本。我还尝试创建一些代码,因此当我将鼠标悬停在特定图标上时,它会显示一个工具提示消息。
因为代码速度相当迟钝,我怀疑我做的事情非常糟糕。
答案 0 :(得分:3)
可能已启用HotTracking。这会导致项目在被鼠标悬停时重绘,因此鼠标下的项目可以以不同方式呈现。绘图时你可能忽略了hottrack状态。这可能是造成黑暗的原因。
您应该分析您的代码以找到真正的瓶颈。绘图代码需要快速。我在ListView中做了很多自定义绘图,它的行为并不像你描述的那样慢。
更新:考虑重新编写代码以在OnAdvancedCustomDrawSubItem
事件中绘制单个列,而不是在OnAdvancedCustomDrawItem
事件中执行所有操作。此外,您不需要手动计算每个列的边界,而是可以使用ListView_GetSubItemRect()
。最后,您泄露了TStringList
。