Давным-давно я фактически создал для этого свой собственный мастер, основанный на фактической пользовательской форме, которую я написал для моей FrameWork. Когда отобразился диалог для мастера, он отобразил бы все поля в сетке и позволил бы пользователю указать, какой компонент следует использовать для отображения этого поля.
В моем случае, в зависимости от типа поля, оно было предварительно заполнено конкретными компонентами (например, TcxDateEdit для поля TDateTime, ...). Пользователь все еще может изменить это и указать, какие поля он хочет добавить в форму. Когда пользователь закрывает форму, нужно было просто перебрать все поля и создать соответствующий элемент управления.
Обыскал мой код и нашел это обратно:
{ Custom Devia Development Framework RecordView Module which adds functionality to
create the DB Aware Controls for the RecordView }
TDevFrameWorkRecordViewModule = class( TCustomModule )
protected
procedure CreateDBAwareComponents( aParent : TComponent; aDataSource : TDataSource; aFields : TFields; aFieldDefs : TFieldDefs ); virtual;
function DefaultWizardClass : TDBAwareControlWizardClass; virtual;
function DefaultLabelClass : TComponentClass; virtual;
function MaxFieldCaptionLength ( aFields : TFields ) : Integer; virtual;
protected
function GetSelectedComponents : IDesignerSelections;
function GetSelectedControl : TControl;
property SelectedControl : TControl read GetSelectedControl;
property SelectedComponents : IDesignerSelections read GetSelectedComponents;
public
procedure DevAddDBAwareComponentsWizard( aParent : TControl ); virtual;
procedure ExecuteVerb(Index: Integer); override;
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
end;
...
procedure TDevFrameWorkRecordViewModule.CreateDBAwareComponents(
aParent : TComponent; aDataSource : TDataSource; aFields : TFields; aFieldDefs : TFieldDefs );
var
lcv : Integer;
aLabel : TControl;
aEdit : TWinControl;
aDataBinding : TcxDBEditDataBinding;
aTop , aLeft : Integer;
aWidth : Integer;
aMaxCaptionWidth: Integer;
aDBLeft : Integer;
aRecordView : IDevFrameWorkRecordView;
aDBAwareClass : TComponentClass;
aDBAwareVisible : Boolean;
aWizardForm : TfrmDevFrameWorkAddDataAwareControlsWizard;
begin
{ First make sure the procedure was triggered on a FrameWorkRecordView }
if ( Supports( Root, IDevFrameWorkRecordView, aRecordView ) ) then
begin
{ Now Create and Show the wizard so the user can specify all the options }
aWizardForm := DefaultWizardClass.Create( Nil );
try
aWizardForm.RecordDataSet := aRecordView.DataSource.DataSet;
aWizardForm.InitialiseSettings;
{ If the user closed the Wizard using the OK button, we can continue the
process }
if ( aWizardForm.ShowModal = mrOK ) then
begin
{ By default the label components should start at 8,8 in the Parent Container }
aTop := 8;
aLeft := 8;
aWidth:= 121;
aMaxCaptionWidth := MaxFieldCaptionLength( aFields );
{ Now set the intial Left Position for our DBAware controls according
to the MaxCaptionWidth }
aDBLeft := 24 + ( ( ( aMaxCaptionWidth div 8 ) + 1 ) * 8 );
{ Loop over all fields to create the Label and DBAwareComponent }
for lcv := 0 to Pred( aFields.Count ) do
begin
{ Get some settings from the Wizard form }
aDBAwareClass := aWizardForm.GetDBAwareComponentClass( aFields[ lcv ] );
aDBAwareVisible := aWizardForm.GetDBAwareComponentVisible( aFields[ lcv ] );
{ Only create the components if the user indicated he wants to see them }
if aDBAwareVisible then
begin
{ Now create the Label and the DBAware Control }
aLabel := TControl ( Designer.CreateComponent( DefaultLabelClass, aParent, aLeft , aTop, aMaxCaptionWidth, 17 ) );
aEdit := TWinControl( Designer.CreateComponent( aDBAwareClass, aParent, aDBLeft, aTop, aWidth, 21 ) );
{ Now Set the Label Properties }
aLabel.Name := Designer.UniqueName( 'cxlbl' + aFields[ lcv ].FieldName );
aLabel.HelpType := htKeyWord;
aLabel.HelpKeyword := Root.Name + '.' + aFields[ lcv ].FieldName;
{ Set the additional properties using RTTI }
if ( IsPublishedProp( aLabel, 'FocusControl' ) ) then
begin
SetObjectProp( aLabel, 'FocusControl', aEdit );
end;
if ( IsPublishedProp( aLabel, 'Caption' ) ) then
begin
SetStrProp( aLabel, 'Caption', aFields[ lcv ].DisplayLabel );
end;
{ Now set the Edit Properites }
aEdit.Name := Designer.UniqueName( {'cxlbl' +} aFields[ lcv ].FieldName );
aEdit.HelpType := htKeyWord;
aEdit.HelpKeyword := Root.Name + '.' + aFields[ lcv ].FieldName;
{ Set the additional properties using RTTI }
if ( IsPublishedProp( aEdit, 'DataBinding' ) ) then
begin
aDataBinding := TcxDBEditDataBinding( GetObjectProp( aEdit, 'DataBinding' ) );
SetObjectProp( aDataBinding, 'DataSource', aDataSource );
SetStrProp ( aDataBinding, 'DataField' , aFields[ lcv ].FieldName );
end;
if ( aEdit is TcxCustomDropDownEdit ) then
begin
aEdit.Width := aWidth + 16;
end;
{ Now increment the Top position for the next control }
inc( aTop, ( ( ( aEdit.Height div 8 ) + 1 ) * 8 ) );
end;
end;
end;
finally
FreeAndNil( aWizardForm );
end;
end;
end;
function TDevFrameWorkRecordViewModule.DefaultLabelClass: TComponentClass;
begin
Result := TLabel;
end;
function TDevFrameWorkRecordViewModule.DefaultWizardClass: TDBAwareControlWizardClass;
begin
Result := TfrmDevFrameWorkAddDataAwareControlsWizard;
end;
procedure TDevFrameWorkRecordViewModule.ExecuteVerb(Index: Integer);
var
aSelections : IDesignerSelections;
lcv : Integer;
begin
aSelections := TDesignerSelections.Create;
Designer.GetSelections( aSelections );
for lcv := 0 to Pred( aSelections.Count ) do
begin
{$IFDEF CODESITE}
csFWRecordView.Send( 'aSelection.Items[ lcv ]', aSelections.Items[ lcv ] );
{$ENDIF}
end;
Case Index of
0 : DevAddDBAwareComponentsWizard( SelectedControl );
else Inherited ExecuteVerb( Index );
end;
end;
{*****************************************************************************
This function will be used to return a list of selected components on the
current designer.
@Name TDevFrameWorkRecordViewModule.GetSelectedComponents
@author Devia - Stefaan Lesage
@param None
@return None
@Exception None
@See None
******************************************************************************}
function TDevFrameWorkRecordViewModule.GetSelectedComponents: IDesignerSelections;
begin
Result := TDesignerSelections.Create;
Designer.GetSelections( Result );
end;
function TDevFrameWorkRecordViewModule.GetSelectedControl: TControl;
var
lcv : Integer;
begin
Result := Nil;
if ( Assigned( SelectedComponents ) ) then
begin
if ( SelectedComponents.Count <> 0 ) then
begin
for lcv := 0 to Pred( SelectedComponents.Count ) do
begin
if ( SelectedComponents.Items[ lcv ] is TControl ) then
begin
Result := TControl( SelectedComponents.Items[ lcv ] );
Break;
end;
end;
end;
end;
end;
function TDevFrameWorkRecordViewModule.GetVerb(Index: Integer): string;
begin
Case Index of
0 : Result := 'Dev.AddDataAwareComponents';
end;
end;
function TDevFrameWorkRecordViewModule.GetVerbCount: Integer;
begin
Result := 1;
end;
{*****************************************************************************
This function will determine the length of the Longest field's caption.
@Name TDevFrameWorkRecordViewModule.MaxFieldCaptionLength
@author Devia - Stefaan Lesage
@param None
@return Returns the length of the longest field's catpion.
@Exception None
@See None
******************************************************************************}
function TDevFrameWorkRecordViewModule.MaxFieldCaptionLength(
aFields: TFields): Integer;
var
aMaxCaptionWidth : Integer;
aCanvas : TCanvas;
lcv : Integer;
aCaption : String;
begin
aMaxCaptionWidth := 0;
{ First Determine how long the largest caption will be }
aCanvas := TDevFrameWorkRecordView( Root ).Canvas;
{ Loop over each field to dertermin which caption is the longest one }
for lcv := 0 to Pred( aFields.Count ) do
begin
if ( aFields[ lcv ].DisplayLabel <> '' ) then
begin
aCaption := aFields[ lcv ].DisplayLabel;
end
else
begin
aCaption := aFields[ lcv ].FieldName;
end;
if ( aCanvas.TextWidth( aCaption ) >
aMaxCaptionWidth ) then
begin
aMaxCaptionWidth := aCanvas.TextWidth( aCaption );
end;
end;
{ Return the Length of the Longest Caption }
Result := aMaxCaptionWidth;
end;
procedure TDevFrameWorkRecordViewModule.DevAddDBAwareComponentsWizard( aParent : TControl );
var
aRecordView : IDevFrameWorkRecordView;
aDataSource : TDataSource;
begin
{$IFDEF CODESITE}
csFWRecordView.EnterMethod( Self, 'DevAddDBAwareComponentsWizard' );
{$ENDIF}
if ( Supports( Root, IDevFrameWorkRecordView, aRecordView ) ) then
begin
{$IFDEF CODESITE}
csFWRecordView.SendMsg( csmInfo, 'Root supports I®FrameWorkRecordView' );
{$ENDIF}
aDataSource := TDataSource( Designer.GetComponent( 'srcMain' ) );
if ( Assigned( aDataSource ) ) and
( Assigned( aDataSource.DataSet ) ) then
begin
{$IFDEF CODESITE}
csFWRecordView.SendMsg( csmInfo, 'aRecordView.DataSource Assigned' );
csFWRecordView.SendMsg( csmInfo, 'aRecordView.DataSource.DataSet Assigned' );
{$ENDIF}
CreateDBAwareComponents( aParent, aDataSource, aDataSource.DataSet.Fields, aDataSource.DataSet.FieldDefs );
end;
end;
{$IFDEF CODESITE}
csFWRecordView.ExitMethod( Self, 'DevAddDBAwareComponentsWizard' );
{$ENDIF}
end;
Конечно, это не скомпилируется для вас. Это то, что я написал для среды разработки в Delphi 7 несколько лет назад. Это должно дать вам представление о том, как вы могли бы это сделать.
С уважением,
Stefaan