gpt4 book ai didi

delphi - TListView SelCount 报告虚拟列表中的项目数错误

转载 作者:行者123 更新时间:2023-12-03 14:53:37 25 4
gpt4 key购买 nike

我需要根据是否在列表中至少选择一行来启用或禁用按钮。

下面是重现此问题的代码。该列表是使用 OnData 事件填充的,并且允许选择多行。

我认为我可以使用 OnSelectItem 来检测用户何时更改选择,然后使用 TListView SelCount 函数来检测所选行的数量。

问题是当用户选择多行时 SelCount 返回 0。如果列表是手动填充的(即不通过 OnData 事件),则此方法可以正常工作。

有什么想法吗?

谢谢

更新:使用 OnChange 事件似乎可以解决问题。不过,理解为什么当选择多行时(从 SelectItem 事件中)SelCount 返回 0 仍然会很有趣。

另一个更新:我发布了一个测试项目:https://dl.dropboxusercontent.com/u/35370420/TestListView2.zip以及屏幕截图:

enter image description here

要重现此问题,请运行应用程序,选择 Item1,然后按住 SHIFT 键并单击 Item2。该按钮被禁用。我的目的是只要列表中至少选择了一项,就动态启用该按钮。如果没有选定的项目,该按钮将被禁用。

PAS 文件:

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.

表格:

object Form3: TForm3
Left = 0
Top = 0
Caption = 'Form3'
ClientHeight = 600
ClientWidth = 952
Color = clBtnFace
DoubleBuffered = True
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object ListView1: TListView
Left = 168
Top = 160
Width = 250
Height = 150
Columns = <
item
AutoSize = True
Caption = 'Test'
end>
HideSelection = False
MultiSelect = True
OwnerData = True
TabOrder = 0
ViewStyle = vsReport
OnData = ListView1Data
OnSelectItem = ListView1SelectItem
end
object Button1: TButton
Left = 168
Top = 120
Width = 75
Height = 25
Caption = 'Some Action'
Enabled = False
TabOrder = 1
end
end

最佳答案

根本问题是,当您 SHIFT+Click 多个项目时,您将不会获得已选择项目的任何 OnSelectItem 事件。 SHIFT+Click 会首先取消选择所有 ListView 项,从而触发带有 Item=nilSelected= 的单个 OnSelectItem 事件False,在新项目被选中之前。在该事件发生时,TListView.SelCount 实际上为 0,因此您禁用了按钮,但随后没有进一步的 OnSelectItem 事件来告诉您新项目已被添加。已选中,因此您无需再次检查 SelCount 来重新启用该按钮。

OnSelectItem 事件被触发以回复 LVN_ITEMCHANGED当单个项目在选定和未选定之间更改状态时,或者当整个 ListView 中的所有项目更改为相同的选定/未选定状态时发出通知。但是,在虚拟模式下,当多个连续项目同时更改为相同状态时,Windows 可以改为发送单个 LVN_ODSTATECHANGED该范围的项目的通知。 TListLiew在接收到LVN_ODSTATECHANGED时不会触发OnSelectItem,而是触发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;

因此,您需要同时使用 OnSelectItemOnDataStateChange 来处理所有可能的选择/取消选择状态更改。

最好的解决方案是不要在单个项目状态更改时手动启用/禁用 TButton。在表单上放置一个 TActionManager,创建一个新的 TAction 并将其分配给 TButton.Action 属性,然后使用 TAction .OnUpdate 事件根据当前TListView.SelCount启用/禁用TAction,例如:

procedure TForm3.MyActionUpdate(Sender: TObject);
begin
MyAction.Enabled := ListView1.SelCount > 0;
end;

每当主消息队列空闲时,包括在处理 ListView 通知消息之后,都会自动启用/禁用关联的 TButton。这样,无论使用哪种输入组合来选择/取消选择 ListView 项目,您都可以保持 TButton 更新。

关于delphi - TListView SelCount 报告虚拟列表中的项目数错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22240431/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com