我有程序在TForm上显示/隐藏一个元素:
procedure ShowHideControl(const ParentForm: TForm; const ControlName: String; ShowControl: Boolean);
var
i: Integer;
begin
for i := 0 to pred(ParentForm.ComponentCount) do
begin
if (ParentForm.Components[i].Name = ControlName) then
begin
if ShowControl then
TControl(ParentForm.Components[i]).Show
else
TControl(ParentForm.Components[i]).Hide;
Break;
end;
end;
end;
然后我尝试使用它:
procedure TForm1.Button6Click(Sender: TObject);
begin
ShowHideEveryControl(TForm(TForm1), 'Button4', True);
end;
为什么我在Button6点击时会出现访问冲突?
对我来说一切都很好...... Button4作为一个孩子存在:)
答案 0 :(得分:5)
这个演员是错误的:
TForm(TForm1)
您告诉编译器忽略TForm1
不是TForm
实例并要求它假装它的事实。在您实际尝试将其用作实例之前,这很好,然后发生错误。
您需要将实例传递给TForm
后代。你可以这样写:
ShowHideEveryThing(Self, 'Button4', True);
如果您对此不清楚,您的过程参数的类型为TForm
。这意味着您需要提供一个或者来自TForm
的类的实例。我再说一遍,你必须提供一个实例。但是您提供的TForm1
是类。
接下来的问题就出现了:
if (ParentForm.Components[i].Name = FormName) then
begin
if ShowForm then
TForm(ParentForm.Components[i]).Show
else
TForm(ParentForm.Components[i]).Hide;
Break;
end;
你再次使用了错误的演员。当编译器告诉您某个特定对象没有方法时,您必须听它。将编译器关闭并伪装成一种类型的对象实际上是不同类型的对象并不好。您的按钮绝对不是表单,因此请勿尝试将其投射到TForm
。
很难知道你在这里想要做什么。当你写:
ShowHideEveryThing(Self, 'Button4', True);
在我看来,写作更加明智:
Button4.Show;
使用表示为文本的名称来引用控件并不是一个好主意。使用引用变量引用它们更安全,更清晰。这样你就让编译器完成它的工作并检查程序的类型安全性。
您的函数中使用的名称是可疑的:
procedure ShowHideEveryThing(const ParentForm: TForm; const FormName: String;
ShowForm: Boolean);
让我们来看看它们:
ShowHideEveryThing
:但您声称该功能应显示/隐藏一个元素。这与使用所有内容无关。FormName
:您实际传递了一个组件名称,然后查找具有该名称的ParentForm
拥有的组件。似乎FormName
是错误的。ShowForm
:再次,您想控制表单或单个元素的可见性吗?显然,你需要退后一步,明确这个功能的意图。
顺便说一句,你通常不需要写:
if b then
Control.Show
else
Control.Hide;
相反,你可以写:
Control.Visible := b;
我给你的第一条建议就是停止施法,直到你理解它为止。一旦你理解正确,尽可能设计你的代码,这样你就不需要施放。如果您确实需要强制转换,请确保您的强制转换有效,最好使用as
运算符进行检查。或者至少先使用is
运算符进行测试。
您的代码显示了经典错误的所有标志。编译器对应于您编写的代码。您已从某处了解到可以使用转换来抑制这些编译器错误,现在您可以广泛应用此技术作为编译程序的方法。问题是编译器总是知道它在说什么。当它反对时,听它。如果您发现自己使用演员表来抑制编译器错误,请退后一步,仔细考虑您正在做什么。编译器是你的朋友。