Delphi TListView SelCount报告虚拟列表中的项目数错误
我需要根据列表中是否至少选择了一行来启用或禁用按钮 下面是重现此问题的代码。该列表使用OnData事件填充,并允许选择多行 我认为可以使用OnSelectItem来检测用户何时更改选择,然后使用TListView SelCount函数来检测所选行的数量 问题在于,当用户选择多行时,SelCount返回0。如果列表是手动填充的(即,不是通过OnData事件填充的),则此选项可以正常工作 有什么想法吗 谢谢 更新:改用OnChange事件似乎可以解决这个问题。不过,理解为什么SelCount在选择多行(从SelectItem事件中)时返回0还是很有意思的 另一个更新:我发布了一个测试项目:以及一个屏幕截图: 要重现此问题,请运行应用程序,选择Item1,然后按住SHIFT键并单击Item2。该按钮已禁用。我的意图是动态启用按钮,只要列表中至少选择了一项。如果没有选定的项目,则按钮被禁用 PAS文件:Delphi TListView SelCount报告虚拟列表中的项目数错误,delphi,vcl,delphi-xe5,tlistview,Delphi,Vcl,Delphi Xe5,Tlistview,我需要根据列表中是否至少选择了一行来启用或禁用按钮 下面是重现此问题的代码。该列表使用OnData事件填充,并允许选择多行 我认为可以使用OnSelectItem来检测用户何时更改选择,然后使用TListView SelCount函数来检测所选行的数量 问题在于,当用户选择多行时,SelCount返回0。如果列表是手动填充的(即,不是通过OnData事件填充的),则此选项可以正常工作 有什么想法吗 谢谢 更新:改用OnChange事件似乎可以解决这个问题。不过,理解为什么SelCount在选择多
unit MainUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls;
type
TForm3 = class(TForm)
ListView1: TListView;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
begin
ListView1.Items.Count := 5;
end;
procedure TForm3.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := String.Format('Item%d', [Item.Index]);
end;
procedure TForm3.ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
begin
Button1.Enabled := ListView1.SelCount > 0;
OutputDebugString(pchar(String.Format('SelCount = %d', [ListView1.SelCount])));
end;
end.
表格:
对象格式3:t格式3
左=0
Top=0
标题='Form3'
ClientHeight=600
ClientWidth=952
颜色=clBtnFace
双缓冲=真
Font.Charset=默认字符集
Font.Color=clWindowText
字体高度=-11
Font.Name='Tahoma'
Font.Style=[]
OldCreateOrder=False
OnCreate=FormCreate
PixelsPerInch=96
text高度=13
对象列表视图1:TListView
左=168
Top=160
宽度=250
高度=150
列=<
项目
自动调整大小=真
标题=‘测试’
结束>
HideSelection=False
多选=真
OwnerData=True
TabOrder=0
ViewStyle=vsReport
OnData=ListView1Data
OnSelectItem=ListView1SelectItem
结束
对象按钮1:t按钮
左=168
顶部=120
宽度=75
高度=25
标题=‘一些动作’
已启用=错误
TabOrder=1
结束
结束
根本问题是,当按住SHIFT键并单击多个项目时,对于已选择的项目,将不会获得任何OnSelectItem
事件。按住SHIFT键并单击可首先取消选中所有列表视图项目,触发单个OnSelectItem
事件,其中Item=nil
和Selected=False
,然后选择新项目。在该事件发生时,TListView.SelCount
实际上是0,因此您禁用了按钮,但没有进一步的OnSelectItem
事件告诉您已选择了新项目,因此您不必再次选中SelCount
来重新启用按钮
当单个项目在选定和未选定之间更改状态时,或者当整个ListView中的所有项目更改为相同的选定/未选定状态时,将触发OnSelectItem
事件以响应通知。但是,在虚拟模式下,当多个连续项目同时更改为相同状态时,Windows可以为该范围的项目发送单个通知tListLeaw
在接收到LVN\u ODSTATECHANGED
时,不会触发选择项上的OnDataStateChange
,而是触发OnDataStateChange
,例如:
procedure TForm3.ListView1DataStateChange(Sender: TObject; StartIndex, EndIndex: Integer; OldState, NewState: TItemStates);
begin
if (NewState * [isSelected]) <> (OldState * [isSelected]) then
Button1.Enabled := ListView1.SelCount > 0;
end;
每当主消息队列空闲时,包括在处理ListView通知消息之后,将自动启用/禁用关联的
t按钮。这样,无论使用何种输入组合来选择/取消选择ListView项,您都可以保持t按钮的更新。fyi-我无法用Delphi 7再现错误。-1问题中的代码在XE5中按预期工作,而不是如您所述。@DavidHeffernan:您在哪个操作系统上运行它?我正在使用Windows 7 64位和XE5的最新更新。您可以从以下位置下载项目:。我使用sysinternals DebugView来查看输出。当我在列表中选择多个项目时,仅触发一个SelectItem事件,SelCount为0。如果我只选择一项,则会触发两个事件。我在另一台Windows 7 64位计算机上测试了该项目,其行为与此相同。此处为Win7 x64。当且仅当选择>0项时,按钮才启用。我想指出,控制属性(如启用)的正确方法是通过操作和操作列表/管理器。尽管我同意在这种情况下,操作列表/管理器肯定是正确的方法(因此,在这种情况下,实际的LV问题变得无关紧要),在其他一些情况下,Q和A都非常有价值。例如,您经常希望在状态栏中显示类似“%d个选定项”的内容。@AndreasRejbrand我仍然会使用TAction.OnUpdate
事件进行此类显示,例如:procedure TForm3.MyActionUpdate(发件人:TObject);begin StatusBar1.Panels[0]。文本:=格式(“%d个选定项”,[ListView1.SelCount]);结束代码>我通常不会那样做,但我同意这有明显的好处。
procedure TForm3.ListView1DataStateChange(Sender: TObject; StartIndex, EndIndex: Integer; OldState, NewState: TItemStates);
begin
if (NewState * [isSelected]) <> (OldState * [isSelected]) then
Button1.Enabled := ListView1.SelCount > 0;
end;
procedure TForm3.MyActionUpdate(Sender: TObject);
begin
MyAction.Enabled := ListView1.SelCount > 0;
end;