4

オブジェクトのさまざまなプロパティを変更できるようにするダイアログを 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-files/whatever との間でオブジェクトをマーシャリングするために、同様のコードが必要になることがよくあります。

この種の単純だが反復的なコードを避けるための一般的なイディオムやテクニックはありますか?

4

6 に答える 6

3

まあ、私が完全にかけがえのないものだと感じているのは、 Shift + ALT + Rを押してGExpertsをインストールした後に呼び出されるGExpertsプラグインウィザード「リバースステートメント」です。

ハイライトされたブロックの割り当てを自動的に切り替えます。例えば:

edit1.text := dbfield.asString;

になる

dbField.asString := edit1.text;

探しているものとはまったく異なりますが、多数の割り当てがある場合は時間を大幅に節約できます。

于 2008-10-10T15:54:58.180 に答える
3

これが私のバリエーションです。同じ繰り返しのコードにうんざりした私がしたことは、必要な 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;
于 2008-10-10T15:16:08.133 に答える
1

フォーム上のビジュアル コンポーネントのプロパティにアクセスすることは、お勧めできません。別々のプロパティを持つ方が良いと考えられています。上記の例では、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.

これは、呼び出し元のコードに影響を与えることなく、フォームのビジュアル コンポーネントを変更できることを意味します。

もう 1 つのオプションは、オブジェクトをプロパティとしてダイアログに渡すことです。

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.

それが役立つことを願っています。

于 2008-10-13T10:12:45.717 に答える
0

問題を完全に解決するわけではありませんが、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;

ビルダーの知る限り、似たようなものはありません。

于 2008-10-10T14:33:33.773 に答える
0

「メディエーターパターン」を調べてください。これは GoF 設計パターンであり、彼らの著書では、GoF は実際に、ここで説明しているものと幾分似た状況でこの設計パターンを動機付けています。別の問題(結合)を解決することを目的としていますが、とにかくこの問題も抱えていると思います。

つまり、ダイアログ メディエーター (すべてのダイアログ ウィジェットの間に配置される追加のオブジェクト) を作成するという考え方です。ウィジェットは他のウィジェットを認識していませんが、各ウィジェットはメディエーターを認識しています。メディエータはすべてのウィジェットを認識しています。1 つのウィジェットが変更されると、メディエーターに通知されます。その後、メディエータは関連するウィジェットにこれを通知します。たとえば、[OK] をクリックすると、メディエーターはこのイベントについて他のウィジェットに通知する場合があります。

このようにして、各ウィジェットはそれ自体に関連するイベントとアクションのみを処理します。メディエーターはすべてのウィジェット間の相互作用を処理するため、この「ボイラープレート」コードはすべてすべてのウィジェットに分割され、すべてのウィジェットにグローバルな「残り」は相互作用であり、メディエーターの責任です。

于 2008-10-11T15:47:24.373 に答える
0

コントロールをデータにバインドすることは、Delphi ではうまく機能しますが、残念ながら、そのデータが TDataSet の子孫に存在する場合に限られます。データ ストレージにオブジェクトを使用する TDataSet の子孫を記述できますが、そのようなものが既に存在することがわかります。以下のリンクを参照してください... この実装は、単一のオブジェクトではなく、オブジェクトのコレクション (TCollection または TObjectList) でのみ機能するようです。

http://www.torry.net/pages.php?id=563 - ページで「Snap Object DataSet」を検索します

私はこれについて個人的な経験はありませんが、機能する場合、特にデータモジュールのプロパティなどの単一のオブジェクトインスタンスでも機能する場合は非常に便利です...

于 2008-10-10T17:03:32.707 に答える