【问题标题】:Access Violation when touching dynamic form?触摸动态表单时访问冲突?
【发布时间】:2011-02-10 21:00:13
【问题描述】:

我正在动态创建一个窗体,但是关闭它的例程位于我的主窗体的单元中,因为它与我的主窗体 (TSkype) 上的控件相关联。该事件是 SkypeAsyncSearchUsersFinished。当 SkypeAsyncSearchUsersFinished 例程完成时,我尝试将 ModalResult 设置为动态表单的 mrOk。但是,这会产生访问冲突。

这是搜索完成时触发的代码:

   if SIDList.Count = 0 then
   begin
     frmSearcher.tmrFadeOut.Enabled := True;
   end;

我尝试调试它,并在 frmSearcher.tmrFadeOut 处设置了一个断点...然后我进入下一行(例程 End;),这就是 AV 出现的时候。

tmrFadeOutTimer 事件执行 ModalResult := mrOk;

这就是我创建动态表单的方式:

Function ShowSearcher():Boolean;
Var
   dlg : TfrmSearcher;
Begin
  Result := False;
  dlg := TfrmSearcher.Create(Forms.Application);


  dlg.tmrFadeIn.Enabled := True;


    if dlg.ShowModal = mrOk then
         Begin
         // Do nothing here

         End;

  Result := True;
  dlg.Release;

End;

是的,我确信计时器只会启用一次。 :)

是的,我确定表单是“活动的”。 :)

实际上,如果我删除 tmrFadeOut.Enabled 代码,一切正常,但表单不会关闭。执行 frmSearcher.ModalResult := mrOk; 也会产生 AV。

如果您需要更多信息,我会添加。 :)

非常感谢! :)

【问题讨论】:

  • 您能发布错误消息的确切文本吗?这会有所帮助。
  • frmSearcher.tmrFadeOut.Enabled := True;dlg.tmrFadeIn.Enabled := True; 之类的代码意味着在TfrmSearcher 之外,您了解该表单的内部结构。你不应该:在TfrmSearcher 上创建一个属性或一组方法来封装TfrmSearcher 的内部工作。
  • @Mason - 这是访问冲突。错误代码取决于我是启用计时器还是设置 ModalResult。 :)
  • @Jeroen 是的,现在当你提到它时.. :)

标签: delphi dynamic


【解决方案1】:

由于您是手动创建 TfrmSearcher 表单,请删除 IDE 生成的变量 frmSearcher,修复您将遇到的编译错误,一切都会好起来的。

您获得了 AV,因为 frmSearcher 为 NIL。

【讨论】:

  • 谢谢,我回家试试!当然会回报!哈哈,我真的需要列出导致 AV 的原因。 :P
  • @Cosmin - 如果我没有 frmSearcher,我该如何调用 tmrFadeOut.Enable?请记住,我是从 frmMain 中的过程调用 tmrFadeOut。 :) 我可以使用frmSearcher 而不是dlg 吗?
  • 不,不要使用frmSearcher。将dlg 变量从ShowSearcher() 例程移动到主窗体类的私有部分。然后你使用dlg 来做dlg.tmrFadeOut.Enabled := True。为了安全起见,我也会在那之后立即使用dlg := nil
  • @Jeff:AVs 是由非法内存访问引起的。基本上有两件事导致它:取消引用设置为 nil 的指针或对象引用,或取消引用设置为垃圾值的指针或对象引用,因为它要么尚未初始化,要么已损坏以某种方式。
  • @Jeff:正确理解它需要掌握超过三句话的指针知识。不过,简单的版本是,在处理对象时,任何时候调用对象的任何成员(属性、字段或方法),您都在取消引用对象引用。换句话说,变量是对内存中实际对象的引用(指针),并且您正在跟踪它指向(引用)的内存。如果指针无效,那么您将遇到访问冲突。
【解决方案2】:

您正在将新的 TfrmSearcher 对象实例分配给其他方法无法访问的本地 dlg 变量。您的其他例程正在尝试使用您未分配任何值的 frmSearcher 变量访问对话框。

【讨论】:

    【解决方案3】:

    我将其添加为答案,因为我想格式化代码。这不是试图回答这个问题,我可能会在适当的时候删除,特别是如果我得到很多反对票(同行压力)。

    我想展示的是如何创建、展示和销毁表单。你这样做:

    procedure ShowMyForm;
    var
      Form: TMyForm;
    begin
      Form := TMyForm.Create(nil);
      try
        Form.ShowModal;
      finally
        Form.Free;
      end;
    end;
    

    在您的代码中:

    1. 无需将所有者传递给构造函数,因为您正在确定表单的生命周期。
    2. 函数的返回变量毫无意义,因为你总是返回True。唯一的失败模式是通过异常但函数没有返回值。
    3. 不要打电话给Release,原来的Free才是你想要的。您在处理消息时调用Release,并且希望在处理当前队列中的任何消息后表单消失。

    【讨论】:

    • 即使它不是答案,我仍然 +1 它,因为它对我有帮助。谢谢大卫!
    • 我之所以使用我发布的代码,是因为我通常在从表单传递和返回数据时使用该模板,例如添加内容时。所以,按照我的方式做,应该是当我来回传递一些数据时(我需要知道模态结果是否是 mrOk),但是当我只想显示一个表单时,我使用你的。对吗?
    • @Jeff Points are 1 and 3 适用于你所说的情况。如果您需要从表格中返回信息,例如无论用户单击确定还是取消,然后在需要时将其传回。保留从未使用过的变量通常被认为是一个坏主意。以后修改代码时很容易陷入陷阱,而且还会使代码变得更长、更密集,从而影响可读性,并使您更难使代码正确,这始终是您的第一目标。
    • @Jeff 更改代码!将procedure ShowMyForm 变成procedure ShowMyForm(out MyReturnVariable: TMyReturnVariableType)
    • @David- 是的,我知道,但我应该在 ShowModal 之后添加 if Form.ModalResult = mrOk then MyReturnVariable := Something; 吗?
    猜你喜欢
    • 2014-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 2015-03-28
    • 1970-01-01
    • 2020-01-04
    相关资源
    最近更新 更多