Delphi TListview OwnerDraw SubItems - 更改默认字体(在画布上绘制后以某种方式显示为粗体)

时间:2012-11-21 03:11:57

标签: delphi ownerdrawn tlistview

如果你使用带有TListView的ownerdraw,那么默认情况下子项都是BOLD字体样式,即使listview font.style被设置为[],对于自定义绘制后的所有子项也是如此。

我找到的解决方法是强制在CustomDrawSubItem事件中设置样式:

ListView2.Canvas.Font.Style := [fsItalic];
ListView2.Canvas.Font.Style := [];

(除非将默认样式设置为[]之外的其他内容,否则使用[]进行简单调用将无效,因为SetStyle调用不认为样式已更改)

然而,这是一个丑陋的修复,涉及额外的处理时间。有更好的解决方案吗?

演示项目:http://www.mediafire.com/?v8bsdpvpfqy47vn

2 个答案:

答案 0 :(得分:3)

我没有遇到您描述的确切情况,但我遇到了类似的问题。当我使用所有者绘制的TListView并分配了OnAdvancedCustomDrawSubItem个事件来基于每个子项更改Canvas.Font时,我发现在我更改了Sender.Canvas.Font之后一个子项目,即使我为它们更改Sender.Canvas.Font,也会使用错误的设置绘制后续子项目。我的解决方法是在Sender.Canvas.Font.OnChange事件处理程序的末尾手动调用OnAdvancedCustomDrawSubItem事件处理程序。这表示TListView向Windows报告CDRF_NEWFONT,然后一切都被正确绘制。就好像Sender.Canvas.Font.OnChange事件在TListView被所有者绘制时没有正确连接,因此它不会检测字体更改,因此不会正确地向Windows报告。

答案 1 :(得分:3)

我同意jachguate的comment,因为VCL控件似乎存在问题; TCustomListView.CNNotify的可能设计问题。但要遵循那里的逻辑并不容易。

一种解决方案是在DefaultDraw为true时强制对控件的画布进行更改,以便VCL在自定义绘图通知返回之前再次创建并选择控件的字体到传递的DC。例如:

procedure TForm1.LVCustomDrawSubItem(Sender: TCustomListView; Item: TListItem;
  SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean);
Var R: TRect;
    bmp: TBitmap;
    x: Integer;
begin
  DefaultDraw := True;

  if SubItem = 1 then begin
    DefaultDraw := False;
    ...
      ...       
      Sender.Canvas.Draw(R.Left - 2, R.Top, Bmp);
      Bmp.Free;
    end;
  end;

  if DefaultDraw then
    Sender.Canvas.Brush.Color := ColorToRGB(clWindow);     // <--
end;


我喜欢的方法是尽可能避免使用控件的画布。您可以为您的案例使用临时DC,这也避免了问题评论中提到的黑色背景问题。

uses
  commctrl;

  ...

procedure TForm1.LVCustomDrawSubItem(Sender: TCustomListView; Item: TListItem;
  SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean);
Var R: TRect;
    bmp: TBitmap;
    x: Integer;
    DC: HDC;
begin
  DefaultDraw := True;

  if SubItem = 1 then begin
    DefaultDraw := False;
    ...
      ...

      DC := GetDC(Sender.Handle);
      ImageList_Draw(TypeImages.Handle, 0, DC, R.Left - 2, R.Top, ILD_NORMAL);
      ReleaseDC(Sender.Handle, DC);

      Bmp.Free;
    end;
  end;
end;