首页 > 解决方案 > 无法在 Delphi 中更改 TEdit 文本

问题描述

我在运行时将组件添加到表单中,并且我还在字典中添加了更改这些组件的属性的事件,以便稍后调用它们。

TEventBeforeInsert = function(var AComponent: TComponent; AForm: TForm): Boolean of Object;

TFieldBase = class
private
  FEvent:TEventBeforeInsert;
....
function TFieldBase.EventBeforeInsert: TEventBeforeInsert;
begin
  Result:=FEvent;
end;

function TFieldBase.EventBeforeInsert(AEvent: TEventBeforeInsert): TFieldBase ;
begin
  FEvent:=AEvent;
  Result:=Self;
end;

....

表单调用

TFormBase.New
.addStringField
(
    TFieldBase.New
    .Enabled(True)
    .Description('User')
    .EventBeforeInsert(TEvents.New.EditFillUser), TTabsNames.Tab1
).Show();

表单类

TFormBase = class(TForm)
private
FDictionary: TDictionary<String, TEventBeforeInsert>;
...
function TFormBase.addStringField(AField: TFieldBase; ATab: TTabsNames): TFormBase;
var
  FLink: TLinkControlToField;
  FEdit: TEdit;
begin
  Result := Self;
  FEdit := TEdit.Create(Self);
  FEdit.Visible := True;
  FEdit.Parent := TPanel(PanelParent.FindComponent('PanelTab' + Ord(ATab).ToString));
  FEdit.Enabled:=AField.Enabled;

 
  if Assigned(AField.EventBeforeInsert) then
  begin
    FDictionary.Add(FEdit.Name,AField.EventBeforeInsert);
  end;
end;
...
procedure TFormBase.rectInsertClick(Sender: TObject);
var
    Item:String;
begin
  for Item in FDictionary.Keys do
  begin
    if Not FDictionary.Items[Item](Self.FindComponent(Item),Self) then
      Exit;
  end;
end;

我在这里遇到问题,在调试时我看到 text 属性被正确更改,但没有对正在显示的表单进行任何更改。

TEvents = class
...
function TEvents.EditFillUser(AComponent: TComponent;AForm: TForm): Boolean;
begin
  TEdit(AComponent).Text:=IntToStr(0);
  Result:=True;
end

我认为变量按值传递可能是一个问题......有人可以帮助我吗?

编辑1:我尝试过这样声明的字典:

FDictionary: TDictionary<TComponent, TEventBeforeInsert>;
...
if Not FDictionary.Items[Item](Item,Self) then //call

我也尝试过像这样使用 TForm 参考:

function TEvents.EditFillUser(AComponent: String;AForm: TForm): Boolean;
begin
  TEdit(AForm.FindComponent(AComponent)).Text:=IntToStr(0);
  Result:=True;
end

标签: delphi

解决方案


TFormBase.addStringField()中,在Name将新创建的TEdit对象插入FDictionary.. 只有在设计时创建的组件具有自动生成Name的 s。在运行时创建的组件不会。因此,您正在使用空白Names 跟踪您的对象。如果要通过 跟踪对象Name,则需要将自己的值实际分配给FEdit.Name,例如:

function TFormBase.addStringField(AField: TFieldBase; ATab: TTabsNames): TFormBase;
var
  ...
  FEdit: TEdit;
  FEvent: TEventBeforeInsert;
begin
  ...
  FEdit := TEdit.Create(Self);
  FEdit.Name := 'SomeUniqueNameHere'; // <-- for you to decide on...
  ...
 
  FEvent := AField.EventBeforeInsert;
  if Assigned(FEvent) then
    FDictionary.Add(FEdit.Name, FEvent);
end;

但是,在这种特殊情况下,我认为根本没有理由使用 a TDictionary。考虑使用 aTList代替,那么您根本不需要Names 。这也将提高迭代的性能,TFormBase.rectInsertClick()因为它不再需要寻找每个TComponent使用的对象FindComponent()

TFormBase = class(TForm)
private
  type TEventBeforeInsertPair = TPair<TComponent, TEventBeforeInsert>;
  FBeforeInsertEvents: TList<TEventBeforeInsertPair>;
  ...
public
  constructor Create;
  destructor Destroy; override;
  ...
end;

...

constructor TFormBase.Create;
begin
  inherited;
  FBeforeInsertEvents := TList<TEventBeforeInsertPair>.Create;
end;

destructor TFormBase.Destroy;
begin
  FBeforeInsertEvents.Free;
  inherited;
end;

function TFormBase.addStringField(AField: TFieldBase; ATab: TTabsNames): TFormBase;
var
  ...
  FEdit: TEdit;
  FEvent: TEventBeforeInsert;
begin
  ...
  FEdit := TEdit.Create(Self);
  ...

  FEvent := AField.EventBeforeInsert;
  if Assigned(FEvent) then
    FBeforeInsertEvents.Add(TEventBeforeInsertPair.Create(FEdit, FEvent));
end;

procedure TFormBase.rectInsertClick(Sender: TObject);
var
  Item: TEventBeforeInsertPair;
begin
  for Item in FBeforeInsertEvents do
  begin
    if not Item.Value(Item.Key, Self) then
      Exit;
  end;
end;

...

此外,您的TEvents.EditFillUser()方法与TEventBeforeInsert. 的第一个参数TEventBeforeInsert被声明为通过引用传递TComponent指针var(为什么?),但第一个参数EditFillUser()并没有这样做。除非您希望您的事件处理程序更改TComponent指针指向的内容(这不会像您当前使用TEventBeforeInsertwith的方式那样工作TDictionary),否则根本没有理由通过引用传递TComponent指针:var

TEventBeforeInsert = function(AComponent: TComponent; AForm: TForm): Boolean of Object;

此外,您的使用TEvents.New似乎是内存泄漏,因为没有人拥有新创建的TEvents对象的所有权(除非它的构造函数将该对象添加到我们看不到的某个内部列表中)。与 相同TFieldBase.New。甚至(假设关闭表单时TFormBase.New没有OnClose设置事件)。Action=caFree在某些时候,您需要调用Free()任何class您的对象Create()


推荐阅读