Author: William Gerbert
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:
1
2 procedure TfrmMain.FormCreate(Sender: TObject);
3 begin
4 StringGrid1.DefaultRowHeight := ComboBox1.Height;
5 end;
6
7 procedure TfrmMain.StringGrid1DrawCell(Sender: TObject; Col, Row:
8 Integer; Rect: TRect; State: TGridDrawState);
9 var
10 R: TRect;
11 begin
12 if (Col >= StringGrid1.FixedCols) and
13 (Row >= StringGrid1.FixedRows) and
14 (gdFocused in State) then
15 with ComboBox1 do
16 begin
17 BringToFront;
18 CopyRect(R, Rect);
19 R.TopLeft := frmMain.ScreenToClient(
20 StringGrid1.ClientToScreen(R.TopLeft));
21 R.BottomRight := frmMain.ScreenToClient(
22 StringGrid1.ClientToScreen(R.BottomRight));
23 SetBounds(R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top);
24 end;
25 end;
26
27 procedure TfrmMain.StringGrid1TopLeftChanged(Sender: TObject);
28 var
29 R: TRect;
30 begin
31 with StringGrid1 do
32 CopyRect(R, CellRect(Col, Row));
33
34 with ComboBox1 do
35 begin
36 Visible := False;
37 R.TopLeft := frmMain.ScreenToClient(
38 StringGrid1.ClientToScreen(R.TopLeft));
39 R.BottomRight := frmMain.ScreenToClient(
40 StringGrid1.ClientToScreen(R.BottomRight));
41 SetBounds(R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top);
42 end;
43
44 with StringGrid1 do
45 if (TopRow <= Row) and (TopRow + VisibleRowCount > Row) then
46 ComboBox1.Show;
47 end;
48
49 procedure TfrmMain.ComboBox1Change(Sender: TObject);
50 begin
51 with StringGrid1 do
52 Cells[Col, Row] := ComboBox1.Text;
53 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.
|