Избегание диалогового окна в Delphi и / или C ++ - PullRequest
4 голосов
/ 10 октября 2008

Мне часто нужно создавать диалог в Delphi / C ++ Builder, который позволяет изменять различные свойства объекта, и код для его использования обычно выглядит так:

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;

Мне также часто требуется подобный код для сортировки объектов в / из xml / ini-файлов / чего угодно.

Существуют ли распространенные идиомы или методы, позволяющие избежать такого простого, но повторяющегося кода?

Ответы [ 6 ]

3 голосов
/ 10 октября 2008

хорошо, что я считаю совершенно бесценным, это плагин GExperts мастера «Обратное утверждение», который вызывается после установки GExperts нажатием Shift + ALT + R

То, что он делает, это автоматически переключает назначения для выделенного блока. Например:

edit1.text := dbfield.asString;

становится

dbField.asString := edit1.text;

Не совсем то, что вы ищете, но очень экономит время, когда у вас большое количество заданий.

3 голосов
/ 10 октября 2008

Вот мой вариант этого. То, что я сделал, сыт по горло одним и тем же повторяющимся кодом, заключалось в том, чтобы назвать все поля редактирования в соответствии с именами узлов XML, которые я хотел, затем перебрать компоненты и вывести их значения. Код XML должен быть очевидным, и у меня есть только поле редактирования и флажок, но вы должны увидеть идею.

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;
1 голос
/ 13 октября 2008

Не считается хорошей практикой доступ к свойствам визуальных компонентов в форме. Считается, что лучше иметь отдельные свойства. В приведенном выше примере вы будете иметь свойства username и password с методами get и set.

Например:

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.

Это означает, что вы можете изменить визуальные компоненты в форме, не влияя на код вызова.

Другой вариант - передать объект как свойство в диалоговое окно;

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.

Надеюсь, это поможет.

0 голосов
/ 11 октября 2008

Посмотрите " образец посредника ". Это шаблон проектирования GoF, и в своей книге GoF фактически мотивирует этот шаблон проектирования в ситуации, несколько схожей с тем, что вы здесь описываете. Он направлен на решение другой проблемы - навязывание - но я думаю, что у вас все равно есть эта проблема.

Короче говоря, идея состоит в том, чтобы создать посредник диалога, дополнительный объект, который находится между всеми виджетами диалога. Ни один виджет не знает ни о каком другом виджете, но каждый виджет знает посредника. Посредник знает все виджеты. Когда один виджет изменяется, он информирует посредника; Затем посредник информирует соответствующие виджеты об этом. Например, при нажатии кнопки «ОК» посредник может сообщить об этом событии другим виджетам.

Таким образом, каждый виджет заботится о событиях и действиях, связанных только с самим собой. Посредник заботится о взаимодействии между всеми виджетами, поэтому весь этот «шаблонный» код разделен на все виджеты, а «остаток», который является глобальным для всех виджетов, является взаимодействием, и это является обязанностью посредника. *

0 голосов
/ 10 октября 2008

Привязка элементов управления к данным работает хорошо в Delphi, но, к сожалению, только когда эти данные находятся в потомке TDataSet. Вы могли бы написать потомка TDataSet, который использует объект для хранения данных, и оказалось, что одна такая вещь уже существует. См. Ссылку ниже ... Похоже, эта реализация работает только с коллекциями объектов (TCollection или TObjectList), а не с отдельными объектами.

http://www.torry.net/pages.php?id=563 - поиск на странице "Snap Data DataSet"

У меня нет личного опыта с этим, но было бы очень полезно, если бы он работал, особенно если он также работал бы с единичными экземплярами объекта, такими как свойство в модуле данных ...

0 голосов
/ 10 октября 2008

Delphi по крайней мере имеет 'With', хотя это не решает проблему полностью.

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;

И у строителя AFAIK нет ничего похожего.

...