Автоматически создавать компоненты визуального редактирования для источника данных? - PullRequest
0 голосов
/ 04 февраля 2010

В моем проекте есть TADOQuery tdm_Company, которая заполняется набором полей, снабженных надлежащими метками и полями, установленными в visible = false, где это необходимо. Запрос возвращает один результат. У меня есть подробный экран, который нуждается в куче меток и редактировать текстовые поля для этих полей. Можно ли автоматически сгенерировать их в редакторе? Что, если мне нужны эти элементы управления, чтобы они были элементами управления DevExpress (например, TcxDBTextEdit и TcxLabel)?

Ответы [ 3 ]

1 голос
/ 05 февраля 2010

В очень похожем случае (запрос на возврат единственной записи, показывающей контактные данные от объекта - компании, клиента и т. Д.) Мы используем DevExpress TcxDBVerticalGrid . Он масштабируется намного лучше и более гибок (особенно при изменении размера формы), когда дело доходит до отображения группы данных, представляющих один объект.

Конечно, вы не привязаны к вышеуказанному компоненту, вы можете получить хорошие результаты с (почти) любым вертикальным гридом / DBIspector, но так как вы спросили о компоненте DevExpress, я дал вам вышеуказанное решение.

НТН

1 голос
/ 05 февраля 2010

Давным-давно я фактически создал для этого свой собственный мастер, основанный на фактической пользовательской форме, которую я написал для моей 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

1 голос
/ 04 февраля 2010

Я никогда не пробовал этого, но есть (или был? - извините, не могу проверить) Мастер форм базы данных . Если вы хотите иметь другие элементы управления, отличные от тех, которые генерирует мастер, есть возможность изменить их впоследствии, например, GExperts 'Заменить компоненты .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...