滾動條

 以前做過程序自己處理滾動條,爲屏幕無效區的更新和屏幕的閃爍花了不少功夫,還使用了雙緩衝。近兩天看了一下CScrollView類,發現這些工作都幫你做好了,會省不少事。於是想研究一下它的實現方法,研究結果表明其實就是普通VC書籍上講解的滾動條處理方式,卻讓我對VC無效區的處理和座標轉換有了更深入的認識。

    對於滾動條點擊或拖動以後導致滾動條變量信息的改變就不說了,邏輯很簡單,下面主要來分析點擊或拖動以後的處理。

    比如我們點擊了一下垂直滾動條的向上按鈕,這時,窗口要向下滾動一行,我們現在就是要實現這個功能。滾動窗口有一個特性,就是窗口的大部分區域信息沒有改變,只是位置下移了。系統有一個ScrollWindow函數,專門用於窗口信息的移動,底層實現就是把內存中的數據直接複製到相應位置,而不需要重新繪製,並將滾動後的那塊區域設爲有效區,這樣就減少無效區的範圍。然後,窗口最上面的一行需要更新,這時將其設爲無效區,重新繪製該區域就可以了。

     繪製無效區就出現問題了,因爲我們將窗口移動,如果只是把窗口最上面一行重新繪製,那就會使第二行和第一行的顯示相同,沒有達到繪製緊貼窗口上的一行的目的,該如何處理呢?這就前涉到座標變換的問題。首先要明確,你在DC上進行的任何操作都是針對邏輯座標的,並且是在“窗口”座標上進行的,而具體哪些內容被顯示到屏幕上,取決於“視口”(viewport)座標系。窗口座標和視口座標有一個對應關係,可以看作兩個原點重疊,注意,原點不一定是(0,0)點。對於窗口上的座標值,要轉換爲視口座標值,首先是減去窗口原點值,然後乘以比例因子,然後加上視口原點值得到的。屏幕上顯示窗口的左上角始終是視口的(0,0)點,對於座標轉換的多種模式,請參看相關書籍。

     如果你覆蓋CScrollview的OnPaint函數,並在其中進行繪圖操作,就會發現滾動條不能正常工作。如果不覆蓋,而直接在OnDraw中進行繪圖操作,就會如願以償,原因何在呢?其實CScrollView中的OnPaint函數默認調用了OnDraw函數,並在OnDraw之前有這麼一行代碼:OnPrepareDC(&dc)。這一句是關鍵所在,通過debug跟蹤代碼發現,其中有一行SetViewportOrg起到了關鍵作用。這個函數用來設置視口的原點,通過將視口原點上調,我們就會在同一區域繪製出本來顯示在其之下的內容,這樣就達到了滾動的目的。其實我們也可以通過SetWindowOrg的方法改變窗口原點,要記住和SetViewport的設置恰恰相反。

      通過以上分析,你應該對滾動條的實現邏輯和座標變換比較清楚了吧?

發佈了33 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章