Add a TCombobox Column to a Firemonkey TGrid

后端 未结 2 1658
不知归路
不知归路 2021-01-23 06:59

This question appears to have been answered already, possibly by MonkeyStyler/Mike Sutton, however, as I am using Delphi 10 Seattle, provided code and guides don\'t wor

相关标签:
2条回答
  • 2021-01-23 07:12

    You need to do quite much. Let's start. At first you need declare some data type that will store the values for your ComboBox column.

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

    and populate a TList<TComboRecord> with some data.

    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;
    

    Than you need create a TComboBox ascendant so that it could store and manipulate the TComboRecord type data.

      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;
    

    Than you need to inherit a new class form 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;
    

    You see that now we have to subtype TGrid class as well as we have to get its handler by Grid function and need access to protected FOnEditingDone variable

      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;
    

    Finally we need set the necessary creation and event handliing mechanism in our form unit. Add a column variable to the from declaration.

      protected
        CCColumn:TComboColumn;
    

    populate the ComboData and create the column:

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

    and handle the events:

    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;
    

    Do not forget to pass changes (if you need) to ComboData list. The current handlers will not do this for you. I prefer making this in Grid2SetValue event handler.

    0 讨论(0)
  • 2021-01-23 07:24

    Here is the easy way to add a Combobox to a FMX TGrid. Granted, this solution has the same items in every combo, but that's all I can achieve right now.

    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
    

    ... And just for continuity

    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;
    
    0 讨论(0)
提交回复
热议问题