如何避免 Swing 中的无限更新循环?

Posted

技术标签:

【中文标题】如何避免 Swing 中的无限更新循环?【英文标题】:How to avoid infinite update loops in Swing? 【发布时间】:2011-09-19 16:01:25 【问题描述】:

我有一个带有一组项目(例如组合框和文本字段)的 JPanel。在这些项目上实现了一些动作侦听器来注册用户更新。

如果用户在 JComboBox 中选择了一个值(例如),则操作侦听器会捕获该事件。调用相应的底层 bean 方法并刷新面板。更改可能会影响窗格中显示的其他字段。

问题是,当面板刷新时,所有的监听器都被触发了,他们自己调用刷新。这会导致无限循环。

我怎样才能避免这种情况?我无法摆脱监听器,因为我需要捕获用户更新,但我不希望它们在我只刷新面板内容时触发。

【问题讨论】:

请将 JPane 修改为 JPanel,对于从 JComboBox 到 GUI 的任何输出,最好查找 ItemListener 并注意仅测试特定事件,您是否能够侦听 JComboBox 的弹出窗口,请检查这个论坛是一些很好的话题 【参考方案1】:

一个选项是有一个中心布尔值或一些指标,每个侦听器都可以检查以防止事件链接。

另一个选项是如果值没有更改,则不刷新字段。这样每个组件每次刷新最多更新一次。

【讨论】:

我也刚刚想到了第二个选项。我目前正在实施和测试它....【参考方案2】:

我无法摆脱侦听器,因为我需要捕获用户更新,但我不希望仅在刷新窗格内容时触发它们

然后移除监听器,刷新窗格内容,然后恢复监听器。这样,侦听器仅在用户更改时触发。

【讨论】:

您建议的解决方案意味着我可能会错过一些用户操作/更新。这对我的申请是不可接受的。比较旧值/新值解决方案正确地涵盖了这种情况。 @JVerstry,您不会错过任何用户操作/更新。所有代码都在 EDT 上执行,因此在处理任何用户更新之前将添加回侦听器。 未注册的 EDT 不会调用监听器。您无法预测事件的调用顺序,因为您不知道用户何时创建事件。它可能在自己生成事件的字段更新之间......用户事件将在两者之间被调度(没有监听器)...... @JVerstry,要么您不了解事件的工作原理,要么不了解如何实施此建议。每当提出此类问题时,您都会找到两个标准答案。删除/添加侦听器方法和布尔方法。我更喜欢这个解决方案,因为我相信它更干净,因为所有代码都位于一个地方。使用布尔方法,您可以将代码分成三个位置,一个用于定义变量,另一个用于设置布尔值,最后另一个用于检查布尔值。我相信任何分散在多个地方的代码都更难维护。【参考方案3】:

我认为,如果您的问题出在组合框中,它只是指向一个错误。确实,如果用户更改了组合框的值,就会以某种方式触发窗格的刷新,那么不应再次更改组合框的值!因此,如果它是 onValueChanged() (或类似的东西),则在刷新窗格时根本不应该调用它。

但如果由于某种原因发生这种情况,您可以验证旧值和新值是否相同并退出侦听器。

如果这仍然没有帮助,我建议您使用一些非标准的解决方案:尝试将堆栈跟踪调查到侦听器中。您能否确定侦听器是作为对用户操作的直接反应还是在窗格刷新后被调用的?在这种情况下,您可以创建实用方法并将其放在所有相关侦听器的开头。

【讨论】:

我也想检查旧值和新值。我目前正在实施和测试...【参考方案4】:

我的应用程序也遇到了这个问题,并且带有标志的解决方案,即我应该检查每个侦听器并在代码中启用/禁用,对我来说感觉不是很好。我总是忘记在必要的地方将此标志设置为真/假。 这就是为什么我决定实施另一个解决方案。 我只是对我经常使用的所有默认摆动组件进行子类化,并实现了在鼠标/键盘/剪贴板/等事件之后触发的自定义 ValueChanged 事件。现在我总是知道,如果 ValueChanged 事件被触发,这意味着该值是由用户发出的,而不是由代码发出的。这种方式的事件处理更加简洁。这个解决方案解决了我的问题。

【讨论】:

以上是关于如何避免 Swing 中的无限更新循环?的主要内容,如果未能解决你的问题,请参考以下文章

避免在反应组件中无限重新渲染

componentDidUpdate 创建无限循环,不知道如何避免它

如何避免“React Hook useEffect 缺少依赖项”和无限循环

避免在指向网站中的错误页面时出现无限循环

如何通过使用 git 提交号作为 xcode 内部版本号来避免无限循环

避免无限循环 Spring Boot