你熟悉的GUI系統一般怎麼處理局部位置的更新?

我用的比較多的是iOS的UIKit,所以就用它舉例了.

UIKit裡面的視圖基本單元是UIView,UIView其實是用CALayer來負責繪圖這塊,繪製後其實是緩存下一張點陣圖,如果不需要重繪就會利用這個保存的點陣圖,例如有時只是視圖的布局改變,就可以利用一下緩存。如果當前的這個UIView需要重繪,程序員可以調用函數把這個視圖標記一下。但我對它到底怎麼反應到屏幕上不是很清楚。

我猜想可能的解決方法是,系統定期發起一類調用,先重畫所以需要重畫的部分,在這些部分組合起來。也可能是重畫過程中就把布局考慮進來,通過切割一整張畫布來實現局部的更新,因為布局是會影響重畫的結果的(比如子視圖超過父視圖的部分就畫不出來)。

希望大家講解自己熟悉的GUI庫的處理方式,能講講優缺點當然更好了,能講講UIKit就更好了?或者推薦一下設計GUI的經典書籍什麼的!


一般有兩種做法。

第一種是Windows API的,他有dirty rect功能,在當初Windows 3.1那種超爛的硬體上也可以高速繪製窗口。因此他有一個InvalidRect還是啥的API讓你主動告訴他控制項的什麼地方要重畫,然後就給你發一個WM_PAINT,裡面有一個clip過的DC。

第二種是www.gaclib.net 的。因為我需要跟XAML一樣超級豐富的排版功能,所以每當你改了label的文字的時候一層一層的往上通知尺寸變化然後繪製什麼的是不現實的,這會導致你批量修改屬性的時候重繪太多次導致性能急劇下降。然而你要是有類似BeginUpdate和EndUpdate這樣的函數防止控制項臨時繪製的話,這又會導致你每一次修改都要log下來,在EndUpdate的時候重新排版,這樣做起來超級麻煩,而且很容易出bug。

所以www.gaclib.net 採用的方法就是,每次渲染的時候都重新計算每一個控制項的尺寸,控制項是不保存它自己的尺寸的。當然你真的重新計算肯定也慢,所以我在一些比較複雜的排版節點上,譬如說表格之類的東西做了cache。這樣下來,當你的UI上有幾萬個排版對象的時候,都可以在人類無法察覺的時間間隔下在渲染的時候算出所有的尺寸。因此你修改label的文字的時候再也不用通知父控制項因為自己的尺寸變化重新排版了,一切都會等到渲染的時候再說。這樣也大大簡化了屬性設置的時候的工作。你屬性設置,就只是屬性設置,不會做很多額外的事情,譬如說主動刷新什麼的。然後我就有個timer來繪製,就跟遊戲一樣,而且CPU也只是1%或2%這樣的佔用。


沒有出現在可視區域的元素不需要繪製


推薦閱讀:

程序員的核心競爭力是什麼?
为什么至今还没有没有一个图形化的系统,只需要我们写写画画或者点几下鼠标就能实现编程?
考上計算機二級什麼水平,能開發操作系統和桌面應用不?
如何評價王垠這個人?
遊戲中非人形boss碰撞到底是怎麼處理的?

TAG:編程 | 圖形用戶界面 | GDI | UIKit | GUI設計 |