Add a TCombobox Column to a Firemonkey TGrid

风格不统一 提交于 2019-12-02 02:34:48

问题


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 work anymore. Specifically

firemonkey grid basics

doesn't work because the ApplyStyling event handler is only called once now (at column create)

I want to add a TCombobox or TComboboxEdit column to aTGrid.

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;

This creates the combobox column in the grid, but it's the same combobox in every row, and I have no idea how to add the GetValue and SetValue methods applicable here.


回答1:


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.




回答2:


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;


来源:https://stackoverflow.com/questions/32920219/add-a-tcombobox-column-to-a-firemonkey-tgrid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!