◆在結束當前行時需要計算文檔元素在當前行中的相對位置,若當前行是由於情況1而導致結束的則需要修正元素間距,由於文檔行所有元素的寬度和不一定等於容器的顯示寬度,因此若沒有進行修正則文檔的右邊緣參差不齊,影響美觀,因此需要計算元素寬度和和容器的顯示寬度之差,將該寬度差比較均勻的插入到各個文檔元素之間,這樣文檔的右邊緣則比較整齊。為了保存這個修正值,在TextElement中新增一個WidthFix屬性來保存該值。其實大家可以觀察到IE顯示文檔內容時沒有進行右邊緣的修正而Word則進行了類似的修正
◆若當前行是由於最後一個元素強制分行而結束的則無需進行由於情況1而導致的右邊緣修正,但計算文檔元素位置時需要進行文檔對齊方式的修正。首先找到影響當前文本行的段落對象,獲得它的對齊方式設置(左對齊,右對齊,居中對齊),根據對齊方式來計算元素見的空白,然後設置元素的WidthFix屬性
◆此外還需要修正元素在文檔行中的頂端坐標,由於同一行的文檔元素高度不一定一致,此時需要遍歷所有的元素,以最高的元素的高度為文檔行的高度,以此計算元素在文檔行中的頂端位置,以保證各個元素的低邊緣在同一水平線上
◆結束完畢的行對象添加到容器的Lines文檔行集合中,然後創建創建一個文檔行對象作為當前行,如此循環直到處理了容器對象所有的內容
◆產生了所有的文檔行對象後根據容器對象的在視圖區域中的坐標和文檔行的行間距設置來計算文檔行在視圖區域中的坐標,這樣文檔行中所有的元素的在視圖區域中的坐標就是文檔行的坐標和元素在文檔行中的相對坐標的和
◆在修改文檔行中元素的位置時,需要獲得元素舊的在視圖區域中的最小外切矩形數據,然後和重新計算過的最小外切矩形進行比較,若兩者不一樣則表示元素在視圖區域中顯示的位置發生改變,將這兩個矩形添加到文本編輯器重繪矩形集合中,當文檔重新分行完畢後,文本編輯器就將所有的重繪矩形進行加法操作,獲得的矩形就是需要重新繪制的區域。如此這樣是為了優化顯示操作,減少頁面閃爍;因為用戶修改了文檔內容後到而導致的分行只是影響顯示區域中一部分,而其他部分雖然重新計算了位置但新舊位置沒有差別,因此不需要重新繪制。
其實關於分行操作應當還有更優化的方法,但本人能力有限,只能提出這種方法。試驗證明,在處理小的文檔時程序運行速度還行,但當文檔內容很多,有數萬個字符時,分行速度就很慢,還望高手提供解決之道。
為了表示整個文檔對象,還定義了文檔對象TextDocument ,該對象在文檔對象模型中是個最大的對象,我沒有模仿其他文檔對象的模式將其從TextElement派生過來的,而是直接定義的。該對象用於從整體上操作文檔,並列出了一些操作文檔的基本操作,比如刪除,復制粘貼等。此外還提供一套方法來實現VBA的功能。
此外還定義了文檔內容管理對象Content ,該對象隸屬於TextDocument對象,用於管理所有的文檔元素,它定義了屬性Elements,該屬性為一個保存了文檔所有元素對象的列表。該對象還定義了屬性SelectStart來表示插入點的位置,SelectLength 來表示選擇區域的長度,為0表示沒有選中任何元素,為正數則表示從插入點向後選中了若干個元素,為負數則表示從插入點向前選中了若干個元素。本對象還定義了一套處理插入點的函數,比如向左向右移動若干個元素,向上向下移動一行。大家都知道,在文本框中可以直接用光標鍵來移動插入點,也可以使用光標鍵時同時按下Shift鍵來移動插入點並選擇文檔內容,用戶也可以用鼠標點擊操作來移動插入點,鼠標點擊的同時按下Shift鍵也能移動插入點選擇文檔內容;為此在Content對象定義了屬性AutoClearSelection,當設置了該屬性則移動插入點時設置SelectLength為0,若沒有設置該屬性則移動插入點時設置SelectLength值,使得新插入點和舊插入點之間的元素被選中,這樣文本編輯器根據用戶是否按下Shift鍵來設置AutoClearSelection屬性就行了。用戶修改了插入點和選擇區域,則文本編輯器需要重新繪制用戶界面,此時需要優化,只重新繪制選擇狀態發生改變的元素。可以證明,當選擇的元素為連續的,則無論如何的修改選擇區域和插入點,最多只有兩片區域中的元素的選擇狀態發生改變。因此只要獲得這兩片區域的起始位置和長度,然後重新繪制這兩個區域中的元素即可。
用戶可以對文檔進行很多種操作,比如移動插入點,選擇元素,設置字符的字體顏色和大小,插入文字和圖片,修改元素的設置,刪除剪切復制粘貼等等,有好幾十種操作,而且這些操作在某個時刻是不可用的,需要進行判斷,若這些操作都在TextDocument中定義相應的接口函數,則TextDocument類代碼太多,過於臃腫,而且每新增一種操作都需要修改TextDocument,因此在此提出動作這個概念。動作就是一個實現某種文檔操作的類型,該類型有統一的接口,並使用TextDocument或其他對象提供的基本的操作來實現比較復雜的操作。為此定義動作基礎類EditorAction,該類為抽象類,它的主要接口有:
◆HotKey 字段,動作對應的熱鍵代碼,動作對象初始化的時候設置該動作對應的熱鍵
◆KeyCode 字段,觸發動作時的鍵盤按鍵編碼
◆ShiftKey 字段,觸發動作時的Shift鍵狀態
◆ControlKey 字段,觸發動作時的Control鍵狀態
◆AltKey 字段,觸發動作時的Alt鍵狀態
◆MouseX,MouseY 字段,觸發動作時的鼠標光標在視圖區域中的坐標
◆MouseButton 字段,觸發動作時的鼠標按鍵狀態
◆Param1,Param2,Param3 字段,動作的參數,其意義由具體的動作決定
◆TestHotKey 函數測試鍵盤熱鍵,本函數由文本編輯器調用來判斷是否觸發某動作
◆ActionName 只讀屬性,動作名稱
◆isEnable 動作是否可用
◆Execute 執行動作