避免Delphi和/或C++中的对话框板
Avoiding Dialog Boilerplate in Delphi and /or C++
我经常需要在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文件/其他文件。
有没有一些常见的习惯用法或技巧可以避免这种简单但重复的代码?
好吧,我觉得非常宝贵的是GExpert插件向导"反向语句",它在安装GExpert后通过按Shift+ALT+R 调用
它的作用是自动切换高亮显示块的指定。例如:
edit1.text := dbfield.asString;
成为
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和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.
希望能有所帮助。
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没有什么相似之处。
将控件绑定到数据在Delphi中运行良好,但遗憾的是,只有当数据驻留在TDataSet子代中时。您可以编写一个使用对象进行数据存储的TDataSet子体,结果发现已经存在这样一个对象。请参阅下面的链接。。。此实现似乎只适用于对象集合(TCollection或TObjectList),而不适用于单个对象。
http://www.torry.net/pages.php?id=563-在页面中搜索"捕捉对象数据集"
我对此没有任何个人经验,但如果它能工作,尤其是如果它也能处理单个对象实例,例如数据模块上的属性,那将非常有用。。。
查找"中介模式"。这是一个GoF设计模式,在他们的书中,GoF实际上用与你在这里描述的情况有点相似的情况来激励这种设计模式。它旨在解决一个不同的问题——耦合——但我认为无论如何你也有这个问题。
简而言之,这个想法是创建一个对话框中介器,一个位于所有对话框小部件之间的额外对象。没有一个小部件知道任何其他小部件,但每个小部件都知道中介。中介知道所有的小部件。当一个小部件发生更改时,它会通知中介;中介器然后将此情况通知相关的小部件。例如,当您单击"确定"时,中介器可能会将此事件通知其他小部件。
通过这种方式,每个小部件只处理与自身相关的事件和操作。中介负责所有小部件之间的交互,因此所有这些"样板"代码都被拆分到所有小部件上,对所有小部件全局的"残留物"就是交互,这是中介的责任。
- 如何在Qbutton的帮助下更改Q对话框的宽度
- 当对话框被接受时,如何用参数调用槽
- WinAPI 在单击第一个对话框上的按钮控件并销毁第一个对话框后创建第二个对话框
- 如何多次询问来自QML对话框的输入?
- 选择文件对话框错误
- 自定义对话框(源自QDialog)不会关闭(Android)
- 如何在 MFC 对话框中使用 OnDraw
- 在C++中创建文件夹选取器对话框的最简单方法是什么?
- 从资源视图访问对话框时出现问题
- 如何检测窗口当前是否正在运行模式对话框?
- "最小化"按钮不会出现在 MFC 对话框中
- 如何获取QNetworkConfiguration UserChoice对话框?
- 表单显示对话框函数错误,并且不执行下面的语句
- 如何在 VC6 中的对话框中将图标设置为按钮
- C++/Win32 构造函数不使用从对话框获取的字符串初始化变量
- 在 Win32 应用中,如果未选择文件夹并且用户单击"确定",则文件夹选择对话框将关闭
- 在主窗口之前显示登录对话框并隐藏主窗口按钮
- 找不到没有具有类名 #32770 的窗口名称的父窗口的子窗口(对话框)
- 如何在主窗口标签的对话框中显示QLineEdit的输入
- Qt为所有对话框设置通用背景