对于那些没有遇到这个问题的人来说,这个问题似乎很明显。
我需要处理 VTV(虚拟树视图)中的选择更改。我有一个节点的平面列表。每当:
- 用户点击一个节点;
- 用户 Shift/Ctrl-点击一个节点;
- 用户使用箭头键导航列表;
- 用户通过拖动鼠标创建选择
- 用户通过单击空格或 Ctrl-单击唯一选定的节点删除选择
等等。这是最常见和预期的行为,就像 Windows 资源管理器一样:当您使用鼠标和/或键盘选择文件时,信息面板会显示它们的属性。我仅需要这些。
但这就是我的难点所在。
以下是我的一些研究结果。
起初我使用 OnChange。它似乎工作得很好,但我注意到一些奇怪的闪烁,并发现在最常见的情况下(选定一个节点,用户单击另一个节点),OnChange 会触发两次:
- 旧节点被取消选择时。此时选择为空。我刷新 GUI 来显示“没有选择”标签代替所有属性。
- 新节点被选中时。我再次刷新 GUI 以显示新节点的属性。因此会出现闪烁。
这个问题可以在谷歌上搜索到,所以我发现人们使用 OnFocusChange 和 OnFocusChanging 来代替 OnChange。但是这种方法仅适用于单选。对于多选、拖选和导航键,这种方法不起作用。在某些情况下,焦点事件甚至根本不触发(例如当通过单击空白处移除选择时)。
我进行了一些调试输出研究,以了解这些处理程序在不同场景下的触发方式。我的研究结果没有任何可见的意义或模式。
C OnChange
FC OnFocusChange
FCg OnFocusChanging
- nil parameter
* non-nil parameter
! valid selection
Nodes User action Handlers fired (in order)
selected
0 Click node FCg-* C*!
1 Click same FCg**
1 Click another C- FCg** C*! FC*
1 Ctlr + Click same FCg** C*!
1 Ctrl + Click another FCg** C*! FC*
1 Shift + Click same FCg** C*!
1 Shift + Click another FCg** C-! FC*
N Click focused selected C-! FCg**
N Click unfocused selected C-! FCg** FC*
N Click unselected C- FCg** C*! FC*
N Ctrl + Click unselected FCg** C*! FC*
N Ctrl + Click focused FCg** C*!
N Shift + Click unselected FCg** C-! FC*
N Shift + Click focused FCg** C-!
1 Arrow FCg** FC* C- C*!
1 Shift + Arrow FCg** FC* C*!
N Arrow FCg** FC* C- C*!
N Shift + Arrow (less) C*! FCg** FC*
N Shift + Arrow (more) FCg** FC* C*!
Any Ctrl/Shift + Drag (more) C*! C-!
0 Click empty -
1/N Click Empty C-!
N Ctrl/Shift + Drag (less) C-!
1 Ctrl/Shift + Drag (less) C-!
0 Arrow FCg** FC* C*!
这篇文章有些难以理解。简单来说,根据具体的用户操作,三个处理程序(OnChange、OnFocusChange和OnFocusChanging)将以随机顺序调用,带有随机参数。在我还需要事件处理的时候,有时FC和FCg根本不会被调用,因此显然我必须使用OnChange。
但下一个任务是:在OnChange中,我无法知道是否应该使用此调用或等待下一个调用。有时所选节点集是中间状态且无用,对其进行处理会导致GUI闪烁和/或不必要的重计算。
我只需要表格中标有“!”的调用。但无法从内部区分它们。例如:如果我在“C-”(OnChange,Node = nil,SelectedCount = 0)中,它可能意味着用户已取消选择(然后我需要处理它),也可能意味着他们单击了另一个节点(然后我需要等待下一个OnChange调用以形成新的选择)。
总之,我希望我的研究是不必要的。我希望我错过了某些能使解决方案简单明了的东西,你们可以指出来给我。根据我目前了解的内容解决这个难题会产生一些极其不可靠和复杂的逻辑。
提前感谢!