如何检查是不是在 TTabSheet 控件上创建了 OnResize 事件?
Posted
技术标签:
【中文标题】如何检查是不是在 TTabSheet 控件上创建了 OnResize 事件?【英文标题】:How can I check if OnResize event is created on TTabSheet control?如何检查是否在 TTabSheet 控件上创建了 OnResize 事件? 【发布时间】:2016-08-15 15:00:58 【问题描述】:我在TPageControl
上有多个TTabSheet
,并且在某些操作上,用户单击一个按钮,我想在选定的TTabSheet
上运行OnResize
事件。问题是并非所有TTabSheet
控件都创建了OnResize
事件。
我在按钮上有这个代码:
procedure TForm1.Button1Click(Sender: TObject);
begin
TTabSheet(PageControl1.ActivePage).OnResize(PageControl1.ActivePage);
end;
procedure TForm1.TabSheet1Resize(Sender: TObject);
begin
// actions on Resize
end;
它在TabSheet1
处于活动状态时起作用。但是当TabSheet2
处于活动状态并且它没有OnResize
事件时,我得到错误:
Project Project1.exe 引发异常类 $C0000005 并显示消息 '访问地址 0x00000000: 读取地址 0x00000000'.
我尝试检查 nil,如下所示:
If TTabSheet(PageControl1.ActivePage).OnResize(PageControl1.ActivePage) <> nil then...
但它不能编译:
E2008 不兼容类型。
我发现的解决方法是让每个TTabSheet
控件都有空的OnResize
事件,只有注释,没有代码。
如果TTabSheet
有OnResize
事件,有没有比 nil 更好的检查?
谢谢
【问题讨论】:
如果已分配(PageControl1.ActivePage.OnResize) 则 .... 如果我是你,我会尽量避免从代码中调用事件处理程序。 OnResize 改变了一些 TLabrl 和 TEdit 控件的显示方式。我也需要在单击按钮时执行它。我怎样才能避免调用它但被执行? 框架调用事件。如果您想对按钮单击和调整大小事件做出响应,我会执行以下操作: 1. 创建一个执行该操作的私有方法。 2. 从按钮单击处理程序调用该私有方法。 3. 从 resize 事件调用该私有方法。 完全不清楚您要解决什么问题。您是在 IDE 表单设计器中创建 Tabsheet2,还是在代码中创建? 【参考方案1】:您可能以错误的方式处理此问题。您不应在代码中调用事件处理程序。把它留给框架。而是这样写:
procedure TForm1.DoTabsheet1Resize;
begin
// actions on Resize
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DoTabsheet1Resize;
end;
procedure TForm1.TabSheet1Resize(Sender: TObject);
begin
DoTabsheet1Resize;
end;
这里DoTabsheet1Resize
是您定义的私有方法。
【讨论】:
所以我需要为 TabSheet1 和其他每个 TabSheet 编写这个新的私有方法吗?他们是私人的什么?我知道每个类都可以有私有方法,那么这些在哪个类中呢? TTabSheet 在 Vcl.ComCtrls 类 TWinControl 中定义。那里?还是每个执行它们的 TButton? 啊哈,我明白了……它在 TForm1 中!从未创建私有方法,所以我很困惑。【参考方案2】:procedure TForm1.Button1Click(Sender: TObject);
begin
If Assigned(PageControl1.ActivePage.OnResize)
then PageControl1.ActivePage.OnResize(Sender);
end;
【讨论】:
已分配零、空和未附加检查?这适用于所有情况还是仅适用于某些情况? @Matej 你能定义“空”和“非附加”吗?这些是什么东西?答案是没有这样的事情。如果事件处理程序是nil
,则Assigned()
返回False
,并且没有附加事件处理程序。看到代码从外部调用事件处理程序仍然让我有点恶心。
好的,谢谢大卫。我对 Objetct Inspector 中的 TTabSheet 事件感到困惑。它显示它们在那里,但没有附加代码。所以它们存在但没有被分配。对我来说还是有点困惑。
所以如果我使用 Assigned 我不需要 TTabSheet() 在 PageControl1.ActivePage 之前?
@Matejmtj 是否分配没有区别。 ActivePage
已经是 TTabSheet
了,所以没有必要像这样显式地转换它。【参考方案3】:
从你的评论来看
我设置了 OnResize 事件,但没有设置 TabSheet2。所以 TabSheet2 在 Object Inspector 中有 OnResize 但在 unit1 的代码中没有。
我认为您可能对表单设计器的确切内容感到困惑,它定义了事件处理代码。
试试这个:
在新创建的空白表单上,放置一个 TPageControl,PageControl1,右键单击它并在其中创建两个 TabSheet,TabSheet1 和 TabSheet2。
在 OI 中,单击 TabSheet1,在 OI 中单击其事件选项卡,然后单击 OnResize 事件属性中的下拉按钮。你会发现下拉列表是空的。
现在双击 Tabsheet1 的 OnResize 事件。这样做会导致 OI 在表单的代码中创建一个空的事件处理过程 TabSheet1Resize。它还将 TabSheet1 的 OnResize 属性分配给此过程 TabSheet1Resize。此时不要保存表单,否则 IDE 将检测到此过程不包含代码(或 cmets)并将其删除。
在 TabSheet1Resize 中添加此代码
Caption := 'TabSheet1.Resize';
并保存表单的单位。
现在在 OI 中选择 TabSheet2 的事件选项卡并在其 OnResize 事件中单击。此时 TabSheet2 的 OnResize 属性未分配给任何过程,因此尝试调用 TabSheet2.OnResize()
将导致 AV,因为其 OnResize 属性的值为 Nil。
现在,在 TabSheet2 的 OnResize 中,单击下拉按钮,您将看到
TabSheet1Resize
作为列表中的单个条目。从列表中选择它,现在 TabSheet2 的 OnResize 属性的值与 TabSheet1'1 相同,即过程 TabSheet1Resize。
第 3 步和第 6 步对于 TabSheet1 和 TabSheet2 具有相同的 OnResize 事件处理程序代码至关重要。
换句话说,您的评论似乎忽略了对象(在本例中为 TTabSheet always)所具有的事件处理程序属性(例如 OnResize)之间的差异(这就是 OI 向您展示的原因事件处理程序 property)和事件处理程序 procedure 中的代码(如果有),事件处理程序属性被分配到。
对不起,如果以上所有内容都非常明显,那么我误解了你的几个 cmets。
如果您希望所有其他选项卡具有与 TabSheet1 相同的 OnResize 处理程序,您可以在例如您的 FormCreate 事件处理程序中进行设置,如下所示:
procedure TForm1.FormCreate(Sender: TObject);
var
i : integer;
begin
for i := 1 to PageControl1.PageCount - 1 do
PageControl1.Pages[i].OnResize := PageControl1.Pages[0].OnResize;
// PageControl1.Pages[0] will be equal to TabSheet1, if that's the first Tabsheet
// you created
end;
【讨论】:
很好的解释!您确实误解了我的问题,但您正确地认识到我缺乏词汇:事件处理程序属性和事件处理程序过程。现在我知道更多了。以上是关于如何检查是不是在 TTabSheet 控件上创建了 OnResize 事件?的主要内容,如果未能解决你的问题,请参考以下文章