對於那些自己沒有遇到問題的人來說,這個問題顯而易見。VirtualTreeView:正確處理選擇變化
我需要處理VTV中的選擇更改。我有一個平坦的節點列表。我需要做所有當前選擇的節點的東西,只要
- 用戶單擊一個節點;
- 用戶按住/ Ctrl鍵單擊一個節點;
- 用戶使用箭頭鍵導航列表;
- 用戶通過點擊空白處或Ctrl單擊僅選擇的節點
等,這是最常見的和預期的行爲,就像Windows資源管理器中拖動鼠標
我的一些研究如下。
起初我使用OnChange。它似乎運作良好,但我注意到一些奇怪的閃爍,我發現,最常見的場景(一個節點被選擇,用戶點擊另一個)的OnChange觸發兩次:
- 當舊的節點被取消。這時候的選擇是空的。我刷新我的GUI以顯示「沒有選擇任何東西」標籤來代替所有的屬性。
- 選擇新節點時。我再次刷新我的GUI以顯示新節點的屬性。因此閃爍。
這個問題是googleable,所以我發現人們使用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調用)。
無論如何,我希望我的研究是不必要的。我希望我錯過了一些能夠使解決方案簡單明瞭的事情,並且你們會爲我指出問題。使用我迄今爲止所解決的這個難題會產生一些非常不可靠和複雜的邏輯。
在此先感謝!
謝謝,@TOndrej! 我從未注意過此屬性。說實話,我不希望這樣的事情存在。但這似乎是解決我的問題的「官方」方式。 我試了一下,它的工作原理,但感覺有點尷尬......解決定時器這樣的問題對我來說似乎是一個非常糟糕的主意。但如果一段時間沒有更好的解決方案出現,我將不得不堅持這一點。 – 13x666
@13x666如果你考慮一下,避免在這種情況下閃爍意味着屏幕更新,如果他們一個接一個「太快」......相反,推遲,直到事情(用戶輸入)「冷靜下來」。 –
+1。 @ 13x666,一個計時器實際上是一個非常輕的解決方案,等待用戶輸入「冷靜下來」,正如TOndrej所說的那樣。它本質上只是對SetTimer API的調用。我已經多次明確地將定時器用於此目的,並取得了很大的成功。用戶不會注意到低於200毫秒的延遲,但用戶會注意到由於不必要地繪製GUI而導致處理後續命令時出現閃爍和延遲。 –