【delphi】TMS_Component_Pack_v9.2.4.0中的TadvMemo 支持中文完美修改
大家知道,在delphi的開發環境中,TMS是赫赫有名的三方控件提供商,基本上沒有不知道或者沒有不使用的。TMS提供的控件包羅萬象,非常豐富。但是有一個控件TadvMemo的一個編輯控件,支持語法(delphi,basic,HTML,javascript,css,SQL,C#等等)高亮,很好用,就是有一個硬結是不支持中文,相信大家在使用的過程中都有體會,我問了TMS,答復是tadvMemo只支持monospace字體。而且這個控件版本已經升級的很高了也沒有支持中文,看來只能自己修改了。于是我們修改了TadvMemo源代碼,使其完美支持中文。
簡單的幾個函數就可以讓TadvMemo 支持中文,修改后的代碼下載。
修改后的TadvMemo支持中文功能測試如下:
| 1 | 輸入中文顯示半個漢字 | 修改后正確顯示 |
| 2 | 光標不能放置到一個漢字的中間 | 修改后正確 |
| 3 | Ctrl + Left(home)光標到行首 | 修改后正確 |
| 4 | Ctrl + Right(end)光標到行尾 | 修改后正確 |
| 5 | 鼠標或者按鍵反選 | 修改后正常 |
| 6 | 反選后拷貝到外邊 | 修改后正常 |
| 7 | 從外邊拷貝進入編輯器 | 修改后正常 |
| 8 | overwrite下輸入中文 | 修改后正常 |
| 9 | 光標上移或者下移不能移動到一個漢字中間 | 修改后正常 |
1. 修改原理
TadvMemo認為字符都是等寬的,等寬的概念是顯示一個字符就只能占用一個顯示位置,對于英文字符是沒有問題的,但是對于中文,就不一樣的,一個中文漢字顯示的時候會占用兩個英文字符的位置,這樣就會產生問題。我們要做的就是把中文字符能夠合理的告知TadvMemo,為此,我們需要書寫如下函數:
1.1 修復需要的函數
一、將光標位置轉換成實際的字符位置。比如字符串:”A偉大123“,當光標位于”大"和“1”之間的時候,光標是5,但是對于字符串”A偉大123“來說,如果我們要獲取光標前的字符串“A偉大”,就不能使用光標位置5,而應該使用長度3,因為一個漢字作為字符串處理(unicode)也是1。
參數說明:
S:是實際字符串
CurX:表示光標位置,光標在行首的時候是0,每向右移動一個英文字符光標加1,移動一個漢字光標加2.
positon:表示轉換后字符串的位置。
結果為 True表示轉換成功,否則表示轉換失敗。
function Get_InsertPositonX_02(S : string; CurX : integer; var position : word) : Boolean; vari : integer;B : TBytes;E_Char_Count : Word;A1 : integer; begin//s := 'A你好12大小3設那個';if S = '' then Exit(True);E_Char_Count := 0;B := TEncoding.ANSI.GetBytes(S);//計算有多少個 英文字符for i:= 0 to CurX - 1 doif B[i] < $80 thenE_Char_Count := E_Char_Count + 1;A1 := CurX - E_Char_Count;A1 := (CurX - E_Char_Count) mod 2;A1 := E_Char_Count + (CurX - E_Char_Count) div 2;Result := ((CurX - E_Char_Count) mod 2) = 0;if Result thenposition := E_Char_Count + (CurX - E_Char_Count) div 2elseposition := E_Char_Count + (CurX - E_Char_Count + 1) div 2;end;二、判斷當前光標前是不是一個漢字, True 表示是漢字,否則是英文字母,光標左移是需要使用此函數。
參數說明:
S:是實際字符串
CurX:表示光標位置,
三、判斷當前光標后是不是一個漢字, True 表示是漢字,否則是英文字母,光標右移的時候需要使用該函數
參數說明:
S:是實際字符串
CurX:表示光標位置
四、判斷光標是否在一個完整漢字的中間,正常編輯是不應該出現這個問題的。
參數說明:
S:需要判斷的字符串
CurX:表示光標位置
返回結果True 表示是在一個漢字中間,否則不是
function is_Half_Chinense(S : string; CurX : integer) : Boolean; vari : integer;B : TBytes;o : integer; //記錄半個函數數量 beginB := TEncoding.ANSI.GetBytes(S);if CurX > Length(B) then Exit(False);if CurX = 0 then Exit(False);//光標前或者后是一個英文字符,則直接表示不再半個漢字中間if (B[CurX - 1] < $80) or (B[CurX] < $80) then Exit(False);o := 0;for i := CurX - 1 downto 0 dobeginif B[i] < $80 thenbeginif (o mod 2) = 0 thenExit(False)elseExit(True);end;o := o + 1;end;if (o mod 2) = 0 thenExit(False)elseExit(True); end;2. 需要修改的地方舉例
一、使用 TEncoding.ANSI.GetBytes 直接調整光標位置。
例如,當需要把光標移動到行尾,也就是按下Ctrl + Right(end)鍵的時候,需要修改函數中的CurX:
修改前函數:
procedure TAdvCustomMemo.GotoEnd; beginCurY := Lines.Count - 1;CurX := Length(Lines[Lines.Count - 1]); end;修改后函數:按照漢字字節數調整了光標的位置。
procedure TAdvCustomMemo.GotoEnd; beginCurY := Lines.Count - 1;//SZHN 20210113//CurX := Length(Lines[Lines.Count - 1]);CurX := Length(TEncoding.ANSI.GetBytes(Lines[Lines.Count - 1])); end;二、使用我們的函數調整,例如反選后需要拷貝到剪貼板,此時需要修改函數:TAdvCustomMemo.CopyToClipBoard;
修改前函數代碼:
procedure TAdvCustomMemo.CopyToClipBoard; varMemHandleRTF: THandle;MemHandleHTML: THandle;rtfstr, htmlstr: AnsiString;sl,el: string;ChangeEvt: TNotifyEvent; beginFRTFEngine := TRTFEngine.Create;ChangeEvt := OnChange;OnChange := nil;sl := InternalLines[SelStartY];el := InternalLines[SelEndY];if (SelStartY < SelEndY) thenbeginInternalLines[SelStartY] := Copy(sl, SelStartX, Length(sl));InternalLines[SelEndY] := Copy(el, 1, SelEndX);endelsebeginInternalLines[SelStartY] := Copy(sl, 1, SelStartX);InternalLines[SelEndY] := Copy(el, SelEndX, Length(el));end;下面還有,不需要修改就不貼出來....修改后代碼:注意使用了 Get_InsertPositonX_02 函數
procedure TAdvCustomMemo.CopyToClipBoard; varMemHandleRTF: THandle;MemHandleHTML: THandle;rtfstr, htmlstr: AnsiString;sl,el: string;ChangeEvt: TNotifyEvent;//LXY 20210112positionStart,positionEnd:word; beginFRTFEngine := TRTFEngine.Create;ChangeEvt := OnChange;OnChange := nil;sl := InternalLines[SelStartY];el := InternalLines[SelEndY];//LXY 20210113 重新定位位置{if (SelStartY < SelEndY) thenbeginInternalLines[SelStartY] := Copy(sl, SelStartX, Length(sl));InternalLines[SelEndY] := Copy(el, 1, SelEndX);endelsebeginInternalLines[SelStartY] := Copy(sl, 1, SelStartX);InternalLines[SelEndY] := Copy(el, SelEndX, Length(el));end;}if (SelStartY < SelEndY) thenbeginGet_InsertPositonX_02(sl,SelStartX,positionStart);Get_InsertPositonX_02(el,SelEndX,positionEnd);InternalLines[SelStartY] := Copy(sl, positionStart+1, Length(sl));InternalLines[SelEndY] := Copy(el, 1, positionEnd);endelsebeginGet_InsertPositonX_02(sl,SelStartX,positionStart);Get_InsertPositonX_02(el,SelEndX,positionEnd);InternalLines[SelStartY] := Copy(sl, 1, positionStart);InternalLines[SelEndY] := Copy(el, positionEnd, Length(el));end;//=================================================================>類似需要修改的地方大概有上百處,這里不詳細列舉,需要的朋友可以下載。資源下載
總結
以上是生活随笔為你收集整理的【delphi】TMS_Component_Pack_v9.2.4.0中的TadvMemo 支持中文完美修改的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: li标签中hover的使用及li标签的样
- 下一篇: 安装U8后服务器开机加载信息慢,用友U8