在GUI中打破事件周期

Tor*_*rek 17 events user-interface

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

由于该模型可能会从外部控制器来改变(有可能是使用同一模式的其他控制器,撤消操作等)时,控制器侦听到模型上的变化.控制器还侦听窗口小部件上的事件W并相应地更新属性X.

现在,发生以下情况:

  1. 值in W改变了
  2. 生成一个事件,调用控制器中的处理程序
  3. 控制器设置新值X模型
  4. 模型发出的事件,因为它已经被改变
  5. 所述控制器从接收的变化事件模型
  6. 控制器得到的值X,并将其设置在widget
  7. 转到1.

有几种可能的解决方案:

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

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

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

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

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

sho*_*osh 5

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

看本教程


Red*_*ard 3

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

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