4 Stimmen

Vermeidung von Dialog-Boilerplate in Delphi und /oder C++

Ich muss oft ein Dialogfeld in Delphi/C++Builder entwerfen, mit dem verschiedene Eigenschaften eines Objekts geändert werden können, und der entsprechende Code sieht in der Regel wie folgt aus.

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;

Außerdem benötige ich oft ähnlichen Code für das Marshalling von Objekten in/aus Xml/Ini-Dateien/was auch immer.

Gibt es gängige Idiome oder Techniken, um diese Art von einfachem, aber sich wiederholendem Code zu vermeiden?

3voto

mj2008 Punkte 6597

Hier ist meine Variante davon. Nachdem ich den gleichen, sich wiederholenden Code satt hatte, benannte ich alle Eingabefelder nach den gewünschten XML-Knotennamen und gab dann die Komponenten durch und ihre Werte aus. Der XML-Code sollte offensichtlich sein, und ich habe nur ein Bearbeitungsfeld und ein Kontrollkästchen, aber Sie sollten die Idee erkennen können.

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;

3voto

skamradt Punkte 15128

Nun, etwas, das ich für absolut unschätzbar halte, ist die GExperts Plugin-Assistent "Reverse Statement", der nach der Installation von GExperts durch Drücken von Shift + ALT + R aufgerufen wird

Dabei werden die Zuweisungen für den markierten Block automatisch umgeschaltet. Zum Beispiel:

edit1.text := dbfield.asString;

wird

dbField.asString := edit1.text;

Nicht genau das, was Sie suchen, aber eine enorme Zeitersparnis, wenn Sie eine große Anzahl von Aufträgen haben.

1voto

dcraggs Punkte 758

Es gilt nicht als gute Praxis, auf Eigenschaften von visuellen Komponenten in einem Formular zuzugreifen. Es wird als besser angesehen, getrennte Eigenschaften zu haben. Im obigen Beispiel hätten Sie die Eigenschaften Benutzername und Kennwort mit den Methoden get und set.

Zum Beispiel:

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.

Das bedeutet, dass Sie die visuellen Komponenten des Formulars ändern können, ohne dass dies Auswirkungen auf den aufrufenden Code hat.

Eine andere Möglichkeit wäre, das Objekt als Eigenschaft an den Dialog zu übergeben;

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.

Ich hoffe, das hilft.

0voto

akalenuk Punkte 3755

Delphi hat zumindest "With", obwohl es das Problem nicht vollständig löst.

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;

Und Builder hat AFAIK nichts Ähnliches.

0voto

Jozz Punkte 637

Das Binden von Steuerelementen an Daten funktioniert in Delphi gut, aber leider nur, wenn sich die Daten in einem TDataSet-Abkömmling befinden. Man könnte einen TDataSet-Nachfolger schreiben, der ein Objekt zur Datenspeicherung verwendet, und es stellt sich heraus, dass so etwas bereits existiert. Siehe Link unten... Diese Implementierung scheint nur mit Sammlungen von Objekten (TCollection oder TObjectList) zu funktionieren, nicht mit einzelnen Objekten.

http://www.torry.net/pages.php?id=563 - Suchen Sie auf der Seite nach "Snap Object DataSet".

Ich habe keine persönlichen Erfahrungen damit, aber es wäre sehr nützlich, wenn es funktioniert und vor allem, wenn es auch mit einzelnen Objektinstanzen funktionieren würde, wie z.B. einer Eigenschaft eines Datenmoduls...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X