2016-05-07 9 views
2

Ich schreibe ein benutzerdefiniertes Schalterobjekt, das in Firemonkes TListView Steuerelement pro Element verwendet werden soll. Alles funktioniert wie erwartet, abgesehen von einem seltsamen Fehler. Wenn der Benutzer auf eines der Elemente, aber nicht auf das bestimmte Schalterobjekt klickt, schaltet es den Schalter trotzdem um. Ich gehe davon aus, dass das Ereignis MouseDown ausgelöst wird, wenn der Benutzer auf das Listenelement klickt und nicht unbedingt mein bestimmtes "Steuerelement" darauf gezeichnet wird.Klicken Sie auf Ereignisse, die von der Listenansicht abgefangen werden. Element

Wie schränke ich das Klickereignis so ein, dass es nur dann gilt, wenn der Benutzer auf den aktuellen Schalter klickt?

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. 

Es ist etwas sollte wie folgt aussehen:

enter image description here

+0

Die Signatur von TListItemDrawable.Render hat sich in 10.1 Berlin geändert, scheint aber die Funktionalität nicht zu beeinträchtigen. Mit der Änderung von Dalija Prasnikar (unten) funktioniert es gut. – nolaspeaker

Antwort

5

In Ihrer MouseDown-Methode ist ein Fehler aufgetreten. Es sollte wie folgt aussehen:

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

Wenn der Benutzer klickt auf ListItem es wird für alle seine sichtbaren subcontrols ihre MouseDown Methoden aufrufen, um zu sehen, welche gedrückt wird. Wenn die Methode MouseDowntrue zurückgibt, bedeutet dies, dass eine bestimmte Untersteuerung gedrückt wird. In Ihrem Fall ist diese Logik in TListItemSimpleControl implementiert, von der Sie erben.

Sie haben Logik für alle MouseDown Ereignisse ausgeführt, selbst wenn die Maus nicht innerhalb Ihrer Steuergrenzen gedrückt wurde.