Delphi 如何在所有者绘制的ListView中恢复高亮显示功能

Delphi 如何在所有者绘制的ListView中恢复高亮显示功能,delphi,ownerdrawn,tlistview,Delphi,Ownerdrawn,Tlistview,我编写了一些代码,使第一行为白色,第二行为灰色,第三行为白色,依此类推。要做到这一点,我必须使用OwnerDraw=true,但现在当您将鼠标悬停在一行上时,ListView不再像以前那样响应。我怎么把它加回去 这就是我现在拥有的: 过程TachevementTracker.lvAchievementsDrawItemSender:TSMView; 项目:TSMListItem;Rect:TRect;州:TOwnerDrawState; 变量 i:整数; x1,x2:整数; r:TRect; S

我编写了一些代码,使第一行为白色,第二行为灰色,第三行为白色,依此类推。要做到这一点,我必须使用OwnerDraw=true,但现在当您将鼠标悬停在一行上时,ListView不再像以前那样响应。我怎么把它加回去

这就是我现在拥有的:

过程TachevementTracker.lvAchievementsDrawItemSender:TSMView; 项目:TSMListItem;Rect:TRect;州:TOwnerDrawState; 变量 i:整数; x1,x2:整数; r:TRect; S:字符串; 常数 DT_ALIGN:integer=DT_LEFT,DT_RIGHT,DT_CENTER的数组[TAlignment]; 开始 如果是oddbitem.Index,则 开始 Sender.Canvas.Font.Color:=clBlack; Sender.Canvas.Brush.Color:=$F6F6F6; 终止 其他的 开始 Sender.Canvas.Font.Color:=clBlack; Sender.Canvas.Brush.Color:=clWhite; 终止 Sender.Canvas.Brush.Style:=bsSolid; Sender.Canvas.FillRect; x1:=0; x2:=0; r:=Rect; Sender.Canvas.Brush.Style:=bsClear; 对于i:=0到lva.Columns.Count-1 do 开始 incx2,lvx.Columns[i].宽度; r、 左:=x1; r、 右:=x2; 如果i=0,那么 S:=项。标题 其他的 S:=''+项目。子项目[i-1]; DrawTextSender.Canvas.Handle, s 长度, R DT_单线或DT_对齐[i.Columns[i].ALIGN]或 DT_VCENTER或DT_END_省略号; x1:=x2; 终止 终止
与使用完全所有者图形相比,有一种更简单的方法为列表视图控件的线条着色。即使OwnerDraw为False,也可以使用OnCustomDrawItem事件:

程序TForm1.ListView1CustomDrawItemSender:TCustomListView; 项目:技术指标;州:TCustomDrawState;var-DefaultDraw:布尔型; 常数 BgColors:TColor=clWhite,clSilver的数组[Boolean]; FgColors:TColor=clBlack,clBlack的数组[Boolean]; 开始 Sender.Canvas.Brush.Color:=BgColors[OddItem.Index]; Sender.Canvas.Font.Color:=FgColors[OddItem.Index]; 终止 这实际上保留了主题悬停和选定效果:

问题是,标准主题效果通常与定制颜色一起看起来很糟糕

因此,最好完全自定义绘制OwnerDraw=True:

过程TForm1.ListView1DrawItemSender:TCustomListView;项目:技术指标; Rect:TRect;州:TOwnerDrawState; 常数 BgColors:TColor=clWhite,clSilver的数组[Boolean]; FgColors:TColor=clBlack,clBlack的数组[Boolean]; 对齐:TTextFormats的数组[TAlignment]=tfLeft、tfRight、tfCenter; 变量 LV:TListView; i、 x1,x2:整数; R:TRect; S:字符串; 开始 LV:=作为TListView的发送方; 如果[odSelected,odHotLight]*状态[],则 开始 LV.Canvas.Brush.Color:=clNavy; LV.Canvas.Font.Color:=clWhite; 终止 其他的 开始 LV.Canvas.Brush.Color:=BgColors[OddItem.Index]; LV.Canvas.Font.Color:=FgColors[OddItem.Index]; 终止 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.fillrect; x1:=0; x2:=0; R:=Rect; LV.Canvas.Brush.Style:=bClear; 对于i:=0到LV.Columns.Count-1 do 开始 Incx2,LV.列[i]。宽度; R.左:=x1; R.右:=x2; 如果i=0,那么 S:=项。标题 其他的 S:=项目.子项目[i-1]; S:=32+S; LV.Canvas.TextRectR,S,[tfSingleLine, 路线[LV.Columns[i].路线]、tfVerticalCenter、tfEndEllipsis]; x1:=x2; 终止 如果在状态中,则 开始 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.Brush.Color:=clBlack; LV.Canvas.Font.Color:=clWhite; 直肠充气-1,-1; DrawFocusRectLV.Canvas.Handle,Rect; 终止 终止 不幸的是,正如您所看到的,这引入了新的问题,例如对齐问题,我在这段代码中以非常草率的方式解决了这个问题。而且,这种方法似乎不允许产生悬停热效果。上面的代码段支持高亮显示和聚焦,但不支持悬停

好的,我们开始吧! 如果你真的,真的,想要热的效果,总有一种方法:

将列表视图控件的标记设置为-1,让

过程TForm1.ListView1DrawItemSender:TCustomListView;项目:技术指标; Rect:TRect;州:TOwnerDrawState; 常数 BgColors:TColor=clWhite,clSilver的数组[Boolean]; FgColors:TColor=clBlack,clBlack的数组[Boolean]; 对齐:TTextFormats的数组[TAlignment]=tfLeft、tfRight、tfCenter; 变量 LV:TListView; i、 x1,x2:整数; R:TRect; S:字符串; 开始 LV:=作为TListView的发送方; 如果ListView1.Tag=Item.Index,则// 开始// LV.Canvas.Brush.Color:=clSkyBlue;//刚出现的 LV.Canvas.Font.Color:=clBlack// 结束// 否则,如果在状态中选择了ODR,则 开始 LV.Canvas.Brush.Color:=clNavy; LV.Canvas.Font.Color:=clWhite; 终止 其他的 开始 LV.Canvas.Brush.Color:=BgColors[OddItem.Index]; LV.Canvas.Font.Color:=FgColors[OddItem.Index]; E 钕; LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.fillrect; x1:=0; x2:=0; R:=Rect; LV.Canvas.Brush.Style:=bClear; 对于i:=0到LV.Columns.Count-1 do 开始 Incx2,LV.列[i]。宽度; R.左:=x1; R.右:=x2; 如果i=0,那么 S:=项。标题 其他的 S:=项目.子项目[i-1]; S:=32+S; LV.Canvas.TextRectR,S,[tfSingleLine, 路线[LV.Columns[i].路线]、tfVerticalCenter、tfEndEllipsis]; x1:=x2; 终止 如果ODFocus处于状态而不是odNoFocusRect处于状态,则 开始 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.Brush.Color:=clBlack; LV.Canvas.Font.Color:=clWhite; 直肠充气-1,-1; DrawFocusRectLV.Canvas.Handle,Rect; 终止 终止 并添加以下OnMouseMove处理程序:

程序TForm1.ListView1MouseMoveSsender:ToObject;换档:t换档状态;X,, Y:整数; 变量 李:系统,; Idx:整数; 开始 LI:=ListView1.GetItemAtX,Y; 如果被指派,那么 Idx:=LI.索引 其他的 Idx:=-1; 如果Idx ListView1.Tag,则 开始 ListView1.Tag:=Idx; ListView1.Invalidate;//也许是杀伤力太大了 终止 终止 以及以下OnMouseLeave处理程序:

程序TForm1.ListView1MouseLeaveSender:ToObject; 开始 如果ListView1.Tag为-1,则 开始 ListView1.标记:=-1; ListView1.无效; 终止 终止
与使用完全所有者图形相比,有一种更简单的方法为列表视图控件的线条着色。即使OwnerDraw为False,也可以使用OnCustomDrawItem事件:

程序TForm1.ListView1CustomDrawItemSender:TCustomListView; 项目:技术指标;州:TCustomDrawState;var-DefaultDraw:布尔型; 常数 BgColors:TColor=clWhite,clSilver的数组[Boolean]; FgColors:TColor=clBlack,clBlack的数组[Boolean]; 开始 Sender.Canvas.Brush.Color:=BgColors[OddItem.Index]; Sender.Canvas.Font.Color:=FgColors[OddItem.Index]; 终止 这实际上保留了主题悬停和选定效果:

问题是,标准主题效果通常与定制颜色一起看起来很糟糕

因此,最好完全自定义绘制OwnerDraw=True:

过程TForm1.ListView1DrawItemSender:TCustomListView;项目:技术指标; Rect:TRect;州:TOwnerDrawState; 常数 BgColors:TColor=clWhite,clSilver的数组[Boolean]; FgColors:TColor=clBlack,clBlack的数组[Boolean]; 对齐:TTextFormats的数组[TAlignment]=tfLeft、tfRight、tfCenter; 变量 LV:TListView; i、 x1,x2:整数; R:TRect; S:字符串; 开始 LV:=作为TListView的发送方; 如果[odSelected,odHotLight]*状态[],则 开始 LV.Canvas.Brush.Color:=clNavy; LV.Canvas.Font.Color:=clWhite; 终止 其他的 开始 LV.Canvas.Brush.Color:=BgColors[OddItem.Index]; LV.Canvas.Font.Color:=FgColors[OddItem.Index]; 终止 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.fillrect; x1:=0; x2:=0; R:=Rect; LV.Canvas.Brush.Style:=bClear; 对于i:=0到LV.Columns.Count-1 do 开始 Incx2,LV.列[i]。宽度; R.左:=x1; R.右:=x2; 如果i=0,那么 S:=项。标题 其他的 S:=项目.子项目[i-1]; S:=32+S; LV.Canvas.TextRectR,S,[tfSingleLine, 路线[LV.Columns[i].路线]、tfVerticalCenter、tfEndEllipsis]; x1:=x2; 终止 如果在状态中,则 开始 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.Brush.Color:=clBlack; LV.Canvas.Font.Color:=clWhite; 直肠充气-1,-1; DrawFocusRectLV.Canvas.Handle,Rect; 终止 终止 不幸的是,正如您所看到的,这引入了新的问题,例如对齐问题,我在这段代码中以非常草率的方式解决了这个问题。而且,这种方法似乎不允许产生悬停热效果。上面的代码段支持高亮显示和聚焦,但不支持悬停

好的,我们开始吧! 如果你真的,真的,想要热的效果,总有一种方法:

将列表视图控件的标记设置为-1,让

过程TForm1.ListView1DrawItemSender:TCustomListView;项目:技术指标; Rect:TRect;州:TOwnerDrawState; 常数 BgColors:TColor=clWhite,clSilver的数组[Boolean]; FgColors:TColor=clBlack,clBlack的数组[Boolean]; 对齐:TTextFormats的数组[TAlignment]=tfLeft、tfRight、tfCenter; 变量 LV:TListView; i、 x1,x2:整数; R:TRect; S:字符串; 开始 LV:=作为TListView的发送方; 如果ListView1.Tag=Item.Index,则// 开始// LV.Canvas.Brush.Color:=clSkyBlue;//刚出现的 LV.Canvas.Font.Color:=clBlack// 结束// 否则,如果在状态中选择了ODR,则 开始 LV.Canvas.Brush.Color:=clNavy; LV.Canvas.Font.Color:=clWhite; 终止 其他的 开始 LV.Canvas.Brush.Color:=BgColors[OddItem.Index]; LV.Canvas.Font.Color:=FgColors[OddItem.Index]; 终止 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.FillRe ctRect; x1:=0; x2:=0; R:=Rect; LV.Canvas.Brush.Style:=bClear; 对于i:=0到LV.Columns.Count-1 do 开始 Incx2,LV.列[i]。宽度; R.左:=x1; R.右:=x2; 如果i=0,那么 S:=项。标题 其他的 S:=项目.子项目[i-1]; S:=32+S; LV.Canvas.TextRectR,S,[tfSingleLine, 路线[LV.Columns[i].路线]、tfVerticalCenter、tfEndEllipsis]; x1:=x2; 终止 如果ODFocus处于状态而不是odNoFocusRect处于状态,则 开始 LV.Canvas.Brush.Style:=bsSolid; LV.Canvas.Brush.Color:=clBlack; LV.Canvas.Font.Color:=clWhite; 直肠充气-1,-1; DrawFocusRectLV.Canvas.Handle,Rect; 终止 终止 并添加以下OnMouseMove处理程序:

程序TForm1.ListView1MouseMoveSsender:ToObject;换档:t换档状态;X,, Y:整数; 变量 李:系统,; Idx:整数; 开始 LI:=ListView1.GetItemAtX,Y; 如果被指派,那么 Idx:=LI.索引 其他的 Idx:=-1; 如果Idx ListView1.Tag,则 开始 ListView1.Tag:=Idx; ListView1.Invalidate;//也许是杀伤力太大了 终止 终止 以及以下OnMouseLeave处理程序:

程序TForm1.ListView1MouseLeaveSender:ToObject; 开始 如果ListView1.Tag为-1,则 开始 ListView1.标记:=-1; ListView1.无效; 终止 终止
请确认您使用的事件。实际上最好显示您现在的过程。检查状态是否为odFocused。如果为true,请使用高亮显示颜色。或者,如果您想显示鼠标悬停在某个项目上,请检查状态是否为odHotLight。威廉:当您从复制此代码时,您应该尝试完全理解它。在这种情况下,您首先想到的应该是阅读事件的文档。然后,您应该按照描述状态参数的页面链接进行操作:指示[…]它是选中的、灰色的还是聚焦的。但现在我进一步研究了这一点,我意识到热效应更难实现。@Tom:您可能是指odSelected,而不是odFocused。请确认您使用的事件。实际上最好显示您现在的过程。检查状态是否为odFocused。如果为true,请使用高亮显示颜色。或者,如果您想显示鼠标悬停在某个项目上,请检查状态是否为odHotLight。威廉:当您从复制此代码时,您应该尝试完全理解它。在这种情况下,您首先想到的应该是阅读事件的文档。然后,您应该按照描述状态参数的页面链接进行操作:指示[…]它是选中的、灰色的还是聚焦的。但现在我进一步研究了这一点,我意识到热效应更难实现。@Tom:您可能是指odSelected,而不是odFocused。我试图将代码移动到CustomDrawItem,将OwnerDraw设置为False,并使用Item.DisplayRectdrBounds来补偿缺少的Rect参数,这样就可以响应热状态。然而,结果是Delphi 10.3、Win7 64位、Aero、高DPI的缺陷非常严重!有人能证实这一点吗?我认为这突出了一个原则或规律:按照预期的方式使用GUI控件这样的系统很容易,无需任何修改,也很容易从头开始编写一个自定义控件,因此您可以完全控制所有细节。然而,定制现有系统以满足您自己的、非标准的需求是很困难的。似乎这种方法不允许您产生悬停热效果-如果odHotLight不工作,手动实现相当容易。使用OnMouseMove事件始终通过或直接使用跟踪鼠标下的项目,然后让绘图代码在决定使用哪种颜色时将其与正在绘制的项目进行比较。或者,改为查看。当然,但是复杂性会增加得更多,您可能会问自己,这是否值得。我尝试将代码移动到CustomDrawItem,将OwnerDraw设置为False,并使用Item.DisplayRectdrBounds来补偿缺少的Rect参数,这使得响应热状态成为可能。然而,结果是Delphi 10.3、Win7 64位、Aero、高DPI的缺陷非常严重!有人能证实这一点吗?我认为这突出了一个原则或规律:按照预期的方式使用GUI控件这样的系统很容易,无需任何修改,也很容易从头开始编写一个自定义控件,因此您可以完全控制所有细节。然而,定制现有系统以满足您自己的、非标准的需求是很困难的。似乎这种方法不允许您产生悬停热效果-如果odHotLight不工作,手动实现相当容易。使用OnMouseMove事件始终通过或直接使用跟踪鼠标下的项目,然后让绘图代码在确定哪个c时将其与正在绘制的项目进行比较
要使用的颜色。或者,看一下。当然,但是复杂性会增加更多,你可能会问自己,这是否真的值得。