【问题标题】:Add a TCombobox Column to a Firemonkey TGrid将 TCombobox 列添加到 Firemonkey TGrid
【发布时间】:2015-10-03 07:49:25
【问题描述】:

这个问题似乎已经回答过了,可能是 MonkeyStyler/Mike Sutton,但是,当我使用 Delphi 10 Seattle 时,提供的代码和指南不再起作用。具体

firemonkey grid basics

不起作用,因为 ApplyStyling 事件处理程序现在只调用一次(在列创建时)

我想向 aTGrid 添加一个 TCombobox 或 TComboboxEdit 列。

type
  TComboColumn = Class(TColumn)
  protected
    function CreateCellControl: TStyledControl; override; // works!
  End;

...

Grid1.AddObject(TComboColumn.Create(Grid1)); 

...

    function TComboColumn.CreateCellControl: TStyledControl;
    begin
      Result := TComboBox.Create(Self);
      TComboBox(Result).Items.Add('A');
      TComboBox(Result).Items.Add('B');
      TComboBox(Result).Items.Add('C');
      TComboBox(Result).OnChange := DoTextChanged; // strange hooks
    end;

这会在网格中创建组合框列,但它是每一行中的相同组合框,我不知道如何添加适用于此处的 GetValue 和 SetValue 方法。

【问题讨论】:

    标签: delphi firemonkey


    【解决方案1】:

    你需要做很多事情。开始吧。 首先,您需要声明一些数据类型来存储ComboBox 列的值。

      TComboRecord = record
        FieldValues: array of string;
        ItemSelected: integer;
        function Selected: string;
      end;
    
    
    ...
    { TComboRecord }
    
    function TComboRecord.Selected: string;
    begin
      Result := FieldValues[ItemSelected];
    end;
    

    并用一些数据填充TList<TComboRecord>

    var
      ComboData: TList<TComboRecord>;
    procedure PopulateComboData(Rows: cardinal);
    
    implementation
    
    procedure PopulateComboData(Rows: cardinal);
    var
      RowI: cardinal;
      i: cardinal;
      ComR: TComboRecord;
    begin
      for RowI := 1 to Rows do
      begin
        Setlength(ComR.FieldValues, random(5) + 1);
        for i := 0 to length(ComR.FieldValues) - 1 do
          ComR.FieldValues[i] := inttostr(random(64000));
        ComR.ItemSelected := 0;
        ComboData.Add(ComR);
      end;
    end;
    
    initialization
    
    ComboData := TList<TComboRecord>.Create;
    
    finalization
    
    ComboData.Free;
    

    您需要创建一个TComboBox 方位,以便它可以存储和操作TComboRecord 类型的数据。

      TComboBoxCell = class(TComboBox)
      private
        FComboData: TComboRecord;
        procedure SetComboData(const Value: TComboRecord);
        function GetComboData: TComboRecord;
      protected
        procedure SetData(const Value: TValue); override;
      public
        property ComboData: TComboRecord read GetComboData write SetComboData;
      end;
    ...
    
    { TComboBoxCell }
    
    
    function TComboBoxCell.GetComboData: TComboRecord;
    begin
      FComboData.ItemSelected:=ItemIndex;
      result:=FComboData;
    end;
    
    procedure TComboBoxCell.SetComboData(const Value: TComboRecord);
    var
      s: string;
    begin
      FComboData := Value;
      Items.Clear;
      for s in Value.FieldValues do
        Items.Add(s);
      ItemIndex := Value.ItemSelected;
    end;
    
    procedure TComboBoxCell.SetData(const Value: TValue);
    begin
      inherited;
      ComboData := Value.AsType<TComboRecord>
    end;
    

    比你需要继承一个新的类形式TColumn

      TComboColumn = class(TColumn)
      protected
        procedure DoComboChanged(Sender: TObject);
        function Grid: TComboExtendedGrid; overload;
        function CreateCellControl: TStyledControl; override; 
      end;
    ...
    
    { TComboColumn }
    
    function TComboColumn.CreateCellControl: TStyledControl;
    begin
      Result := TComboBoxCell.Create(Self);
      TComboBoxCell(Result).OnChange := DoComboChanged;
    end;
    
    procedure TComboColumn.DoComboChanged(Sender: TObject);
    var
      P: TPointF;
      LGrid: TComboExtendedGrid;
    begin
      LGrid := Grid;
      if not Assigned(LGrid) then
        Exit;
      if FUpdateColumn then
        Exit;
      if FDisableChange then
        Exit;
      P := StringToPoint(TFmxObject(Sender).TagString);
      LGrid.SetValue(Trunc(P.X), Trunc(P.Y),
        TValue.From<TComboRecord>(TComboBoxCell(Sender).ComboData));
      if Assigned(LGrid.FOnEditingDone) then
        LGrid.FOnEditingDone(Grid, Trunc(P.X), Trunc(P.Y));
    end;
    
    function TComboColumn.Grid: TComboExtendedGrid;
    var
      P: TFmxObject;
    begin
      Result := nil;
      P := Parent;
      while Assigned(P) do
      begin
        if P is TCustomGrid then
        begin
          Result := TComboExtendedGrid(P);
          Exit;
        end;
        P := P.Parent;
      end;
    end;
    

    你看,现在我们必须对TGrid 类进行子类型化,并且我们必须通过Grid 函数获取它的处理程序,并且需要访问protected FOnEditingDone 变量

      TComboExtendedGrid = class(TGrid)
      private
        FOnEditingDone: TOnEditingDone;
      protected
        procedure SetValue(Col, Row: integer; const Value: TValue); override;
      end;
    { TComboExtendedGrid }
    
    procedure TComboExtendedGrid.SetValue(Col, Row: integer; const Value: TValue);
    begin
      inherited;
    
    end;
    

    最后,我们需要在表单单元中设置必要的创建和事件处理机制。在 from 声明中添加一个列变量。

      protected
        CCColumn:TComboColumn;
    

    填充 ComboData 并创建列:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      PopulateComboData(Grid2.RowCount);
      CCColumn:=TComboColumn.Create(Grid2);
      CCColumn.Parent := Grid2;
      CCColumn.Header := 'CB';
    end;
    

    并处理事件:

    procedure TForm1.Grid2GetValue(Sender: TObject; const Col, Row: Integer;
      var Value: TValue);
    begin
      case Col of
         6{Combo Column Number}: Value:=TValue.From<TComboRecord>(ComboData[Row])
      end;
    end;
    
    procedure TForm1.Grid2SetValue(Sender: TObject; const Col, Row: Integer;
      const Value: TValue);
    begin
      case Col of
          6{Combo Column Number}: ShowMessage(Value.AsType<TComboRecord>.Selected);
      end;
    end;
    

    不要忘记将更改(如果需要)传递给ComboData 列表。当前的处理程序不会为您执行此操作。我更喜欢在 Grid2SetValue 事件处理程序中进行此操作。

    【讨论】:

    • 这看起来非常有前途和全面(远远超出我的写作能力,但对我来说是可读的)。当我有机会彻底测试它时,我会接受它作为答案。谢谢!
    • 让我们直截了当。我现在都整理好了。我为 D10 更改了两件事。 1. StringToPoint 现在在 FMX.Utils 2. s := Value.AsType&lt;TComboRecord&gt;.Selected;Grid1.SetValue 导致 D10 中的 AV。对于 D10,我已将其替换为 ComR := Value.AsType&lt;TComboRecord&gt;; if ComR.ItemSelected &gt; -1 then s := ComR.FieldValues[ComR.ItemSelected];。然后它就可以正常工作了。
    • 我还添加了 3.type TComboColumn = class(TColumn) private FUpdateColumn: Boolean; FDisableChange: Boolean; 与我首先使用的 XE7 版本相比。
    • @nolaspeaker 您也可以尝试编写ApplyStyleApplyStyling 程序来设置单元格控件的显示方式(字体颜色、字体大小等)。使用TComboRecord 作为容器传递必要的标志非常方便。
    • 我对@9​​87654349@和Applystyling没有经验,但更重要的是,我的下一个问题是关于网格显示的。组合框的当前选中值仅在实际选中单元格时显示,否则单元格仅显示(记录)。答案很长吗?
    【解决方案2】:

    这是将 Combobox 添加到 FMX TGrid 的简单方法。诚然,这个解决方案在每个组合中都有相同的项目,但我现在只能做到这一点。

    type
      TComboColumn = class(TPopupColumn)
        function CreateCellControl: TStyledControl; override;
      end;
    

    ...

    function TComboColumn.CreateCellControl: TStyledControl;
    var
      ComR: TComboRecord;
      i: Integer;
    begin
       Result := TComboBoxCell.Create(self);
       // now they all have the same drop-down values
       ComR := frmMain.ComboData[0];
       for i := 0 to Length(ComR.FieldValues) do
         TComboBoxCell(Result).Items.Add(ComR.FieldValues[i]);
    end
    

    ...而且只是为了连续性

    procedure TfrmMain.FormCreate(Sender: TObject);
    begin
       AGrid := TComboExtendedGrid.Create(Self);
       AGrid.Parent := Self;
       AGrid.Align := TAlignLayout.Client;
       AGrid.Options := AGrid.Options + [TGridOption.AlwaysShowEditor];
       AGrid.OnGetValue := AGridGetValue;
       AGrid.OnSetValue := AGridSetValue;
       AGrid.RowCount := 5;
    
       ComboData := TList<TComboRecord>.Create;
       PopulateComboData(AGrid.RowCount);
    
       CCColumn := TComboColumn.Create(AGrid);
       CCColumn.Parent := AGrid;
       CCColumn.Header := 'Combohere';   
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      • 2013-03-10
      • 1970-01-01
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多