delphi - 将 TSwitch 添加到每个 TListView 项目

标签 delphi firemonkey delphi-xe8 tlistview

我没有尝试过这个,因为我不知道从哪里开始。

是否可以将 FMX TSwitch 添加到 FMX TListViewitem 中?

任何帮助/建议将不胜感激。

谢谢

最佳答案

您首先必须记住 TListView 控件的整个设计。当它包含大量元素时,它的重量非常轻。您可能有一百万个项目,您肯定不希望实例化一百万个开关控件。因此,您并不需要将控件作为容器嵌入到每个项目中,例如 TListBox 允许的那样。

话虽如此,假设您对每个单独的列表项执行最少的绘制,以与 TListView 的设计保持一致。这需要创建从 TListItemObject 继承的虚拟对象以与每个项目关联。这些对象允许任何项目的现有内置元素,例如配件或位图。

这是我为帮助您入门而整理的非常粗略演示,您需要根据需要更改绘图的外观。

启动一个新的 FMX 应用程序,放置一个 TListView,然后使用此单元代替主窗体的单元:

unit Unit1;

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;

type

  TListItemSwitch = class(TListItemSimpleControl)
  private
    FIsChecked: Boolean;
    FOnSwitch: TNotifyEvent;
    procedure SetIsChecked(const AValue: Boolean);
  protected
    function MouseDown(const Button: TMouseButton; const Shift: TShiftState; const MousePos: TPointF): Boolean;
      override;
    procedure DoSwitch; virtual;
  public
    constructor Create(const AOwner: TListItem); override;
    destructor Destroy; override;

    procedure Render(const Canvas: TCanvas; const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates;
      const SubPassNo: Integer = 0); override;

  public
    property IsChecked: Boolean read FIsChecked write SetIsChecked;
    property OnSwitch: TNotifyEvent read FOnSwitch write FOnSwitch;
  end;

  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}

{ TListItemSwitch }

constructor TListItemSwitch.Create(const AOwner: TListItem);
begin
  inherited;

end;

destructor TListItemSwitch.Destroy;
begin

  inherited;
end;

procedure TListItemSwitch.DoSwitch;
begin
  FIsChecked:= not FIsChecked;
  if Assigned(OnSwitch) then
    OnSwitch(Self);
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.Render(const Canvas: TCanvas;
  const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates;
  const SubPassNo: Integer);
var
  R, R2: TRectF;
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, 8, 8,
      [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
      1.0, TCornerType.Round);

    if IsChecked then begin
      R2.Left:= R.Right - 20;
      R2.Width:= 20;
    end else begin
      R2.Left:= R.Left;
      R2.Width:= 20;
    end;

    Canvas.Fill.Color:= TAlphaColorRec.Black;
    Canvas.FillRect(R2, 8, 8,
      [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
      1.0, TCornerType.Round);

  finally
    Canvas.EndScene;
  end;

end;

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

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  I: TListViewItem;
begin
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;
  I:= ListView1.Items.Add;

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;
    S.Width:= 50;
    S.Height:= 20;
    S.IsChecked:= False;
  end;

end;

end.

Screenshot

注意:这是用 Delphi 10 Seattle 编写的。

我认为您唯一的其他选择是:

  1. 为每个项目实例化一个 TSwitch 并使用与上面相同的方法渲染它(非常草率,我不推荐)
  2. 弄清楚如何使用样式实现标准 TSwitch 的绘制,再次使用与上面相同的方法(这可能是性能和视觉适应的最佳选择)
  3. 改用 TListBox,具体取决于您打算如何使用列表(这对于大量项目来说会非常繁重)

我在 a separate question / answer 中更深入地了解了 Firemonkey 中 TListViewTListBox 之间的差异。 .

关于delphi - 将 TSwitch 添加到每个 TListView 项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37076388/

相关文章:

forms - 从 XE8 中的 Form Tag 分配给 RadioGroup Tag 会导致访问冲突

delphi - 应用程序终止帮助

delphi - 为什么 SetString 内在函数可能会导致 PChar 参数出现 "Incompatible types"错误?

delphi - 如何使用FireMonkey截图(多平台)

delphi - 如何将 TImageList 中的图片分配给 TImage?

delphi - 如何在Delphi XE8中处理TListBox一直向下滚动到最后一个TListBoxItem?

multithreading - TMREWSync(TMultiReadExclusiveWriteSynchronizer)问题

delphi - 是否有一种无需尝试就可以有效地对程序进行防弹的方法?

delphi - 如何从 DLL 显示 FireMonkey 模态表单?

delphi - 枚举(带有自定义值)到字符串/文本