自动生成数据源的可视化编辑组件?

时间:2010-02-04 07:51:04

标签: delphi devexpress

在我的项目中有一个TADOQuery tdm_Company,它填充了一组字段,在适当的地方提供了适当的标签和字段设置为visible = false。查询返回单个结果。
我有一个详细信息屏幕,需要一堆标签和编辑这些字段的文本框。 是否可以在编辑器中自动生成这些?如果我需要那些控件来自DevExpress组件(例如TcxDBTextEdit和TcxLabel),该怎么办?

3 个答案:

答案 0 :(得分:1)

我从来没有尝试过这个,但有(或者是 - 对不起,无法检查)Database Form Wizard。如果您希望拥有除向导生成的控件之外的其他控件,则可以在以后更改这些控件,例如: GExperts' Replace Components

答案 1 :(得分:1)

在一个非常类似的情况下(返回显示来自实体的联系人数据的单个记录的查询 - 公司,客户等),我们使用DevExpress的 TcxDBVerticalGrid 。当它显示一堆代表单个对象的数据时,它可以更好地扩展并且更灵活(特别是在调整表单大小时)。

当然,你不依赖于上面的组件,你可以用(几乎)任何垂直网格/ DBIspector获得好的结果但是因为你问了一个DevExpress组件我给你上面的解决方案。

HTH

答案 2 :(得分:1)

很久以前我实际创建了自己的向导,基于我为我的FrameWork编写的实际自定义表单。当显示向导的对话框时,它将显示网格中的所有字段,并允许用户指示应该使用哪个组件来显示该字段。

在我的情况下,根据字段类型,它预先填充了特定的组件(例如,TDateTime字段的TcxDateEdit,...)。用户仍然可以更改它,并指出他想要添加到表单的字段。一旦用户关闭表单,只需在所有字段上进行迭代并创建相应的控件。

通过我的代码搜索并找到了回复:

{ 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中为开发框架编写的内容。它应该让你知道如何实际做到这一点。

此致

斯特凡