Pergunta

Muitas vezes, preciso projetar uma caixa de diálogo no construtor Delphi/C ++ que permite que várias propriedades de um objeto sejam modificadas, e o código para usá -lo normalmente se parece com isso.

Dialog.Edit1.Text := MyObject.Username;
Dialog.Edit2.Text := MyObject.Password;
// ... many more of the same

if (Dialog.ShowModal = mrOk) 
begin
  MyObject.Username := Dialog.Edit1.Text;
  MyObject.Password := Dialog.Edit2.Text;
  // ... again, many more of the same
end;

Eu também geralmente preciso de um código semelhante para marcar objetos para/de xml/ini-files/o que for.

Existem idiomas ou técnicas comuns para evitar esse tipo de código simples, mas repetitivo?

Foi útil?

Solução

Bem, algo que me sinto completamente inestimável é o Gexperts Assistente de plug -in "declaração reversa", que é invocada após a instalação do GEXPERTS, pressionando o Shift + Alt + R

O que ele faz é alternar automaticamente as atribuições para o bloco destacado. Por exemplo:

edit1.text := dbfield.asString;

torna-se

dbField.asString := edit1.text;

Não é exatamente o que você está procurando, mas um enorme economizador de tempo quando você tem um grande número de tarefas.

Outras dicas

Aqui está minha variação sobre isso. O que eu fiz, tendo sido cansado do mesmo código repetitivo, foi nomear todas as caixas de edição de acordo com os nomes de nó XML que eu queria, depois itera em torno dos componentes e produzir seus valores. O código XML deve ser óbvio, e eu só tenho uma edição e uma caixa de seleção, mas você deve ver a ideia.

procedure TfrmFTPSetup.LoadFromXML(szFileName : string);
var
xComponent : TComponent;
nLoop : Integer;
xMainNode : TXmlNode;
xDocument : TNativeXml;
begin
inherited;

xDocument := TNativeXml.Create;
try
    xDocument.LoadFromFile(szFileName);
    xMainNode := xml_ChildNodeByName(xDocument.Root, 'options');
    for nLoop := 0 to ComponentCount - 1 do
    begin
        xComponent := Components[nLoop];
        if xComponent is TRzCustomEdit then
        begin
            (xComponent as TRzCustomEdit).Text := xMainNode.AttributeByName[xComponent.Name];
        end;
        if xComponent is TRzCheckBox then
        begin
            (xComponent as TRzCheckBox).Checked := xml_X2Boolean(xMainNode.AttributeByName[xComponent.Name], false);
        end;
    end;
finally
    FreeAndNil(xDocument);
end;
 end;

   procedure TfrmFTPSetup.SaveToXML(szFileName : string);
var
xComponent : TComponent;
nLoop : Integer;
xMainNode : TXmlNode;
xDocument : TNativeXml;
begin
inherited;

xDocument := TNativeXml.CreateName('ftpcontrol');
try
    xMainNode := xml_ChildNodeByNameCreate(xDocument.Root, 'options');
    for nLoop := 0 to ComponentCount - 1 do
    begin
        xComponent := Components[nLoop];
        if xComponent is TRzCustomEdit then
        begin
            xMainNode.AttributeByName[xComponent.Name] := (xComponent as TRzCustomEdit).Text;
        end;
        if xComponent is TRzCheckBox then
        begin
            xMainNode.AttributeByName[xComponent.Name] := xml_Boolean2X((xComponent as TRzCheckBox).Checked);
        end;
    end;

    xDocument.XmlFormat := xfReadable;
    xDocument.SaveToFile(szFileName);
finally
    FreeAndNil(xDocument);
end;
 end;

Não é considerado uma boa prática acessar propriedades de componentes visuais em um formulário. É considerado melhor ter propriedades separadas. No exemplo acima, você teria propriedades de nome de usuário e senha com métodos GET e Set.

Por exemplo:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
  private
    function GetPassword: string;
    function GetUsername: string;
    procedure SetPassword(const Value: string);
    procedure SetUsername(const Value: string);
  public
    property Password: string read GetPassword write SetPassword;
    property Username: string read GetUsername write SetUsername;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.GetPassword: string;
begin
 Result := Edit2.Text;
end;

function TForm1.GetUsername: string;
begin
 Result := Edit1.Text;
end;

procedure TForm1.SetPassword(const Value: string);
begin
  Edit2.Text := Value;
end;

procedure TForm1.SetUsername(const Value: string);
begin
  Edit1.Text := Value;
end;

end.

Isso significa que você pode alterar os componentes visuais no formulário sem que ele afete o código de chamada.

Outra opção seria passar o objeto como uma propriedade para a caixa de diálogo;

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TUserObject = class(TObject)
  private
   FPassword: string;
   FUsername: string;
  public
   property Password: string read FPassword write FPassword;
   property Username: string read FUsername write FUsername;
  end;

  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    btnOK: TButton;
    procedure btnOKClick(Sender: TObject);
  private
    FUserObject: TUserObject;
    procedure SetUserObject(const Value: Integer);
  public
    property UserObject: Integer read FUserObject write SetUserObject;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnOKClick(Sender: TObject);
begin
 FUserObject.Username := Edit1.Text;
 FUserObject.Password := Edit2.Text;
 ModalResult := mrOK;
end;

procedure TForm1.SetUserObject(const Value: Integer);
begin
 FUserObject := Value;
 Edit1.Text := FUserObject.Username;
 Edit2.Text := FUserObject.Password;
end;

end.

Espero que ajude.

Delphi pelo menos tem 'com', embora não resolva completamente o problema.

if (Dialog.ShowModal = mrOk) 
begin
  with MyObject do
  begin
    Username := Dialog.Edit1.Text;
    Password := Dialog.Edit2.Text;
    // ... again, many more of the same
  end;
end;

E o construtor Afaik não tem nada parecido.

Os controles de ligação aos dados funcionam bem em Delphi, mas infelizmente somente quando esses dados residem em um descendente de TDataset. Você pode escrever um descendente do TDataSet que usa um objeto para armazenamento de dados, e acontece que já existe uma dessas coisas. Veja o link abaixo ... Esta implementação parece funcionar apenas com coleções de objetos (TCollection ou TobjectList), não objetos únicos.

http://www.torry.net/pages.php?id=563 - Pesquise a página para "DATASET DE ESTRABILIDADE

Não tenho experiência pessoal com isso, mas seria muito útil se funcionasse e, especialmente, se também funcionasse com instâncias de objetos únicos, como uma propriedade em um módulo de dados ...

Olho para cima "Padrão do mediador". É um padrão de design do GOF e, em seu livro, o GoF de fato motiva esse padrão de design com uma situação um tanto semelhante ao que você está descrevendo aqui. Ele visa resolver um problema diferente - acoplamento - mas acho que você tem Esse problema também.

Em suma, a idéia é criar um mediador de diálogo, um objeto extra que fica entre todos os widgets de diálogo. Nenhum widget conhece nenhum outro widget, mas cada widget conhece o mediador. O mediador conhece todos os widgets. Quando um widget muda, ele informa o mediador; O mediador então informa os widgets relevantes sobre isso. Por exemplo, quando você clica em OK, o mediador pode informar outros widgets sobre este evento.

Dessa forma, cada widgets cuida apenas de eventos e ações relacionadas a si mesmo. O mediador cuida da interação entre todos os widgets; portanto, todo esse código "Boilerplate" é dividido em todos os widgets, e o "resíduo" que é global para todos os widgets é a interação e é de responsabilidade do mediador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top