如何避免 Swing 中的无限更新循环?
我有一个包含一组项目(例如组合框和文本字段)的 JPanel。在这些项目上实现一些操作侦听器来注册用户更新。
例如,如果用户在 JComboBox 中选择一个值,则操作侦听器将捕获该事件。调用相应的底层 bean 方法并刷新面板。更改可能会影响窗格中显示的其他字段。
问题是,当刷新面板时,所有侦听器都会被触发,并且它们会自己调用刷新。这会导致无限循环。
我怎样才能避免这种情况?我无法摆脱侦听器,因为我需要捕获用户更新,但我不希望在我仅刷新面板内容时触发这些侦听器。
I have a JPanel with a set of items (for example combo boxes and text fields). Some action listeners are implemented on those items to register user updates.
If the user selects a value in a JComboBox (for example), the action listener captures the event. The corresponding underlying bean method is called and the panel is refreshed. Changing can have an impact on other fields displayed in the pane.
The problem is that when the panel is refreshed, all listeners are triggered, and they call for a refresh themselves. This leads to an infinite loop.
How can I avoid this? I can't get rid of the listeners, because I need to capture user updates, but I don't want these to fire when I am only refreshing the panel content.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一种选择是拥有一个中央布尔值或某个指示器,每个侦听器都可以检查它们以防止事件链接。
另一种选择是,如果值未更改,则不刷新字段。这样每个组件每次刷新最多更新一次。
One option is to have a central boolean value or some indicator that each listener can check to prevent the chaining of events.
Another option is to not refresh the field if the value does not change. That way each component is updated at most once per refresh.
然后删除侦听器,刷新窗格内容,然后恢复侦听器。这样,侦听器仅在用户发生更改时触发。
Then remove the listeners, refresh the pane content and then restore the listeners. This way the listeners only fire when a user change is made.
我认为如果您的问题出在组合框中,那么它只是指出了一个错误。实际上,如果用户更改组合框的值,会以某种方式触发窗格的刷新,则不应再次更改组合框的值!因此,如果它是 onValueChanged() (或类似的东西),则在刷新窗格时根本不应该调用它。
但如果由于某种原因发生这种情况,您可以验证旧值和新值是否相同并退出侦听器。
如果这仍然没有帮助,我建议您使用一些非标准解决方案:尝试调查侦听器的堆栈跟踪。您能否确定侦听器是作为对用户操作的直接反应而调用还是在窗格刷新之后调用?在这种情况下,您可以创建实用方法并将其放在所有相关侦听器的开头。
I think that if your problem is in combobox it just points to a bug. Really, if user changes the value of the combobox, that somehow triggers refresh of the pane the value of the combo box should not be changed second time! So if it is onValueChanged() (or something like this) it should not be called at all when pane is being refreshed.
But if for some reason it happens you can verify whether the old and new values are the same and exit the listener.
If this still does not help I'd suggest you some non-standard solution: try to investigate the stack trace into the listener. Can you identify whether the listener was called as a direct reaction to user's action or after the pane refresh? In this case you can create utility method and put it in the beginning of all relevant listeners.
我的应用程序也遇到了这个问题,并且带有标志的解决方案(我应该检查每个侦听器并在代码中启用/禁用)对我来说感觉不太好。我总是忘记在必要的地方将此标志设置为 true/false。
这就是为什么我决定实施另一个解决方案。
我只是对我经常使用的所有默认 swing 组件进行子类化,并实现了在鼠标/键盘/剪贴板/等事件之后触发的自定义 ValueChanged 事件。现在我总是知道,如果 ValueChanged 事件被触发,则意味着该值是由用户发出的,而不是由代码发出的。这种方式的事件处理更加干净。这个解决方案解决了我的问题。
My applications also suffered from this problem, and solution with the flag, that I should check in every listener and enable/disable in code, feels not very good for me. I always forgot to set this flag to true/false in necessary places.
That is why I decide to implement another solution.
I just subclass all default swing components that I am using often, and implemented custom ValueChanged event that I fire after mouse/keyboard/clipboard/etc events. Now I am always know, that if ValueChanged event is fired, it means, that value was issued by user, not by code. Event handling in this way much more cleaner. This solution solves my problem.