Create a Combobox winthin in a Stringgrid (Views: 28)
Problem/Question/Abstract: 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 unit BWControlStringGrid; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, stdctrls; type TBWControlStringGrid = class(TStringGrid) private fComboBox: TCombobox; procedure WMCommand(var msg: TWMCommand); message WM_COMMAND; procedure DblClick; override; procedure Click; override; procedure RelocateComboBox; procedure HideCombobox; protected procedure KeyPress(var Key: Char); override; public constructor Create(AOWner: TComponent); override; destructor Destroy; override; published end; procedure Register; implementation procedure Register; begin RegisterComponents('hEaDRoOm', [TBWControlStringGrid]); end; procedure TBWControlStringGrid.WMCommand(var msg: TWMCommand); begin if EditorMode and (msg.Ctl = fComboBox.Handle) then inherited else if msg.Ctl <> 0 then msg.result := SendMessage(msg.ctl, CN_COMMAND, TMessage(msg).wparam, TMessage(msg).lparam); end; procedure TBWControlStringGrid.KeyPress(var Key: Char); begin if Key = #13 then RelocateComboBox else HideCombobox; end; procedure TBWControlStringGrid.DblClick; begin inherited; RelocateComboBox; end; procedure TBWControlStringGrid.Click; begin inherited; HideCombobox; end; procedure TBWControlStringGrid.RelocateComboBox; begin fcombobox.boundsrect := CellRect(Selection.Left, Selection.Top); fcomboBox.Visible := TRUE; fcombobox.setfocus; end; procedure TBWControlStringGrid.HideCombobox; begin fcomboBox.Visible := false; end; constructor TBWControlStringGrid.Create(AOWner: TComponent); begin inherited Create(Aowner); fComboBox := TComboBox.Create(self); fComboBox.Parent := self; fComboBox.Visible := FALSE; Options := Options - [goRangeSelect]; end; destructor TBWControlStringGrid.Destroy; begin fComboBox.Destroy; inherited destroy; end; 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: TComboVisibleChangeEvent = procedure(Sender: TObject; Row, Col: Longint; Combo: TComboBox; AllowVisibleChange: boolean) of object fOnHide: TComboVisibleChangeEvent; 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! |