Delphi 如何有选择地使所有者绘制的TListBox无效';什么是帆布?

Delphi 如何有选择地使所有者绘制的TListBox无效';什么是帆布?,delphi,ownerdrawn,Delphi,Ownerdrawn,我有一个所有者绘制的TListBox(lbVirtualOwnerDraw),它的内容会动态更新(一秒钟内可能有多达10次更新)。列表框中一次最多可以有300个项目。每个项目可能有大约5行文本和一个与之关联的图像。每当刷新一个项目时,我都必须刷新(或使之无效)TListBox,以便VCL框架调用ListBoxDrawItem。但这会对整体性能产生不利影响,因为所有重复的重新喷漆都会造成影响。所以我的问题是: 是否有一种方法可以仅使画布的一小部分无效,其中包含一个项目或其一部分的绘图?(例如,包含

我有一个所有者绘制的TListBox(lbVirtualOwnerDraw),它的内容会动态更新(一秒钟内可能有多达10次更新)。列表框中一次最多可以有300个项目。每个项目可能有大约5行文本和一个与之关联的图像。每当刷新一个项目时,我都必须刷新(或使之无效)TListBox,以便VCL框架调用ListBoxDrawItem。但这会对整体性能产生不利影响,因为所有重复的重新喷漆都会造成影响。所以我的问题是:

  • 是否有一种方法可以仅使画布的一小部分无效,其中包含一个项目或其一部分的绘图?(例如,包含一行文本或位图的矩形)

  • 如何处理绘图项中的这种选择性无效矩形?若可以传递一个整数作为刷新或失效的一部分,我可以在DrawItem中使用它来确定要刷新的内容

  • 有没有办法找到一个项目在TListBox上是否可见(通过索引)

  • 提前谢谢

    您可以使用api使窗口的一部分无效。要查找项目占用的区域,可以使用列表框的方法。例如,要使第4项无效:

    var
      R: TRect;
    begin
      R := ListBox1.ItemRect(3);
      InvalidateRect(ListBox1.Handle, @R, True);
    end;
    
    (或“False”作为“失效”的“bErase”,参见其文档)。要仅使位图或文本无效,请在传递到invalidate之前相应地修改矩形


    您不能传递索引或任何类型的用户数据来刷新或使其无效。在绘制例程中,您必须根据位置确定正在绘制的项目,或者在绝对必要时使用全局变量。但您不需要这样做,如果您仅使一个项的一部分无效,则只会为该项调用
    OnDrawItem
    。在任何情况下,不要太担心绘制非无效项,因为在更新区域之外不会有任何实际的图形,所以不会有任何显著的性能影响(请参见第3段)



    要确定某个项目是否可见,可以从顶部的第一个可见项目开始,将连续项目的高度添加到控件的ClientHeight。最重要的项目是在。如果项目的高度是固定的,那么您已经知道最多可以看到多少项目。如果没有,则需要对它们进行汇总。

    结果如下:列表中的每个项目都会调用ListBox DrawItem,即使只有一个项目的一小部分无效。此外,在DrawItem中选中时,Canvas.ClipRect始终是整个ListBox客户端区域。这使得我们无法确定这张图是否是由错误引起的。一件好事是,如果我更新了一个不在可见区域的列表项,那么它就不会调用DrawItem.BTW,我使用的是Delphi7。我做了更多的研究,试图理解底层的ListBox绘制方法。在“TCustomListBox.WMPaint”中,有一条评论说“{listbox不允许像其他windows控件那样对paint进行“子分类”,因此我们必须自己进行。在该方法中,在分派DrawItemMsg之前,它会获取剪贴簿矩形(GetClipBox(Message.DC,R))。但是,TRect,R没有在任何地方使用!我错过什么了吗?谢谢@ssh-在发布答案之前,我已经测试了无效性,我的测试“OnDrawItem”只启动了一次,并且只针对第四个项目。我还尝试在传递的矩形外绘制(绘制前偏移矩形),在无效矩形外没有绘制任何内容。我使用了一个“lbOwnerDrawFixed”列表框,但它不会有什么区别。在你的评论之后,我也看了一下“ClipRect”,它被正确地剪裁了。您使用的是列表框的画布,而不是表单,对吗?如果可以,请使用新应用程序进行测试。@ssh-使用D2007和D3进行测试,结果相同。谢谢Sertac Akyuz!是的,我正在用一个简单的应用程序测试它,以找出细微差别。让我再检查一下,我可能弄错了。能否检查StdCtrls.pas中的TCustomListBox.WMPaint代码?该方法为列表中的每个项目分派DrawItemMsg,如下代码片段=>[Y:=0;而Y