Delphi黑盒技术

This article explains how to create forms/units

本文介绍了如何创建表格/单元

independent of other forms/units object names in a delphi project.

delphi项目中的其他表单/单元对象名称无关

Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi project. In Delphi this is easy, just use the "Add file to project (Shift+F11)" to add the unit from the other project,

您是否曾经在Delphi项目中创建过供用户输入的表单,然后又需要在其他Delphi项目中具有相同的表单。 在Delphi中,这很容易,只需使用“将文件添加到项目(Shift + F11)”即可添加其他项目中的单元,

add name of the unit to your other unit uses implementation and the form is available in this project. But then ... you hit compile ... the compiler starts complaining with errors like

将单位名称添加到您的其他单位使用的实现中,并且此项目中提供该表格。 但是然后...您点击了编译...编译器开始抱怨诸如以下错误

Form2 not found

Let's consider the following problem: The application needs a name and description for a new article from the user.

让我们考虑以下问题:应用程序需要用户的新文章的名称和描述。

Most Delphi programmers would solve this problem with a form like this:

大多数Delphi程序员会使用以下形式解决此问题:

Create a new Form, give it a new name (frmNewArticle), put a TEdit (editArticleName),  a TMemo (memoArticleDescr) and a button (btnOk, modalresult = mrOk) on it, and then call that new form from the main form like this:  

创建一个新窗体,为其赋予一个新名称(frmNewArticle),在其上放置一个TEdit(editArticleName),一个TMemo(memoArticleDescr)和一个按钮(btnOk,modalresult = mrOk),然后从主窗体调用该新窗体,例如这个:

procedure TfrmMain.btnGetNewArticleClick(Sender: TObject);
var 
  frm: TfrmNewArticle;
begin
  frm := TfrmNewArticle.Create(Self);
  try
    if frm.ShowModal = mrOk then 
    begin
      labelArticleName.Caption := frm.editArticleName.Text;
      memoArticleDescr.Text := frm.memoArticleDescr.Text;
    end;
  finally
    FreeAndNil(frm);
  end;
end;     
unit uNewArticle;
 
interface
    
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Buttons, StdCtrls, ExtCtrls;
  
type
  TfrmNewArticle = class(TForm)
    editArticleName: TEdit;
    labelArticleName: TLabel;
    memoArticleDescr: TMemo;
    labelArticleDescr: TLabel;
    btnOk: TBitBtn;
    btnCancel: TBitBtn;
  end;
 
var 
  frmNewArticle: TfrmNewArticle;
   
implementation 
 
{$R *.dfm } 
   
end.

This works, no problem... But consider what would happen when a other developer decides to:

这可行,没问题...但是请考虑当其他开发人员决定执行以下操作时会发生什么:

  Change the names of the edit and memo

更改编辑和备忘录的名称

    - editArticleName to edName

-editArticleName到edName

    - memoArticleDescr to edDescr

-memoArticleDescr到edDescr

  Change the name of the form (and type)

更改表单的名称(和类型)

    - frmNewArticle to frmBasicInput

-从frmNewArticle到frmBasicInput

This would force you into rewriting parts or your project too. And off course, nobody likes that. But in which way can we program so this doesn't happen? Well, you guessed it, with the blackbox technique.

这将迫使您也重写零件或项目。 当然,没人喜欢那样。 但是我们可以通过哪种方式编程,以免发生这种情况? 好吧,您猜对了,采用了黑盒技术。

The first thing you need to do is change the way the input form is addressed by using a function. Place that function in the user input form

您需要做的第一件事是通过使用函数来更改输入表单的寻址方式。 将该功能放在用户输入表单中

unit uNewArticle;
 
interface
    
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Buttons, StdCtrls, ExtCtrls;
  
type
  TfrmNewArticle = class(TForm)
    editArticleName: TEdit;
    labelArticleName: TLabel;
    memoArticleDescr: TMemo;
    labelArticleDescr: TLabel;
    btnOk: TBitBtn;
    btnCancel: TBitBtn;
  end;
 
var 
  frmNewArticle: TfrmNewArticle;
   
// new function inserted
function NewArticle_NameAndDescr(var aNewName: string; var aNewDescr: string): boolean;
   
implementation 
 
{$R *.dfm }  
  
// new function implementation inserted
function NewArticle_NameAndDescr(var aNewName: string; var aNewDescr: string): boolean;
var frm: TfrmNewArticle;
begin
  Result := False;
  frm := TfrmNewArticle.Create(nil);
  try
    frm.editArticleName.Text := aNewName;
    frm.memoArticleDescr.Text := aNewDescr;
    if frm.ShowModal = mrOk then 
    begin
      Result := True;
      aNewName := frm.editArticleName.Text;
      aNewDescr := frm.memoArticleDescr.Text;
    end;
  finally
    FreeAndNil(frm);
  end;
end; 
  
end.

Next is to use this new function inside the mainform

接下来是在主窗体中使用此新功能

procedure TfrmMain.btnGetNewArticleClick(Sender: TObject);
var aName, aDescr: string;
begin
  aName := '';
  aDescr := '';
  if NewArticle_NameAndDescr(aName, aDescr) then 
  begin
    labelArticleName.Caption := aName;
    memoArticleDescr.Text := aDescr;
  end;
end;     

Now what would happen if somebody were to change the names of the edit and memo? The compiler would complain too, but it would be in the unit where the names changed, and not in your unit! A good programmer would solve the compiler errors in the function you inserted, and thus solving the problem for you as well.

现在,如果有人更改编辑和备忘录的名称会发生​​什么? 编译器也会抱怨,但是它将在更改名称的单元中出现,而不是在您的单元中出现! 一个好的程序员可以解决您插入的函数中的编译器错误,从而也为您解决问题。

Now let's extend on this. If we were to change the form and add a edit for a barcode number, and if we wanted this barcode in our main form, we would have to change our function header too. A solution could be :

现在让我们对此进行扩展。 如果要更改表单并添加条形码编号的编辑,并且如果我们希望在主表单中使用此条形码,则也必须更改函数头。 一个解决方案可能是:

  
function NewArticle_NameAndDescr(var aNewName: string; var aNewDescr: string; 
  var aNewBarcode: string): boolean;
  

This is leading to a different problem: the parameters in the header of the function/procedure.

这导致了另一个问题:函数/过程的标题中的参数。

A more adaptable approach for the parameters would be using a TStrings to pass/retreive info. Let's change the function so it has only a TStrings as parameter (you want to change the contents of the TStrings, not the parameter pointer, so no var )

参数的更适合的方法是使用TStrings传递/检索信息。 让我们更改函数,使其仅包含一个TStrings作为参数(您想更改TStrings的内容,而不是参数指针,因此更改var

function NewArticle_NameAndDescr(Params: TStrings): boolean;
var frm: TfrmNewArticle;
begin
  Result := False;
  frm := TfrmNewArticle.Create(nil);
  try
    frm.editArticleName.Text := Params.Values['NAME'];
    frm.memoArticleDescr.Text := Params.Values['DESCR'];
    if frm.ShowModal = mrOk then 
    begin
      Result := True;
      Params.Values['NAME'] := frm.editArticleName.Text;
      Params.Values['DESCR'] := frm.memoArticleDescr.Text;
    end;
  finally
    FreeAndNil(frm);
  end;
end; 
procedure TfrmMain.btnGetNewArticleClick(Sender: TObject);
var Params: TStringList;
begin
  Params := TStringList.Create;
  try
    // no need for init of Name and Descr
    // Params.Text is empty !!!
    if NewArticle_NameAndDescr(Params) then 
    begin
      labelArticleName.Caption := Params.Values['NAME'];
      memoArticleDescr.Text := Params.Values['DESCR'];
    end;
  finally
    FreeAndNil(Params);
  end;
end;     

And with the new barcode:

并使用新的条形码:

function NewArticle_NameAndDescr(Params: TStrings): boolean;
var frm: TfrmNewArticle;
begin
  Result := False;
  frm := TfrmNewArticle.Create(nil);
  try
    frm.editArticleName.Text := Params.Values['NAME'];
    frm.memoArticleDescr.Text := Params.Values['DESCR'];
    frm.editArticleBarcode.Text := Params.Values['BARCODE'];
    if frm.ShowModal = mrOk then 
    begin
      Result := True;
      Params.Values['NAME'] := frm.editArticleName.Text;
      Params.Values['DESCR'] := frm.memoArticleDescr.Text;
      Params.Values['BARCODE'] := frm.editBarcode.Text;
    end;
  finally
    FreeAndNil(frm);
  end;
end; 

This is a simple demo of a blackbox technique using a function with parameter TStrings. The basic idea is to put the function/procedure in the interface section of the same unit.

这是使用带有参数TStrings的函数的黑盒技术的简单演示。 基本思想是将功能/过程放在同一单元的接口部分。

If anybody changes names of the form or it's components then the developer will get warnings at compile time about any extra code changes needed. With this you can make units using this form independent of the implementation of the name of the form or its component names.

如果有人更改了表单或其组件的名称,则开发人员将在编译时收到有关需要进行任何其他代码更改的警告。 这样,您可以使使用此表单的单元独立于表单名称或其组件名称的实现。

翻译自: https://www.experts-exchange.com/articles/1285/Delphi-blackbox-technique.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值