Author: Boris Benjamin Wittfoth
How to dynamically create a Combobox within a Cell of a StringGrid
Answer:
You need a descendent of TStringgrid that properly reflects WM_COMMAND to embedded
controls. The standard grid does not do it since it is not intended to play parent
to other controls.
Additionaly simply declare a Set- and GetMethod to access the items of die combobox
1 unit BWControlStringGrid;
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7 Grids, stdctrls;
8
9 type
10 TBWControlStringGrid = class(TStringGrid)
11 private
12 fComboBox: TCombobox;
13 procedure WMCommand(var msg: TWMCommand); message WM_COMMAND;
14 procedure DblClick; override;
15 procedure Click; override;
16 procedure RelocateComboBox;
17 procedure HideCombobox;
18 protected
19 procedure KeyPress(var Key: Char); override;
20 public
21 constructor Create(AOWner: TComponent); override;
22 destructor Destroy; override;
23 published
24 end;
25
26 procedure register;
27
28 implementation
29
30 procedure register;
31 begin
32 RegisterComponents('hEaDRoOm', [TBWControlStringGrid]);
33 end;
34
35 procedure TBWControlStringGrid.WMCommand(var msg: TWMCommand);
36 begin
37 if EditorMode and (msg.Ctl = fComboBox.Handle) then
38 inherited
39 else if msg.Ctl <> 0 then
40 msg.result :=
41 SendMessage(msg.ctl, CN_COMMAND,
42 TMessage(msg).wparam,
43 TMessage(msg).lparam);
44 end;
45
46 procedure TBWControlStringGrid.KeyPress(var Key: Char);
47 begin
48 if Key = #13 then
49 RelocateComboBox
50 else
51 HideCombobox;
52
53 end;
54
55 procedure TBWControlStringGrid.DblClick;
56 begin
57 inherited;
58 RelocateComboBox;
59 end;
60
61 procedure TBWControlStringGrid.Click;
62 begin
63 inherited;
64 HideCombobox;
65 end;
66
67 procedure TBWControlStringGrid.RelocateComboBox;
68 begin
69 fcombobox.boundsrect := CellRect(Selection.Left, Selection.Top);
70 fcomboBox.Visible := TRUE;
71 fcombobox.setfocus;
72 end;
73
74 procedure TBWControlStringGrid.HideCombobox;
75 begin
76 fcomboBox.Visible := false;
77 end;
78
79 constructor TBWControlStringGrid.Create(AOWner: TComponent);
80 begin
81 inherited Create(Aowner);
82 fComboBox := TComboBox.Create(self);
83 fComboBox.Parent := self;
84 fComboBox.Visible := FALSE;
85 Options := Options - [goRangeSelect];
86 end;
87
88 destructor TBWControlStringGrid.Destroy;
89 begin
90 fComboBox.Destroy;
91 inherited destroy;
92 end;
93
94 end.
This is great, but is just the skeleton, of course..
There needs to be some mechansim for getting the combo's text/selection into the
cell, also for relaying the cells contents into the combo in the first place.
This can be done in the Hide and Relocate methods.
The whole thing can get unwieldy if you add a lot of get/set methods for updating
the combos dropdownlist, etc, so making the Combo a Public property, rather than
just a private field might help with that - the onus is then on the programmer to
deal with the combo directly - it is unlikely, for instance, that the dropdownlist
would be the same for each column.
Or two new events could be triggered - OnHide and OnRelocate
eg:
95
96 TComboVisibleChangeEvent = procedure(Sender: TObject; Row, Col: Longint; Combo:
97 TComboBox; AllowVisibleChange: boolean) of object
98
99 fOnHide: TComboVisibleChangeEvent;
100 fOnRelocate: TComboVisibleChangeEvent;
etc.
This way the Combo would be make public when needed. When the Relocate fires, the
dropdownlist could be repopulated, etc
Just ideas for whoever wants them!
|