unit jvclEDBGRID; interface uses jvDBGrid, SysUtils, Classes, Grids, Controls, DB, DBGrids, Graphics, Forms, WinTypes, Messages; type TjvclEDBGrid = class(TJvDBGrid) private iCurrentObj: integer; ColumnHasObj: boolean; ShowObject: boolean; fResizeObjects : Boolean; GridObjs: TList; FOnMouseDown: TMouseEvent; function GetObjIndex (const GridIndex: integer): integer; procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE; protected procedure Loaded; override; procedure SetColumnAttributes; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override; procedure KeyPress(var Key: Char); override; {$ifdef WIN32} procedure DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); override; {$else} procedure DrawDataCell(const Rect: TRect; Field: TField; State: TGridDrawState); override; {$endif} public ObjEnabled: boolean; Property Row; Property Col; constructor Create(AOwner:TComponent); override; destructor Destroy; override; published property ResizeChildObjects : Boolean read fResizeObjects Write fResizeObjects; property EnableChildObjects : Boolean read ObjEnabled Write objEnabled; property OnMouseDown read FOnMouseDown write FOnMouseDown; Property OnMouseMove; Property OnMouseUp; end; procedure Register; implementation {______________________________________________________________________________} procedure Register; begin RegisterComponents('VNM', [TjvclEDBGrid]); end; {______________________________________________________________________________} constructor TjvclEDBGrid.Create (AOwner:TComponent); begin inherited Create(AOwner); ControlStyle := ControlStyle + [csAcceptsControls]; ObjEnabled := true; iCurrentObj := -1; {current visible embedded object} ShowObject := false; {show only when KeyPress or MouseDown} ColumnHasObj := false; GridObjs := TList.Create; {My Defaults (you may change or delete this to suit your needs)} Options := Options - [dgConfirmDelete,dgColumnResize]; TitleFont.Style := []; Height := 142; end; {______________________________________________________________________________} destructor TjvclEDBGrid.Destroy; begin inherited Destroy; GridObjs.Free; GridObjs := nil; {$IFNDEF WIN32} try TitleFont.Free; {fix Delphi 1 memory leak} TitleFont:=Nil; except end; {$ENDIF} end; {______________________________________________________________________________} procedure TjvclEDBGrid.Loaded; begin Inherited Loaded; if csDesigning in ComponentState then Exit; {move all objects from Controls property to GridObjs} {Notice: this is necessary because some controls (TComboBox, for example) don't "behave" themselves when having the grid as parent (Who knows why?)} while ControlCount > 0 do begin {hide all embedded objects} Controls[ControlCount-1].Visible := false; {move objects to GridObjs} GridObjs.Add(Controls[ControlCount-1]); TControl(GridObjs[GridObjs.Count-1]).Parent := Parent; end; end; {______________________________________________________________________________} procedure TjvclEDBGrid.SetColumnAttributes; var i: Integer; begin inherited SetColumnAttributes; {tell the grid to stop at each embedded object} for i := 1 to FieldCount do if not TabStops[i] then TabStops[i] := (GetObjIndex(i-1) <> -1); end; {______________________________________________________________________________} function TjvclEDBGrid.GetObjIndex (const GridIndex: integer): integer; var i: integer; begin result := -1; for i := 0 to GridObjs.Count-1 do {each embedded object must have a corresponding Calculated Field} if CompareText(TControl(GridObjs[i]).Name, Fields[GridIndex].FieldName) = 0 then begin result := i; break end; end; {______________________________________________________________________________} procedure TjvclEDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); begin if Assigned(FOnMouseDown) then FOnMouseDown(Self,Button,Shift,X,Y); inherited MouseDown(Button, Shift, X, Y); {show current embedded object} ShowObject := true; DrawCell(Col,Row,CellRect(Col,Row),[gdFocused,gdSelected]); end; {______________________________________________________________________________} procedure TjvclEDBGrid.KeyPress(var Key: Char); begin inherited KeyPress(Key); {show current embedded object, if need be} if ColumnHasObj and (Key <> #9) then begin ShowObject := true; DrawCell(Col,Row,CellRect(Col,Row),[gdFocused]); end; end; { Mod so that a control which is not resized to fit the column, appears right aligned to the column if it is near the right side of the grid control} {______________________________________________________________________________} {$ifdef WIN32} procedure TjvclEDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); {$else} procedure TjvclEDBGrid.DrawDataCell(const Rect: TRect; Field: TField; State: TGridDrawState); {$endif} begin {$ifdef WIN32} inherited DrawColumnCell(Rect,DataCol,Column,State); {$else} inherited DrawDataCell(Rect,Field,State); {$endif} if (gdFocused in State) and ObjEnabled then begin {check if there's a visible object then hide it} if iCurrentObj <> -1 then begin TControl(GridObjs[iCurrentObj]).Visible := false; iCurrentObj := -1; end; {check if the current column has an enbedded object then show it} if ShowObject then begin iCurrentObj := GetObjIndex(SelectedIndex); if iCurrentObj <> -1 then with TControl(GridObjs[iCurrentObj]) do begin if fResizeObjects = true then { Resize control to fit cell } Setbounds(Rect.Left + Self.Left, Rect.Top + Self.Top, Rect.Right - Rect.Left,Height) else begin { handle right align if required } if (Rect.Left + self.Left + width) > (self.Left + self.Width) then Setbounds(Rect.Right + Self.Left - width , Rect.Top + Self.Top, Width, Height) else { Normal left align } Setbounds(Rect.Left + Self.Left, Rect.Top + Self.Top, Width, Height); end; {make it visible and give it focus} Visible := true; TWinControl(GridObjs[iCurrentObj]).SetFocus; end; ShowObject := false; end; end; end; {______________________________________________________________________________} procedure TjvclEDBGrid.WMSetFocus(var Msg: TWMSetFocus); begin inherited; {adjust the cursor position after exiting an embedded object} if ColumnHasObj then if Col < FieldCount then Col := Col + 1 else begin Col := 1; Datasource.Dataset.Next; end; end; {______________________________________________________________________________} procedure TjvclEDBGrid.WMGetDlgCode(var Msg: TWMGetDlgCode); begin inherited; {set flag for KeyPress event (called once when entering each grid column)} ColumnHasObj := GetObjIndex(Col-1) <> -1; end; end.