5

在Delphi中,有时我们需要这样做......

function TForm1.EDIT_Click(Sender: TObject);
begin
  (Sender As TEdit).Text := '';
end;

...但有时我们需要使用其他对象类重复该功能,例如...

function TForm1.COMBOBOX_Click(Sender: TObject);
begin
  (Sender As TComboBox).Text := '';
end;

...因为运营商As不接受灵活性。它必须知道类才能.Text允许().

有时代码会充满相似之处functionsprocedures因为我们需要使用我们无法指定的相似视觉控件来做同样的事情。

这只是一个使用示例。通常,我将这些代码用于更复杂的代码,以在许多控件和其他类型的对象上实现标准目标。

是否有替代方案或技巧可以使这些任务更加灵活?

4

7 回答 7

12

使用 RTTI 对不相关类的同名属性执行常见任务,例如:

Uses
 ..., TypInfo;

// Assigned to both TEdit and TComboBox
function TForm1.ControlClick(Sender: TObject);
var
  PropInfo: PPropInfo;
begin
  PropInfo := GetPropInfo(Sender, 'Text', []);
  if Assigned(PropInfo) then
    SetStrProp(Sender, PropInfo, '');
end;

在某些情况下,一些控件使用Text而另一些则使用Caption,例如;

function TForm1.ControlClick(Sender: TObject);
var
  PropInfo: PPropInfo;
begin
  PropInfo := GetPropInfo(Sender, 'Text', []);
  if not Assigned(PropInfo) then
    PropInfo := GetPropInfo(Sender, 'Caption', []);
  if Assigned(PropInfo) then
    SetStrProp(Sender, PropInfo, '');
end;
于 2012-07-05T04:16:45.597 回答
10

你可以使用is运算符,试试这个示例

 if Sender is TEdit then
  TEdit(Sender).Text:=''
 else
 if Sender is TComboBox then
  TComboBox(Sender).Text:='';
于 2012-07-04T22:02:39.253 回答
5

您可以通过使用absolute关键字来消除混乱的类型转换,该关键字允许您声明不同类型的变量占用相同的内存位置,在这种情况下与事件参数的位置相同。

您仍然需要使用“is”执行类型检查,但在其他方面,这种方法更简洁但同样安全。

procedure TMyForm.ControlClick(Sender: TObject);
var
  edit: TEdit absolute Sender;
  combo: TComboBox absolute Sender;
   :
begin
  if Sender is TEdit then
    edit.Text := ''
  else if Sender is TComboBox then
    combobox.Text := ''
  else
   :
end;

大约3 年前,我在我的博客中更详细地介绍了使用此语言功能。

于 2012-07-05T03:48:24.530 回答
2

我将我的评论作为答案发布,因为我在这里看不到任何提到这一点的答案。SetTextBuf 是 TControl 的公共方法。此方法用于通过 SetText 窗口消息填充内部文本数据成员。这就是 TControl 后代更新 Caption 和 Text 属性的方式。因此所有 TControl 后代,例如 TButton、TEdit、TComboBox 都将使用以下类型的代码工作。而且您不必使用 RTTI。

function TForm1.EDIT_Click(Sender: TObject);
begin
  (Sender as TControl).SetTextBuf('Text or Caption'); // will work for both the Caption and text property
end;
于 2012-07-05T18:22:21.603 回答
1

我不知道您是否将 tag 属性用于任何用途,但它对这些情况很有用。将所有 Tedits 的标签设置为 1 并将所有 Tcomboboxes 的标签设置为 2 等可以让你这样做:

if Sender is TControl then
  Case TControl(Sender).tag of
    1: TEdit(sender).text := '';
    2: Tcombobox(sender).text := '';
    3....etc
  end;

只是一个想法,它看起来更整洁,更容易阅读/调试:)

于 2012-07-05T10:52:28.657 回答
0

感谢你们,特别是@RemyLebeau,我可以使这个通用功能适用于任何类型的 Win 控件或数据库控件。如果它是必需的但为空,如果它在数据库中有重复的信息,或者我们想要检查的任何其他条件,它会将控件变为红色(或您想要的任何颜色)。它返回数字而不是真假,因此我们可以在多次检查结束时只发送一条消息,并告诉用户他/她犯了多少错误。

function CheckInput(Control: TWinControl; Condition: Boolean; EmptyState: Integer; Msg: String): Integer;
var
  PropInfo: PPropInfo;
begin
{ os controles que precisam passar por condições para que seu conteúdo seja aceito }
  Result := 0;
  if EmptyState = ciNotEmpty then
  begin
    PropInfo := GetPropInfo(Control, 'Text', []);
    if Assigned(PropInfo) then
    begin
      if GetStrProp(Control, PropInfo) = '' then
      begin
        Condition := False;
        Msg := ciEmptyMsg;
      end;
    end;
  end;
  if not Condition then
  begin
    Result := 1;
    PropInfo := GetPropInfo(Control, 'Color', []);
    if Assigned(PropInfo) then SetPropValue(Control, PropInfo, ciErrorColor);
    if Msg <> '' then ShowMessage(Msg);
  end
  else
  begin
    PropInfo := GetPropInfo(Control, 'Color', []);
    if Assigned(PropInfo) then SetPropValue(Control, PropInfo, ciNormalColor);
  end;
end;
于 2012-07-28T02:57:54.410 回答
-1

如果你一直往下走,你会注意到 TEdit 和 TCombobox 都从 TControl 下降。如果您查看他们使用哪种方法来设置文本,那么您会发现它是 TControl 实现的方法。这就是为什么你可以做一些丑陋的事情,比如:

if (sender is TEdit) or (sender is TComboBox) then
  TEdit(sender).Text:='test';

您必须确保您放入此处的所有对象在内部使用相同的方法,否则您的应用程序将以神秘的方式中断。

于 2012-07-05T06:44:56.157 回答