2017-06-22 61 views
1

我有一個winforms應用程序和兩個控件,我在其中進行自定義繪圖。主控件顯示道路的長連續圖像的一小部分,而另一個控件顯示整個道路圖像的水平壓扁表示。第二個控件用於導航第一個控件:您可以單擊概覽中的任意位置以在主視圖中滾動到該位置。這裏的一個屏幕截圖,其中主視圖是在頂部和概述是對底部:爲什麼一個控件會比另一個更頻繁地重繪?

screenshot of both controls

有在概覽控制指示在主視圖中被示出的圖像的位置處的青色線。 (在這個屏幕截圖中,它的寬度僅爲左側的1/3)。用戶可以在概覽中單擊並拖動該行,這將導致主視圖滾動。

我注意到了一些關於重繪的奇怪現象:當我在總覽控件中拖動青色線時,主視圖比概覽更頻繁地重繪,即使兩者都響應鼠標移動而失效。我知道WM_PAINT消息只在隊列中沒有其他消息時才被髮送,但我不明白爲什麼一個控件會比另一個更頻繁地重繪,如果它們同時失效。

其實,當我輸入最後一句話時,我想我偶然發現了原因。告訴我這聽起來是否正確:

每個控件都有自己的消息隊列,並且主控件沒有收到任何與輸入有關的消息,所以它的消息隊列比概覽中的消息隊列更爲頻繁,它必須處理所有的鼠標事件。所以它比概覽更頻繁地收到WM_PAINT消息。

所以在這一點上,我想問題是,「這有道理嗎?這是怎麼回事?」

+0

在整體概覽中,「整個道路圖像的水平壓扁表示」是如何實現的?你在Paint()事件中進行計算,還是迭代一些數據並自定義繪製位置上的線條?我猜測繪製概覽需要比主視圖花費更長的時間。 –

+0

@Idle_Mind,實際上我最近優化了概覽控件的繪製,以便它保持最後一個完整渲染的位圖,並且只是在blot時加上繪製青線。它只在場景實際發生變化時更新位圖,這在滾動期間很少見,而且絕對不會發生。但是,即使它的呈現時間比主視圖要花費更長的時間,但如果它們以相同的頻率發生,效果只會是普遍的遲緩,這不是我所看到的。主要控制是跟上鼠標事件,而概覽不是。 – adv12

回答

3

理論不健全,每個線程只有一個消息隊列。你看到的幾乎肯定是由WM_PAINT的產生方式造成的。僅在隊列爲時爲空。這使得它成爲「低優先級」消息,用戶輸入總是首先。重要的是,它是這樣工作的,你不希望用戶輸入丟失,或者消息隊列爆炸,因爲繪製代碼很慢。

所以,粗略地說,你調用了Invalidate()兩次。最底部的窗口獲取Paint事件,但當它完成時,還有另一個鼠標事件正在等待處理。因此,第二個窗口而不是得到其繪畫事件,並且您將使已失效的窗口失效。只有當你放慢鼠標或停止移動時,它才能趕上。

從任務管理器很容易看到,你會看到你的程序的UI線程燃燒100%的核心。

無論如何強制塗料是可能的,但你必須調用Update()而不是Invalidate()。你的程序仍然燃燒100%的核心,但現在,而不是跳過油漆,它將不太響應鼠標。這聽起來很危險,有可能淹沒消息隊列,但事實並非如此。 WM_MOUSEMOVE也不會被添加到消息隊列中。像WM_PAINT一樣,它只在隊列爲空時生成。你會先得到它。

+0

我想我主要理解這個解釋,但是它是什麼使得它在消息隊列是空的時候獲得WM_PAINT的最高控制權以及因爲事件進入而最終沒有得到它的最低控制權呢?爲什麼它永遠不會相反?平局運氣好嗎?關於它們在控制層次內的相對順序? – adv12

+0

不是「頂級控件」,Windows使用「畫家的算法」和顏色從後到前。其中「後退」是Z次序中最低的一次。當控件不相互重疊時,Z順序並不總是顯而易見的,在View> Other Windows> Document Outline工具窗口中可以看到Z順序。 「帶到前面」和「發回」設計器命令修改它。 –

+0

是的,我的意思是「我的截圖中的頂級控件」。我的意思是,我的主要觀點總是看起來是成功重繪的控件,而我的概覽控件總是似乎是因爲新的鼠標事件進入而無法獲取WM_PAINT的控件。我想你只是說我是如何將他們安排在設計師身上的副產品,如果我重新排列他們,我可能會看到不同的行爲。那是對的嗎?如果是這樣,這聽起來有點不穩定,我可能想切換到使用Update()的建議。 – adv12

相關問題