I'm try to build a tool that reads data from a database and displays it as a table using a TGrid in Firemonkey. I need to use different types of columns like TCheckColumn and TPopupColumn but can't find any good guide or example on how to use them in C++ Builder.
Any way, I managed to understand the usage of the TStringColumn,TProgressColumn setting the Value of the cell in the TGrid's event onGetValue.
Does any one of you know how to set the Value for columns of type TCheckColumn, TImageColumn and TPopupColumn?
thanks
Daniele
---UPDATE---
I managed to use the TProgressColumn. This is what I do in the Form's constructor:
// TStringColumn
Grid1->AddObject(new TStringColumn(this));
// TCheckColumn
TCheckColumn* c = new TCheckColumn(this);
Grid1->AddObject(c);
// TPopupColumn
// list of values
TStringList * l = new TStringList(NULL);
l->Add(L"First");
l->Add(L"Second");
l->Add(L"Third");
TPopupColumn* p = new TPopupColumn(this);
// adding the list to the PopupColumn
p->Items = l;
Grid1->AddObject(p);
// TProgressColumn
Grid1->AddObject(new TProgressColumn (this));
Grid1->RowCount = 3 ;
and this is the Grid1GetValue method:
// TStringColumn
if(Col == 0) Value = TValue::From<String>(Row);
// TCheckColumn !! Can't make it work
if(Col == 1) Value = TValue::From<Boolean>(true);
// TPopupColumn
if(Col == 2) Value = TValue::From<int>(2);
// TProgressColumn
if(Col == 3) Value = TValue::From<double>(50.0);
---UPDATE---
if I save the value of the column using the method OnSetValue
void __fastcall TForm1::Grid1SetValue(...)
{
if(Col == 1) check = Value;
}
and then set it with the method OnGetValue:
void __fastcall TForm1::Grid1GetValue(...)
{
// TCheckColumn !! Can't make it work
if(Col == 1) Value = check;// TValue::From<Boolean>(true);
}
After I click on one checkbox all the other checkboxes change state. So the component works correctly... now the point is how to set the Value to true or false in the right way.
TGris does not store any data, you should create your own datastorage.
Example: TGrid with TCheckColumn, TStringColumn and TPopupColumn
type
TField = record
Checked: Boolean;
Name: string;
Column: Byte;
end;
var
Fields: TList<TField>;
function SetField(const AChecked: Boolean; const AName: string; const AColumn: Byte): TField;
begin
with Result do begin
Checked := AChecked;
Name := AName;
Column := AColumn;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
Fields := TList<TField>.Create;
Fields.Add(SetField(True, 'Name', 1));
Fields.Add(SetField(True, 'Login', 2));
Fields.Add(SetField(True, 'Password', 3));
for I := 1 to Fields.Count do
PopupColumn1.Items.Add('Column ' + IntToStr(I));
gdFields.RowCount := Fields.Count;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Fields.Free;
end;
procedure TFormExport.gdFieldsGetValue(Sender: TObject; const Col, Row: Integer; var Value: TValue);
begin
case gdFields.Columns[Col].TabOrder of
0: Value := Fields[Row].Checked;
1: Value := Fields[Row].Name;
2: Value := Fields[Row].Column - 1;
end;
end;
procedure TFormExport.gdFieldsSetValue(Sender: TObject; const Col, Row: Integer; const Value: TValue);
var
FRec: TField;
begin
FRec := Fields[Row];
case gdFields.Columns[Col].TabOrder of
0: FRec.Checked := Value.AsBoolean;
1: FRec.Name := Value.AsString;
2: FRec.Column := Value.AsInteger + 1;
end;
Fields[Row] := FRec;
end;
Now all data from your datastorage will be changed after editing your TGrid, but possible bug in TGrid - never received OnSetValue after changing PopupColumn
I can't give C++ code but a Delphi example should be easy enough to translate.
You get and set all cell values the same way, by listening for the OnGetData and OnSetData events, get take/give values of type TValue (XE3 and later). It's just a case of returning the appropriate type in the TValue:
uses System.RTTI;
procedure Form1.Grid1GetValue(Sender: TObject;const Col, Row: Integer;var Value: TValue);
begin
if Col = 1 then
Value := TValue.From<Integer>(1)
else if Col = 2 then
Value := TValue.From<String>('Hello')
else if Col = 3 then
Value := Tvalue.From<Single>(1.0);
end;
procedure Form1.Grid1SetValue(Sender: TObject;const Col, Row: Integer;const Value: TValue);
begin
if Col = 1 then
I := Value.As<Integer>
else if Col = 2 then
St := Value.As<String>
else if Col = 3 then
Si := Value.As<Single>;
end;
As far as I can tell a popup menu can't accept or give data.
In order to solve your problem, redefine the TCheckCell
class in the following way:
#include <FMX.Grid.hpp>
#include <boost/dynamic_bitset.hpp>
class CheckCellClass:public TCheckCell
{
public:
__fastcall virtual CheckCellClass(System::Classes::TComponent*AOwner):TCheckCell(AOwner)
{
};
virtual System::Rtti::TValue __fastcall GetData(void)
{
return TValue::From<bool>(this->IsChecked);
};
virtual void __fastcall SetData(const TValue&Value)
{
TValue V(Value);
this->IsChecked=V.AsBoolean();
};
};
//Redifine TCheckColumn class
class CheckColumnClass:public TCheckColumn
{
private:
virtual Fmx::Controls::TStyledControl*__fastcall CreateCellControl(void)
{
CheckCellClass*Cell=new CheckCellClass(this);
Cell->OnChange =&(this->DoCheckChanged);
return Cell;
};
public:
__fastcall CheckColumnClass(System::Classes::TComponent*AOwner):TCheckColumn(AOwner)
{
};
};
//global Data for Save curent State Cell
boost::dynamic_bitset<unsigned char>FullDiscreteInputs;
Add To Grid In Constuctor
FullDiscreteInputs.resize(100);
DiscreteInputsGrid->RowCount=FullDiscreteInputs.size();
CheckColumnClass* DiscreteInPutsCheckColumn =new CheckColumnClass(DiscreteInputsGrid);
DiscreteInputsGrid->AddObject(CoilsCheckColumn);
void __fastcall TForm1::DiscreteInputsGridGetValue(TObject*Sender, const int Col, const int Row,TValue&Value)
{
//...
if(DiscreteInputsGrid->ColumnByIndex(Col)==DiscreteInPutsCheckColumn)
{
Value=TValue::From<bool>(FullDiscreteInputs[Row]);
}
//...
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DiscreteInputsGridSetValue(TObject*Sender, const int Col, const int Row, const TValue&Value)
{
TValue V(Value);
if(DiscreteInputsGrid->ColumnByIndex(Col)==DiscreteInPutsCheckColumn)
{
FullDiscreteInputs[Row]=V.AsBoolean();
}
}
//---------------------------------------------------------------------------