【问题标题】:Disabling deselect in TListView control在 TListView 控件中禁用取消选择
【发布时间】:2011-12-26 14:06:16
【问题描述】:

我想将 TListView (vsIcon) 用作一种选项卡 - 这样只能像选项卡一样选择一个项目。只选择一项没有问题(禁用多选属性)。问题是单击列表视图中图标和文本之间的空白点时取消选择项目。

这是我目前尝试过的:

void __fastcall TForm::ListViewChanging(TObject *Sender, TListItem *Item, TItemChange Change, bool &AllowChange)
{
if (Change == ctState)
    {
    TPoint CursorRel = ListView->ScreenToClient(Mouse->CursorPos);
    AllowChange = (ListView->GetItemAt(CursorRel.x, CursorRel.y) != NULL);
    StatusBar->SimpleText = (AllowChange)? "YES" : "NO";
    }
}

上述方法有效,但存在问题。当鼠标单击空白区域时,它会取消选择该项目,并且键盘向上/向下箭头不再起作用,尽管该项目看起来仍处于选中状态。如果我忽略键盘,对于鼠标选择它可以正常工作,它会忽略在状态栏中显示“NO”消息的空白区域的点击。

任何想法如何解决此问题,使其适用于所有可能的选择方法(键盘、鼠标(任何其他?))。

【问题讨论】:

    标签: delphi c++builder tlistview


    【解决方案1】:

    拦截WM_LBUTTONDOWN 发布到控件并停止默认处理,如果单击不是在项目上。子类化控件,或使用 ApplicationEvents 组件等。带有插入器类的 Delphi 代码示例:

    type
      TListView = class(comctrls.TListView)
      protected
        procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
      end;
    
      TForm1 = class(TForm)
        ListView1: TListView;
      private
        ..
    
    procedure TListView.WMLButtonDown(var Message: TWMLButtonDown);
    begin
      if GetItemAt(Message.XPos, Message.YPos) <> nil then
        inherited;
    end;
    

    【讨论】:

    • 完美运行!谢谢 !但是您必须对鼠标右键和双击执行相同的操作,因为它们也可以取消选择该项目。
    【解决方案2】:

    这是您问题的另一个可能答案:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ImgList, ComCtrls;
    
    type
      TForm1 = class(TForm)
        ListView1: TListView;
        ImageList1: TImageList;
        StatusBar1: TStatusBar;
        procedure ListView1Changing(Sender: TObject; Item: TListItem;
          Change: TItemChange; var AllowChange: Boolean);
        procedure ListView1MouseUp(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
        procedure ListView1Enter(Sender: TObject);
      private
        FListItem: TListItem;
        procedure SelectedListItemStateSave;
        procedure SelectedListItemStateRestore;
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.SelectedListItemStateRestore;
    begin
      ListView1.Selected := FListItem;
      ListView1.Selected.Focused := True; // Always focused
    end;
    
    procedure TForm1.SelectedListItemStateSave;
    begin
      FListItem := ListView1.Selected;
    end;
    
    procedure TForm1.ListView1Changing(Sender: TObject; Item: TListItem;
      Change: TItemChange; var AllowChange: Boolean);
    begin
      if (Change=ctState) then
        SelectedListItemStateSave;
    end;
    
    procedure TForm1.ListView1Enter(Sender: TObject);
    begin
      if ListView1.Selected = nil then
      begin
        FListItem :=ListView1.Items[0]; // Initialization
        SelectedListItemStateRestore;
      end;
    end;
    
    procedure TForm1.ListView1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      if ListView1.GetItemAt(X,Y) = nil then
      begin
        SelectedListItemStateRestore;
      end;
    end;
    
    end.
    

    【讨论】:

    • 我觉得这个可以用。感谢您的回答。
    • @Coder - 这对您的情况可能并不重要,但通常如果您不想阻止某些事情,最好阻止它(如果您能提供帮助)而不是撤消已经发生的事情完毕。例如,用户可以在空白区域按下按钮,但释放项目上的按钮..
    • @Sertac Akyuz:从严格的 OOP 角度来看,我更喜欢基于TCustomListView 甚至TCustomMultiSelectListControl 推出一个新组件,并从头开始实现所需的特定行为。我的解决方案基于@Coder12345 的偏好。
    猜你喜欢
    • 1970-01-01
    • 2013-09-13
    • 2016-10-04
    • 1970-01-01
    • 2013-12-02
    • 2016-01-11
    • 2021-10-29
    • 2015-01-03
    • 2018-07-18
    相关资源
    最近更新 更多