单击列表视图父项捕获的事件

时间:2016-05-07 02:14:06

标签: delphi firemonkey delphi-10-seattle

我正在编写一个自定义开关对象,用于每个项目的Firemonkey TListView控件。一切都按预期工作,除了一个奇怪的故障。当用户点击其中一个项目而不是特定交换机对象时,它无论如何都会切换开关。我假设当用户点击列表项时触发MouseDown事件,而不一定是我的特定“控件”。

如何将click事件限制为仅在用户单击实际开关时应用?

JD.ListViewObjects.pas

unit JD.ListViewObjects;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base,
  FMX.ListView;

type
  TLISwitchThumbStyle = (tsRect, tsRoundRect, tsElipse);

  TListItemSwitch = class(TListItemSimpleControl)
  private
    FIsChecked: Boolean;
    FOnSwitch: TNotifyEvent;
    FThumbStyle: TLISwitchThumbStyle;
    FThumbWidth: Single;
    FThumbHeight: Single;
    FThumbRound: Single;
    procedure SetIsChecked(const AValue: Boolean);
    procedure SetThumbStyle(const Value: TLISwitchThumbStyle);
    procedure SetThumbWidth(const Value: Single);
    procedure SetThumbHeight(const Value: Single);
    procedure SetThumbRound(const Value: Single);
  protected
    function MouseDown(const Button: TMouseButton; const Shift: TShiftState; const MousePos: TPointF): Boolean;
      override;
    procedure DoSwitch; virtual;
    procedure Render(const Canvas: TCanvas; const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates;
      const SubPassNo: Integer = 0); override;
  public
    constructor Create(const AOwner: TListItem); override;
    destructor Destroy; override;
  public
    property IsChecked: Boolean read FIsChecked write SetIsChecked;
    property ThumbWidth: Single read FThumbWidth write SetThumbWidth;
    property ThumbHeight: Single read FThumbHeight write SetThumbHeight;
    property ThumbStyle: TLISwitchThumbStyle read FThumbStyle write SetThumbStyle;
    property ThumbRound: Single read FThumbRound write SetThumbRound;
    property OnSwitch: TNotifyEvent read FOnSwitch write FOnSwitch;
  end;

implementation

{ TListItemSwitch }

constructor TListItemSwitch.Create(const AOwner: TListItem);
begin
  inherited;
  Width:= 50;
  Height:= 20;
  FIsChecked:= False;
  FThumbWidth:= 15;
  FThumbHeight:= 15;
  FThumbRound:= 3;
end;

destructor TListItemSwitch.Destroy;
begin

  inherited;
end;

function TListItemSwitch.MouseDown(const Button: TMouseButton;
  const Shift: TShiftState; const MousePos: TPointF): Boolean;
begin
  if (Button = TMouseButton.mbLeft) and Enabled then begin
    DoSwitch;
  end;
  inherited;
end;

procedure TListItemSwitch.DoSwitch;
begin
  FIsChecked:= not FIsChecked;
  if Assigned(OnSwitch) then
    OnSwitch(Self);
  Invalidate;
end;

procedure TListItemSwitch.SetIsChecked(const AValue: Boolean);
begin
  FIsChecked:= AValue;
  Invalidate;
end;

procedure TListItemSwitch.SetThumbWidth(const Value: Single);
begin
  FThumbWidth := Value;
  Invalidate;
end;

procedure TListItemSwitch.SetThumbHeight(const Value: Single);
begin
  FThumbHeight := Value;
  Invalidate;
end;

procedure TListItemSwitch.SetThumbRound(const Value: Single);
begin
  FThumbRound := Value;
  Invalidate;
end;

procedure TListItemSwitch.SetThumbStyle(const Value: TLISwitchThumbStyle);
begin
  FThumbStyle := Value;
  Invalidate;
end;

procedure TListItemSwitch.Render(const Canvas: TCanvas;
  const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates;
  const SubPassNo: Integer);
var
  R, R2: TRectF;
  D: Single;
begin
  inherited;
  R:= Self.LocalRect;
  R2:= R;
  Canvas.BeginScene;
  try
    Canvas.Stroke.Kind:= TBrushKind.None;
    Canvas.Fill.Kind:= TBrushKind.Solid;
    Canvas.Fill.Color:= TAlphaColorRec.Skyblue;
    Canvas.FillRect(R, FThumbRound, FThumbRound,
      [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
      1.0, TCornerType.Round);
    R2.Top:= R.Top + (R.Height / 2) - (FThumbHeight / 2);
    R2.Height:= FThumbHeight;
    D:= R2.Top - R.Top;
    if IsChecked then begin
      R2.Left:= R.Right - FThumbWidth - D;
    end else begin
      R2.Left:= R.Left + D;
    end;
    R2.Width:= FThumbWidth;
    Canvas.Fill.Color:= TAlphaColorRec.Black;
    Canvas.FillRect(R2, FThumbRound, FThumbRound,
      [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
      1.0, TCornerType.Round);
  finally
    Canvas.EndScene;
  end;
end;
end.

uListViewSwitchTest.pas

unit uListViewSwitchTest;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base,
  FMX.ListView, FMX.Controls.Presentation, FMX.StdCtrls,
  JD.ListViewObjects;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    procedure ListView1UpdateObjects(const Sender: TObject;
      const AItem: TListViewItem);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  X: Integer;
  function A: TListViewItem;
  begin
    Result:= ListView1.Items.Add;
  end;
begin
  ListView1.Align:= TAlignLayout.Client;
  for X := 1 to 50 do
    A;
end;

procedure TForm1.ListView1UpdateObjects(const Sender: TObject;
  const AItem: TListViewItem);
var
  S: TListItemSwitch;
begin
  S:= AItem.Objects.FindObject('Switch') as TListItemSwitch;
  if S = nil then begin
    S:= TListItemSwitch.Create(AItem);
    S.Name:= 'Switch';
    S.Align:= TListItemAlign.Trailing;
    S.VertAlign:= TListItemAlign.Center;
  end;
end;

end.

看起来应该是这样的:

enter image description here

1 个答案:

答案 0 :(得分:5)

to expected argument type UnsafeMutablePointer<CGPoint>方法存在错误。它应该是这样的:

MouseDown

当用户点击function TListItemSwitch.MouseDown(const Button: TMouseButton; const Shift: TShiftState; const MousePos: TPointF): Boolean; begin Result := inherited; if Result then begin DoSwitch; end; end; 时,它会遍历所有可见的子控件,调用他们的ListItem方法来查看哪一个被按下。如果MouseDown方法返回MouseDown,则表示按下了特定的子控件。在您的情况下,逻辑是在您继承的true中实现的。

即使没有在控件范围内按下鼠标,您也会对所有TListItemSimpleControl事件执行DoSwitch逻辑。