【问题标题】:Is it possible to display a form before a component/form is destroyed?是否可以在组件/表单被销毁之前显示表单?
【发布时间】:2012-04-16 13:12:31
【问题描述】:

我在 Delphi5 中工作

我希望在项目运行时销毁组件之前出现自定义表单。

是否可以在自定义组件中执行此操作?换句话说,我可以在自定义组件在运行时销毁之前显示一个表单,当放置它的表单关闭时?

我尝试在组件的析构函数中放置以下内容,但在关闭表单时出现访问冲突错误:

destructor TqqFormLogger.Destroy;
begin
  if NOT (csDesigning in ComponentState) then
    SurveyForm.Click;

  inherited Destroy;
end;

【问题讨论】:

  • 做你想做的事没问题。不可能说为什么它不适合你。 SurveyForm 是什么?任何更多代码的机会,以便我们可以看到 AV 在哪里。
  • 抱歉没说清楚。我拥有的是一个名为“FormLogger”的组件,它放置在我们项目的所有表单上。在项目运行时,该组件会创建一个 TButton(称为 SurveyButton),如果单击该按钮,则会打开一个表单(SurveyForm)。到目前为止,这部分工作正常。但是,我们希望在每次关闭表单时都打开 SurveyForm(即触发 SurveyButton.Click 事件)。似乎当在我的组件的析构函数中触发了 SurveyButton.click 时,承载该组件的主窗体已经被销毁。有解决办法吗?谢谢
  • 表单在设计时组件上自动调用FreeNotification()(反过来又调用表单的FreeNotification() 方法)。您的组件可以覆盖其Notification() 方法以检测何时释放表单。或者,如果您有任何在关闭时没有立即释放的 Form,您的组件的构造函数可以将事件处理程序分配给 Form 的 OnClose 事件。
  • 嗨雷米,谢谢你的建议。您能否阐明如何实施上述两个建议,特别是如何分配或覆盖我的所有者表单(组件所在的表单)的 OnClose 事件?

标签: delphi components vcl delphi-5


【解决方案1】:

一般来说,AV 是一些代码试图调用不再存在的例程的信号。

从这个角度来看,作为这个特定析构函数的结果的 AV 可能表示以下两种情况之一:

  1. SurveyForm 不存在了,或者
  2. SurveyForm.Click 的结果代码期望您的组件存在为真,但组件无论如何都会被销毁。

名称Click 暗示SurveyForm 是一个类似按钮的控件。如果该控件不是您的组件的一部分,而是该组件所在的表单的一部分,那么前者(案例 1)肯定是正确的:表单的析构函数已经销毁 SurveyForm,现在即将销毁您的零件。您可以通过使用 BeforeDestruction 来防止这种情况,正如 Remy 已经提到的那样。此外(但作为一般提示,而不是作为您的问题的解决方案),您可以通过将该组件注册到您自己的组件来防止使用已损坏的组件,以便在其销毁时得到通知。使用FreeNotification 和覆盖Notification 来执行此操作,其中您将组件设为零:

procedure TqqFormLogger.SetSurveyForm(Value: TForm);
begin
  FSurveyForm := Value;
  FSurveyForm.FreeNotification(Self);
end;

procedure TqqFormLogger.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (AComponent = FSurveyForm) and (Operation = opRemove) then
    FSurveyForm := nil;
end;

destructor TqqFormLogger.Destroy; 
begin
  if FSurveyForm <> nil then
    ...

如果控件确实是您的组件的一部分,那么我怀疑Click 后面的代码无论如何都允许处理组件的析构函数(案例2)。例如,当发布消息(手动或作为 VCL 或 Windows 内部的结果)时,inherited Destroy 将在消息到达或被处理之前被调用。

简而言之:现在这个问题太笼统,无法给出具体答案。

【讨论】:

  • SurveyForm 仍然存在于调用 Click 方法的位置,因为它在 TComponent.Destroy 执行之前不会死。
  • +1 每当组件引用外部组件时,最好使用FreeNotification(),以防外部组件被过早释放或无序释放。
  • @DavidHeffernan: 但我们还不知道何时/何地调用与TqqFormLogger.Destroy 相关的SurveyForm.Destroy,或者即使SurveyFormTqqFormLogger 的对象相同父窗体。
  • @RemyLebeau 这就是为什么目前任何答案都严重依赖猜测工作的原因。
【解决方案2】:

看看重写 BeforeDestruction() 方法而不是析构函数。

但是为什么要在组件层这样做呢?为什么不在父 Form 的 OnClose 事件中做呢?

【讨论】:

  • 为什么会有任何不同?大概问题是SurveyForm 不好。在 BeforeDestruction、OnClose 等中也是如此。
  • BeforeDestruction() 在任何析构函数之前被调用,因此它是一个类在其析构函数(尤其是隐式析构函数)有机会接触任何东西之前做事的好地方。但更重要的是,父窗体的OnClose 事件在窗体的任何子控件开始被销毁之前触发,因此这可能是在父窗体关闭后TqqFormLogger 之前释放SurveyForm 的时间问题@ 是销毁。
  • 为了简单化我的问题:是否有可能让组件控制或中断它的父(所有者)表单的关闭事件(破坏)过程,以便在表单关闭之前对其自己进行一些处理?
  • 不控制/中断,不。但是在 Form 上调用 FreeNotification(),当 Form 正在被释放时,您会收到通知。
  • 嗨 Remy,我在组件的创建构造函数中放置了 Owner.FreeNotification(self)。然后,我使用以下内容覆盖我的组件的 Notification 事件:如果 AComponent.Name = Owner.Name 然后是 SurveyForm.ShowModal。但是,这仍然不起作用。我想是因为父(所有者)表单在没有等待显示我的调查表的情况下关闭。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多