在GUI中打破事件周期

时间:2008-09-24 00:25:42

标签: user-interface events

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

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

现在,发生以下情况:

  1. W中的值已更改
  2. 生成一个事件,调用控制器中的处理程序
  3. 控制器模型中设置X的新值
  4. 模型会发生事件,因为它已被更改
  5. 控制器模型
  6. 收到更改事件
  7. 控制器获取X的值并将其设置在小部件中
  8. 转到1。
  9. 有几种可能的解决方案:

    1. 修改控制器以在模型更新时设置标志,如果设置了此标志,则不对模型中的任何事件做出反应。
    2. 暂时断开控制器(或告诉模型一段时间不发送任何事件)
    3. 冻结小部件的所有更新
    4. 在过去,我通常会选择选项1.因为这是最简单的事情。它的缺点是用标志混乱你的类,但其他方法也有它们的缺点。

      仅仅是为了记录,我已经遇到了几个GUI工具包的问题,​​包括GTK +,Qt和SWT,所以我认为这是非常适合工具包的。

      任何最佳做法?或者我使用的架构是错误的?

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

3 个答案:

答案 0 :(得分:5)

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

语义的方式

see this tutorial

答案 1 :(得分:3)

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

  1. 用户更改小部件中的输入
  2. Widget发出更改事件(滚动完成/输入点击/鼠标离开等)
  3. 控制器响应,转换为模型中的更改
  4. 模型发出事件
  5. 控制器响应,更改小部件中的值
  6. 发出了值更改事件,但未被控制器监听

答案 2 :(得分:1)

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