2011. február 3., csütörtök

A combobox in a cell of a stringgrid


Problem/Question/Abstract:

A combobox in a cell of a stringgrid

Answer:

Here's another great trick by programmer illusionists. What appears as embedded comboboxes within a stringgrid is actually just a combobox floating above the stringgrid, and it just so happens to be the exact same size as the stringgrid cell underneath it.

Here's the basics:


procedure TfrmMain.FormCreate(Sender: TObject);
� begin
��� StringGrid1.DefaultRowHeight := ComboBox1.Height;
� end;

� procedure TfrmMain.StringGrid1DrawCell(Sender: TObject; Col, Row:
��� Integer; Rect: TRect; State: TGridDrawState);
� var
��� R: TRect;
� begin
��� if (Col >= StringGrid1.FixedCols) and
����� (Row >= StringGrid1.FixedRows) and
����� (gdFocused in State) then
����� with ComboBox1 do
����� begin
������� BringToFront;
������� CopyRect(R, Rect);
������� R.TopLeft :=���� frmMain.ScreenToClient(
������������������������ StringGrid1.ClientToScreen(R.TopLeft));
������� R.BottomRight := frmMain.ScreenToClient(
������������������������ StringGrid1.ClientToScreen(R.BottomRight));
������� SetBounds(R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top);
  ��� end;
� end;

� procedure TfrmMain.StringGrid1TopLeftChanged(Sender: TObject);
� var
� R: TRect;
� begin
��� with StringGrid1 do
������� CopyRect(R, CellRect(Col, Row));

�� with ComboBox1 do
��� begin
����� Visible := False;
����� R.TopLeft :=���� frmMain.ScreenToClient(
���������������������� StringGrid1.ClientToScreen(R.TopLeft));
����� R.BottomRight := frmMain.ScreenToClient(
���������������������� StringGrid1.ClientToScreen(R.BottomRight));
����� SetBounds(R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top);
��� end;

�� with StringGrid1 do
����� if (TopRow <= Row) and (TopRow + VisibleRowCount > Row) then
�������� ComboBox1.Show;
� end;

� procedure TfrmMain.ComboBox1Change(Sender: TObject);
� begin
��� with StringGrid1 do
����� Cells[Col, Row] := ComboBox1.Text;
� end;


In essence, the main routine here is the stringgrid's OnDrawCell event handler. Of course, I also set the stringgrid's DefaultRowHeight property to be the same height as the combobox. In addition, the stringgrid's OnTopLeftChanged event handler is used to hide the combobox when the user scrolls out of view. Also, when the user selects an item from the combobox, simply place the text in the current Col/Row.

You can also do a couple other little tricks such as setting the stringgrid's Objects[] property to point to the combobox, as well as possibly setting the combobox's Parent property to point to the stringgrid. However, I've had problems with the Parent approach -- namely, that of dropping down the listbox associated with the combobox.

Nincsenek megjegyzések:

Megjegyzés küldése