【问题标题】:Item control to delete itself from container control从容器控件中删除自身的项控件
【发布时间】:2011-03-29 12:46:54
【问题描述】:

有一个容器控件,一个 TScrollBox,它是多个项目控件的父级。

每个项目控件,本身是复合的,包含(父母和拥有)一个删除按钮。按下按钮会启动项目控件的删除。

删除涉及释放组件,因此实际操作应该与项目无关。问题是,最好的方法是什么?

我实际上知道几个选项:

  • 具有小间隔的计时器(通过单击按钮启动);
  • 一个隐藏的外部按钮(鼠标向下和向上消息发布到该按钮);
  • 表单的自定义消息处理程序。

虽然我可以自信地实施这些方法中的任何一种,但我自以为是,但我不确定哪种方法最好。此外,计时器选项看起来很幼稚,隐藏按钮有点骇人听闻,自定义消息有点矫枉过正。简而言之,这三个似乎都差不多,或多或少。

我可能只是有偏见,不介意被说服相反。最重要的是,我想知道在这种情况下常用的方法是什么(也许我一直都在想念什么)。

【问题讨论】:

  • 我知道我可能在这里遗漏了一些东西。如果项目包含控件,它自己的析构函数不会摆脱它的子组件吗?如果这是真的,为什么不直接删除该项目并释放它?
  • 与我删除答案的原因相同:Andriy 提到的删除按钮是要删除的控件的一部分,它将实现自己对删除按钮单击的处理。因此,您将通过控件自己的事件处理程序之一来执行此操作,并且通常控件真的不喜欢将地毯(世界)从其下方拉出...
  • @Marjan 要求控件释放它自己有问题吗?
  • @Najem:本身不是。实例可以释放自己。但这应该是他们做的最后一件事,所有对他们的引用都应该在他们做之前被清除。大多数情况下,一个实例不知道谁/什么持有对它的引用,这意味着它可能会被要求删除自己两次或更多次。在大卫的回答中使用异步消息意味着破坏被推迟(防止 AV),一旦控制被释放,任何进一步的消息(包括“删除你自己”)都将/应该在句柄消失时被忽略。 (关于它@David?)
  • @Najem:刚刚发现了你的问题。梅森比我解释得更好......

标签: delphi controls containers items


【解决方案1】:

通常的方法是向要释放的控件发布消息。例如,看看TForm.Release 是如何实现的。事实上,我认为你没有理由甚至不能重复使用 CM_RELEASE 消息。

关于发布消息的要点是,它位于队列的后面,只有在任何同步消息(即由SendMessage 传递的消息)完成处理后才会被处理。这样可以避免在对象被释放后调用该对象的方法,这显然是一个您很清楚的错误。

【讨论】:

  • 我刚刚使用它修复了一些代码中的一个讨厌的错误。它有一种可怕的气味,无论如何比为了处理字符串网格中的就地编辑或类似的东西而临时创建的 TEdit 更复杂。
  • 不确定您所说的 re-using 是什么意思(从 TWinControl 开始,TCustomForm 是唯一使用 CM_RELEASE 的类,而我的容器是 TScrollBox;也许这对于Delphi 版本高于 6),但这个想法本身更接近我最初想象的样子,谢谢。是的,我已经被误用的 SendMessage 咬了。
  • 我的意思是 CM_RELEASE 是一条私有的 VCL 消息。但是由于它没有被您的类继承的任何东西使用,我认为您没有理由不能将 CM_RELEASE 发布到要销毁的控件,然后通过调用 Free 来响应它的到来。
  • 结果非常简单。谢谢!
  • 我遇到了类似的问题:我在一行控件上有一个按钮,可以删除该行,也就是说,它会删除该行上的所有控件,包括它自己。我删除按钮,就像行上的所有控件一样,通过在按钮的 OnClick 事件的调用堆栈中调用每个控件的 Free 方法。这会产生访问冲突错误,因为我假设按钮的 OnClick 处理程序在 btnDeleteRow.Free 执行时仍然处于活动状态。调用 btnDeleteRow.Perform(CM_RELEASE, 0, 0) 不会导致 AV 错误,但 Button 不会像调用 btnDeleteRow.Free 时那样消失。
【解决方案2】:

首先,我建议您编写一个继承自 TScrollBox 的自定义控件,并提供子控件实例化和删除作为该滚动框内的一项功能,而不是在你的表格。这段代码将放在它自己的单元中,只有它的公共元素在外面是可见的。这只是面向对象的基础知识。

其次,如果您要从滚动框中移除(删除)控件,则 Timer 只是混乱的根源。如果您还对放入该容器的每个控件进行了子类化,那么您可以使用 TForm.Release 使用的机制(它向它们发送 CM_RELEASE 消息),并以控制在发送此消息时删除自身的方式实现 CM_RELEASE ,但是我觉得这很难看,除非编辑控件在失去焦点时被破坏。

我会直接删除这些方法,而不求助于计时器,方法是继承 TscrollBox 类和我想要放入其中的任何其他类,然后由父对象处理控件的删除( TScrollBox),而不是通过任何形式的外部操作。

【讨论】:

  • 我不会说它丑陋,但让我看到 TCustomForm 可以通过在自己的方法中简单地声明Free; 来拍摄自己是一些启示。但是,消息处理程序可能是允许的特殊情况。感谢有关父控件删除自己的项目的想法。目前它需要比必要的更多的努力,但我也考虑过这个想法,你的解释帮助我更好地理解事情。
  • 消息处理程序是它不能调用 Free 的地方。因此需要释放。当它对自身调用 Free 并返回时,不会再次访问该对象。
  • @David:对不起,但我认为 TCustomForm 确实在 CM_RELEASE 消息处理程序中调用了 Free。 Release 实际上发布消息,作为响应最终调用 Free 方法(在消息处理程序中)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
相关资源
最近更新 更多