Vermeiden Sie Dialogkesselplatte in Delphi und /oder C ++
-
08-07-2019 - |
Frage
Ich muss oft einen Dialog im Delphi/C ++ -Builder entwerfen, mit dem verschiedene Eigenschaften eines Objekts geändert werden können, und der Code, der ihn verwendet, sieht normalerweise so 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;
Ich brauche auch oft einen ähnlichen Code, um Objekte zu/von XML/INI-Files/was auch immer zu marken.
Gibt es gemeinsame Redewendungen oder Techniken, um diese Art von einfachem, aber sich wiederholenden Code zu vermeiden?
Lösung
Nun, etwas, von dem ich völlig von unschätzbarem Wert fühle, ist das Gexperts Plugin -Assistent "Reverse Anweisung", der nach der Installation von Gexperts durch Drücken von Shift + Alt + R aufgerufen wird
Was es tut, ist automatisch die Aufgaben für den hervorgehobenen Block umzuschalten. Zum Beispiel:
edit1.text := dbfield.asString;
wird
dbField.asString := edit1.text;
Nicht genau das, wonach Sie suchen, sondern eine große Zeitsparung, wenn Sie eine große Anzahl von Aufgaben haben.
Andere Tipps
Hier ist meine Variation dazu. Was ich getan habe, nachdem ich den gleichen sich wiederholenden Code satt hatte, war, alle Bearbeitungsfelder gemäß den XML -Knotennamen zu benennen, die ich wollte, dann um die Komponenten umzusetzen und ihre Werte auszugeben. Der XML -Code sollte offensichtlich sein, und ich habe nur ein Bearbeiten und ein Kontrollkästchen, aber Sie sollten in der Lage sein, die Idee zu sehen.
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;
Es wird nicht als gute Praxis angesehen, auf Eigenschaften visueller Komponenten in einem Formular zuzugreifen. Es wird als besser angesehen, separate Eigenschaften zu haben. Im obigen Beispiel hätten Sie Benutzername und Kennworteigenschaften mit GET -and -Set -Methoden.
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.
Dies bedeutet, dass Sie die visuellen Komponenten im Formular ändern können, ohne dass es den aufrufenden Code beeinflusst.
Eine andere Option 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.
Delphi hat zumindest "mit", 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 Afaik hat nichts Ähnliches.
Bindungssteuerungen an Daten funktionieren in Delphi gut, aber leider nur dann, wenn diese Daten in einem tdataset -Nachkommen liegen. Sie können einen Tdataset -Nachkomme schreiben, der ein Objekt für die Datenspeicherung verwendet, und es stellt sich heraus, dass eine solche Sache 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 nach "Snap -Object -Datensatz" die Seite nach "Snap -Objekt -Datensatz"
Ich habe keine persönlichen Erfahrungen damit, aber es wäre sehr nützlich, wenn es funktioniert und insbesondere wenn es auch mit einzelnen Objektinstanzen wie einer Eigenschaft auf einem Datenmodul funktioniert ...
Sieh nach oben "Mediatormuster". Es ist ein GOF -Designmuster, und in ihrem Buch motiviert das GOF dieses Designmuster mit einer etwas ähnlichen Situation wie das, was Sie hier beschreiben. Es zielt darauf ab, ein anderes Problem zu lösen - Kopplung - aber ich denke, Sie haben haben Auch dieses Problem sowieso.
Kurz gesagt, die Idee ist, einen Dialogmediator zu erstellen, ein zusätzliches Objekt, das zwischen allen Dialogwidgets sitzt. Kein Widget kennt ein anderes Widget, aber jedes Widget kennt den Mediator. Der Mediator kennt alle Widgets. Wenn ein Widget ändert, informiert es den Mediator; Der Mediator informiert dann die relevanten Widgets darüber. Wenn Sie beispielsweise auf OK klicken, kann der Mediator andere Widgets über dieses Ereignis informieren.
Auf diese Weise kümmert sich jeder Widget nur um Ereignisse und Handlungen, die nur mit sich selbst zusammenhängen. Der Mediator kümmert sich um die Interaktion zwischen allen Widgets, sodass all dieser "Boilerplate" -Coder über alle Widgets aufgeteilt wird, und der "Rückstand", der global für alle Widgets ist, ist die Interaktion und liegt in der Verantwortung des Vermittlers.