17

在编写 GUI 时,我经常遇到以下问题:假设您有一个模型和一个控制器。控制器有一个小部件W,用于显示X模型的属性。

因为模型可能会从控制器外部更改(可能有其他控制器使用相同的模型、撤消操作等),所以控制器会监听模型的更改。控制器还监听小部件上的事件W并相应地更新属性X

现在,会发生以下情况:

  1. 中的值W已更改
  2. 生成事件,调用控制器中的处理程序
  3. 控制器X模型中设置新值
  4. 模型发出事件,因为它已被更改
  5. 控制器模型接收更改事件
  6. 控制器获取的值X并将其设置在小部件中
  7. 转到 1。

有几种可能的解决方案:

  1. 修改控制器以在模型更新时设置一个标志,如果设置了此标志,则不对来自模型的任何事件做出反应。
  2. 暂时断开控制器(或告诉模型一段时间不要发送任何事件)
  3. 冻结小部件中的任何更新

过去,我通常选择选项 1,因为这是最简单的事情。它的缺点是用标志使你的类变得混乱,但其他方法也有它们的缺点。

只是为了记录,我在几个 GUI 工具包中遇到了这个问题,包括 GTK+、Qt 和 SWT,所以我认为它与工具包无关。

有什么最佳实践吗?还是我使用的架构完全错误?

X@Shy:这是某些情况下的解决方案,但是如果从控制器外部更改(例如,使用命令模式进行撤消/重做时),您仍然会得到一轮多余的事件,因为值已经改变,W被更新并触发一个事件。为了防止对模型进行另一次(无用的)更新,必须吞下小部件生成的事件。
在其他情况下,模型可能更复杂,简单检查究竟发生了什么变化可能不可行,例如复杂的树视图。

4

3 回答 3

5

处理此问题的标准 QT 方法以及他们非常有用的教程中建议的方法是,仅当新值与当前值不同时才更改控制器中的值。
这是信号具有语义的方式valueChanged()

看这个教程

于 2008-09-24T00:29:55.100 回答
3

通常您应该响应小部件中的输入事件而不是更改事件。这可以防止发生这种类型的循环。

  1. 用户更改小部件中的输入
  2. 小部件发出更改事件(滚动完成/单击输入/鼠标离开等)
  3. 控制器响应,转换为模型中的更改
  4. 模型发出事件
  5. 控制器响应,更改小部件中的值
  6. 发出值更改事件,但控制器未监听
于 2008-09-24T00:45:03.800 回答
1

指示更新工作的标志。您可以将它们包装在 BeginUpdate 和 EndUpdate 等方法中。

于 2008-09-24T00:36:38.233 回答