6

我正在使用基于 Swing 的应用程序中的组合框,我很难弄清楚如何区分从用户事件生成的 ItemEvent 与由应用程序引起的 ItemEvent。

例如,假设我有一个组合框“ combo”,并且我正在使用我的 ItemListener“ listener”监听 itemStateChanged 事件。当用户将选择更改为第 2 项或我执行该行(伪代码)时:

combo.setSelection(2)

..似乎我无法区分这些事件。

也就是说,无论如何我都不是 Swing 专家,所以我想我会问。

谢谢!

4

5 回答 5

3

无论用户选择 Item 2,还是 API 调用 setSelection(2),事件都会出现相同的

您的问题的解决方案可能是重新考虑您希望 itemStateChanged 代码在选择更改时执行的操作。为什么您的应用程序在每种情况下的工作方式都不同?也许您可以利用一些相似之处来发挥自己的优势。

使用标志时要小心。itemStateChanged 事件将在事件调度线程上发生,该线程与您设置标志状态的线程不同。这意味着使用标志可能不是 100% 可靠的。

于 2008-10-06T21:33:56.903 回答
2

作用和反应定律很清楚:)。如果您尝试对更改做出反应,则无需区分用户和应用程序。我可以想象只有一个用例需要“区分”。应用程序显示某些数据的情况。在这种情况下,您可能拥有应用程序的数据模型。此模型中还有一些更改侦听器,应用程序 GUI 将通过为组件设置值来做出反应。并且。如果用户在 GUI 组件中选择任何内容。数据模型将通过改变值做出反应。在这种情况下,很容易在数据模型上设置某种只读状态,这将通知模型忽略来自观察对象的任何事件。此通知集应在 EDT 中运行,并且标记没有问题。小例子:

class ApplicationDataModel {

    private Flag current = Flag.RW;

    public void setData(ApplicationData data) {
        current = Flag.RO;
        setDataImpl(data);
        notifyObservers();
        current = Flag.RW;
    }

    public void reaction(Event e) {
        if (flag = Flag.RO) return;
        ...
    }

}

小心标记,不要忘记线程。如果你从另一个线程调用 setData ,那么 EDT 你会遇到麻烦。当然。对象的提取ApplicationData必须在不同的线程中运行;)。一般来说,重新考虑您的应用程序的设计。

于 2008-10-07T08:40:29.540 回答
1

您可以在设置选择之前在代码中设置一个标志,然后在侦听器中检查此标志(如果已设置,请取消设置该标志)...

自 Java 6 以来可能有更好的方法,但这是我一直使用的方法......

[编辑]:正如大卫指出的那样,您需要使用 SwingUtilities.invokeLater 或类似方法在 EDT 中设置标志(并更新组合)(无论如何您都应该这样做,因为您正在更改 UI 控件)

于 2008-10-06T21:11:11.380 回答
0

如果您需要区分事件,那么您的设计可能需要重新考虑。MVC 的重点是将模型的更改与用户的实际鼠标点击解耦。

也许您应该根据为什么要区分这两种情况来重申这个问题。然后,我们可以就实现目标的不同方式提供一些指导。

于 2008-10-07T03:23:25.030 回答
0

所以我猜你希望用户选择执行一些操作,而不仅仅是简单的旧的直接状态更改。这是由有限的灵活性引起的问题(灵活性总是会受到限制,特别是如果您在其他方向上具有灵活性)。

我的建议:

首先,总是直接在 Swing 中使用模型。小部件非常复杂,您希望将不同的关注点分开。幸运的是 Swing 已经有了它的模型。

一种常见的模式是在模型之间进行委托。因此,在这种情况下,您拥有保存数据的“真实”默认模型。在 JComboBox 和真正的 ComboBoxModel 之间插入,并委托 ComboBoxModel 对状态更改指令执行操作。您的应用程序代码应该忽略 JComboBox 并绕过委托模型直接使用真正的 ComboBoxModel。所以在图表中:

用户 -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- 应用程序代码
于 2008-10-07T13:58:41.113 回答