c++ delphi modal-dialog boilerplate

Evitar el texto repetitivo en Delphi y/o C++



modal-dialog boilerplate (6)

La vinculación de los controles a los datos funciona bien en Delphi, pero desafortunadamente solo cuando esos datos residen en un descendiente TDataSet. Podría escribir un descendiente TDataSet que utiliza un objeto para el almacenamiento de datos, y resulta que uno de estos ya existe. Vea el enlace a continuación ... Esta implementación parece funcionar solo con colecciones de objetos (TCollection o TObjectList), no objetos individuales.

http://www.torry.net/pages.php?id=563 - busque en la página "Snap Object DataSet"

No tengo experiencia personal con esto, pero sería muy útil si funciona y especialmente si también funciona con instancias de objetos únicos, como una propiedad en un módulo de datos ...

A menudo necesito diseñar un diálogo en Delphi / C ++ Builder que permita que se modifiquen varias propiedades de un objeto, y el código para usarlo generalmente se ve así.

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;

También a menudo necesito un código similar para ordenar objetos a / desde xml / ini-files / lo que sea.

¿Hay algún modismo o técnica común para evitar este tipo de código simple pero repetitivo?


No se considera una buena práctica acceder a las propiedades de los componentes visuales en un formulario. Se considera mejor tener propiedades separadas. En el ejemplo anterior, tendría propiedades de nombre de usuario y contraseña con los métodos get y set.

Por ejemplo:

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.

Esto significa que puede cambiar los componentes visuales en el formulario sin que esto afecte al código de llamada.

Otra opción sería pasar el objeto como una propiedad al 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 ayude.


bueno, algo que siento completamente invaluable es el asistente de plugins de GExperts "Reverse Statement" que se invoca después de instalar GExperts presionando Shift + ALT + R

Lo que hace es cambiar automáticamente las asignaciones para el bloque resaltado. Por ejemplo:

edit1.text := dbfield.asString;

se convierte

dbField.asString := edit1.text;

No es exactamente lo que estás buscando, pero ahorra mucho tiempo cuando tienes una gran cantidad de tareas.


Aquí está mi variación sobre esto. Lo que hice, habiéndome hartado del mismo código repetitivo, fue nombrar todos los cuadros de edición de acuerdo con los nombres de nodo XML que quería, luego iterar alrededor de los componentes y dar salida a sus valores. El código XML debe ser obvio, y solo tengo una casilla de edición y de verificación, pero debería poder ver la idea.

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;


Delphi al menos tiene ''With'', aunque no resuelve el problema por completo.

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;

Y el constructor AFAIK no tiene nada por igual.


Busque el " patrón del mediador ". Es un patrón de diseño GoF, y en su libro el GoF de hecho motiva este patrón de diseño con una situación algo similar a lo que está describiendo aquí. Tiene como objetivo resolver un problema diferente, el acoplamiento, pero creo que también tienes este problema de todos modos.

En resumen, la idea es crear un mediador de diálogo, un objeto adicional que se encuentre entre todos los widgets de diálogo. Ningún widget sabe de ningún otro widget, pero cada widget conoce el mediador. El mediador conoce todos los widgets. Cuando un widget cambia, informa al mediador; el mediador luego informa los widgets relevantes sobre esto. Por ejemplo, cuando hace clic en Aceptar, el mediador puede informar a otros widgets sobre este evento.

De esta forma, cada widgets se ocupa solo de los eventos y acciones relacionados con él. El mediador se ocupa de la interacción entre todos los widgets, por lo que todo este código "repetitivo" se divide en todos los widgets, y el "residuo" que es global para todos los widgets es la interacción, y es responsabilidad del mediador.