-2

我有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;

代码的一些解释:

该列表是报告列表(报告队列)。我正在介绍“自动报告”(或 UI 中的预定报告)的概念,我想用浅蓝色背景 ( clSkyBlue) 突出显示它。

除了这个背景之外,它还在状态列上绘制了一些图标,指示报告处于什么阶段,此外,报告的排序格式(PDF、Excel 和 HTML 等格式)以及它是否具有已打印和/或通过电子邮件发送。仅当已订购此类事件时才会出现图标,因此图标的数量是可变的。

等待状态图像是完成状态图像的灰色版本。我还尝试创建一些代码,因此当我将鼠标悬停在特定图标上时,它会显示工具提示消息。

因为代码速度相当慢,我怀疑我做错了什么。

4

1 回答 1

3

HotTracking 可能已启用。这会导致项目在鼠标悬停时重绘,因此鼠标下的项目可以以不同的方式呈现。您可能在绘图时忽略了热轨状态。这可以解释黑色。

您应该分析您的代码以找到真正的瓶颈。绘制代码需要快速。我在 ListView 中做了很多自定义绘图,它的行为不像你描述的那样缓慢。

更新:考虑重新编写代码以在事件中绘制单独的列,OnAdvancedCustomDrawSubItem而不是在事件中做所有事情OnAdvancedCustomDrawItem。此外,您不需要手动计算每列的边界,您可以使用它ListView_GetSubItemRect()来代替。最后,您正在泄漏您的TStringList.

于 2013-10-17T15:32:14.357 回答