如果你使用带有TListView的ownerdraw,那么默认情况下子项都是BOLD字体样式,即使listview font.style被设置为[],对于自定义绘制后的所有子项也是如此。
我找到的解决方法是强制在CustomDrawSubItem事件中设置样式:
ListView2.Canvas.Font.Style := [fsItalic];
ListView2.Canvas.Font.Style := [];
(除非将默认样式设置为[]之外的其他内容,否则使用[]进行简单调用将无效,因为SetStyle调用不认为样式已更改)
然而,这是一个丑陋的修复,涉及额外的处理时间。有更好的解决方案吗?
答案 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;