加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-15 09:52:18 所属栏目:大数据 来源:网络整理
导读:我需要启用或禁用按钮,具体取决于列表中是否至少选择了一行. 以下是重现此问题的代码.使用OnData事件填充列表,它允许选择多行. 我以为我可以使用OnSelectItem来检测用户何时更改选择,然后使用TListView SelCount函数来检测所选行的数量. 问题是当用户选择多
我需要启用或禁用按钮,具体取决于列表中是否至少选择了一行.

以下是重现此问题的代码.使用OnData事件填充列表,它允许选择多行.

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

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

有任何想法吗?

谢谢

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

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

?

要重现此问题,请运行应用程序,选择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单击多个项目时,您将不会获得已选择的项目的任何OnSelectItem事件. SHIFT Click会首先取消选择所有列表视图项,在新项目被选中之前触发Item = nil和Selected = False的单个OnSelectItem事件.在该事件发生时,TListView.SelCount确实为0,因此您禁用了按钮,但是没有进一步的OnSelectItem事件告诉您已经选择了新项目,因此您不再检查SelCount以重新启用按钮.

当单个项目在选定和未选定之间更改状态时,或者当整个ListView中的所有项目更改为相同的选定/未选定状态时,将触发OnSelectItem事件以回复LVN_ITEMCHANGED通知.但是,在虚拟模式下,当多个连续项目同时更改为相同的状态时,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;

因此,您需要使用OnSelectItem和OnDataStateChange来处理所有可能的选择/取消选择状态更改.

最佳解决方案是不对单个项目状态更改手动启用/禁用TButton.删除Form上的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的更新.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读