문제

델파이/C ++ 빌더에서 대화 상자를 설계 해야하는 경우가 종종 객체의 다양한 속성을 수정할 수있게 해주 며 사용하는 코드는 일반적으로 다음과 같습니다.

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/uthing에 대한 마샬링 객체에 대해 유사한 코드가 필요합니다.

이런 종류의 단순하지만 반복적 인 코드를 피하기위한 일반적인 관용구 나 기술이 있습니까?

도움이 되었습니까?

해결책

글쎄, 내가 완전히 귀중한 느낌은 gexperts Plugin Wizard "Reverse Statement"는 Shift + Alt + R을 눌러 Gexperts를 설치 한 후 호출됩니다.

그것이하는 일은 강조 표시된 블록의 과제를 자동으로 전환하는 것입니다. 예를 들어:

edit1.text := dbfield.asString;

becomes

dbField.asString := edit1.text;

당신이 찾고있는 것이 아니라 많은 과제가있을 때 큰 시간 절약입니다.

다른 팁

여기에 내 변형이 있습니다. 내가 한 일은 동일한 반복 코드로 지어진 일은 내가 원하는 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;

양식에 시각적 구성 요소의 속성에 액세스하는 것은 모범 사례로 간주되지 않습니다. 별도의 특성을 갖는 것이 더 나은 것으로 간주됩니다. 위의 예에서는 Get and 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.

도움이되기를 바랍니다.

델파이는 최소한 '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은 아무것도 없습니다.

데이터에 대한 바인딩 제어는 델파이에서 잘 작동하지만 불행히도 해당 데이터가 Tdataset 자손에 존재하는 경우에만 적합합니다. 데이터 저장에 객체를 사용하는 Tdataset Descendant를 쓸 수 있으며, 그러한 것이 이미 존재하는 것으로 나타났습니다. 아래 링크를 참조하십시오 ...이 구현은 단일 객체가 아닌 개체 모음 (tcollection 또는 tobjectlist)에서만 작동하는 것으로 보입니다.

http://www.torry.net/pages.php?id=563 - "Snap Object DataSet"에 대한 페이지 검색

나는 이것에 대한 개인적인 경험이 없지만, 그것이 작동하는 경우, 특히 데이터 모듈의 속성과 같은 단일 객체 인스턴스에서도 작동하는 경우에 매우 유용 할 것입니다 ...

찾아라 "중재자 패턴". 그것은 GOF 디자인 패턴이며, 그들의 책에서 GOF는 실제로이 디자인 패턴을 여기에서 묘사하는 것과 다소 비슷한 상황으로 동기를 부여합니다. 다른 문제를 해결하는 것을 목표로하지만, 나는 당신이 가지고 있다고 생각합니다. 이 문제도 어쨌든.

요컨대, 아이디어는 모든 대화 상자 위젯 사이에있는 추가 객체 인 대화 상자 중재자를 만드는 것입니다. 위젯은 다른 위젯에 대해 알지 못하지만 각 위젯은 중재자를 알고 있습니다. 중재자는 모든 위젯을 알고 있습니다. 하나의 위젯이 변경되면 중재자에게 알려줍니다. 그런 다음 중재자는 관련 위젯에 이에 대해 알려줍니다. 예를 들어, 확인을 클릭하면 중재자 가이 이벤트에 대해 다른 위젯에 알릴 수 있습니다.

이런 식으로 각 위젯은 그 자체와 관련된 이벤트와 행동을 처리합니다. 중재자는 모든 위젯 간의 상호 작용을 처리 하므로이 모든 "보일러 플레이트"코드는 모든 위젯을 통해 분할되며 모든 위젯에 전역 인 "잔류 물"은 상호 작용이며 중재자의 책임입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top