Introduction
Sometimes you want to edit the content of a TStringGrid. When you do, if the
default editor is not sufficient, you must create your own editing system for
the string grid. This document helps with the most difficult case - where your
editor needs to be a combo box.
Note that this technique can also work for a TDrawGrid, from which TStringGrid
is derived.
Getting Started
You need to first derive a class from TStringGrid which will be your class.
In this case, I will call the example derived class AStringGridWithCombo;
In this example, the grid has two columns. The first column is fixed and cannot
be edited. The second column can have a string value based on the contents of
a TStringList property of the grid called myListOfStrings.
The editor is a TComboBox which is loaded with those values each time it is
made visible by a click on the grid.
Implementation Concepts
The implementation relies on overriding the Click function. Click is the function
of TStringGrid (and many other controls) which calls the OnClick event handler.
In this case, we do not ever call an OnClick handler, however, we simply capture
the event for our own use - and in this case, that use is to create and display
our editor.
The editor cannot be made a child of the grid - it must be a child of the form.
This is because when it is a child of the grid, the combo is clipped to the
boundary of the currently selected cell, and the drop down is therefore invisible.
Such a restriction may not be a problem for editors which are derived from TEdit,
and which would not mind such clipping. At any rate, when the editor is not
a child of the grid, some calculation must be performed to reposition the editor
over the proper cell and make it the proper size to appear to be in the cell.
The editor in this example, being a combo, uses the OnChange event to accept
the result, insert it in the cell, and make the editor invisible again. Note
that the editor is only created the first time it is needed, and then it is
kept (invisible), until the control is destroyed.
A TEdit control would need to detect a return key or some other signal to deal
with this.
Also note that the combo is shown dropped down. Thus, a change of focus to
another control is considered a change, and the editor properly disappears.
If this were not the case, you might have to have an OnExit handler for your
editor which would perform the function of making the editor invisible again.
The Key Functions
The following are the key functions used in this implementation...
void __fastcall AStringGridWithCombo::Click(void)
{
if (myEditor == NULL)
{
myEditor = new TComboBox(Owner);
myEditor->Name = Name + AnsiString("Editor");
myEditor->Parent = Parent;
myEditor->Visible = FALSE;
myEditor->Style = csDropDown;
myEditor->DropDownCount =
30;
};
myEditor->OnChange = NULL;
myEditor->Items->Clear();
myEditor->Items->Add(" ");
myEditor->Items->AddStrings(myListOfValidStrings);
myEditor->OnChange = FieldPicked;
MoveEditor();
if (Cells[1][Row] != " ") myEditor->Items->Add(Cells[1][Row]);
// Show current value
myEditor->ItemIndex = myEditor->Items->IndexOf(Cells[1][Row]);
myEditor->DroppedDown = TRUE;
}
//---------------------------------------------------------------------------
void __fastcall AStringGridWithCombo::TopLeftChanged(void)
{
Invalidate();
MoveEditor();
}
//---------------------------------------------------------------------------
void __fastcall AStringGridWithCombo::MoveEditor(void)
{
if (myEditor == NULL) return;
TRect Rect = CellRect(Col,Row);
myEditor->Top = Top;
myEditor->Left = Left;
myEditor->Visible = FALSE;
myEditor->Top = myEditor->Top + Rect.Top
+ GridLineWidth;
myEditor->Left = myEditor->Left + Rect.Left
+ GridLineWidth;
myEditor->Height = (Rect.Bottom - Rect.Top)
+ 1;
myEditor->Width = (Rect.Right - Rect.Left) +
1;
myEditor->Visible = TRUE;
} |
Here is the event handler for the OnChange event of the editor combo:
void __fastcall AStringGridWithCombo::FieldPicked(TObject *Sender)
{
Cells[1][Row] = myEditor->Items->Strings[myEditor->ItemIndex];
myEditor->Visible = FALSE;
} |
That function assigns the value picked in the combo to the grid cell and makes
the editor invisible. Again, a slightly different strategy might be needed for
an editor descended from TEdit.
Conclusion
Hopefully this helps make it clear how to create an editor for a TStringGrid.
It isn't easy, but once done, never needs to be done again.
|