Do đó, một trong những dự án nho nhỏ đầu tiên của chúng ta là thừa kế từ Textbox bình thường để tạo một Textbox, tạm gọi là vnTextbox, hỗ trợ đánh chữ Việt Unicode theo lối VNI hay VIQR.
Trang 1Thừa kế Textbox để đánh chữ Việt Unicode Lập trình dùng thừa kế
Hết rồi giai đoạn bực mình với VB6 thì sự giới hạn về lập trình theo hướng đối tượng (Object Oriented), NET cho phép ta tha hồ thừa kế Do đó, một trong những dự án nho nhỏ đầu tiên của chúng ta là thừa kế từ Textbox bình thường
để tạo một Textbox, tạm gọi là vnTextbox, hỗ trợ đánh chữ Việt Unicode theo lối VNI hay VIQR Dĩ nhiên, ta vẫn tiếp tục giữ các programs bỏ dấu chuyên nghiệp ưng ý của mình như VietKey, UniKey, VPSKey, v.v , nhưng có thể sau nầy sẽ có trường hợp ta cung cấp cho khách hàng một chương trình áp dụng tiếng Việt để
họ dùng cho nhu cầu chuyên môn mà không cần phải dùng thêm một program
bỏ dấu hỗ trợ
Để tạo một Control thừa kế từ Textbox bạn khởi động một Project mới loại Windows Control Library như sau:
Kế đó, khi mở code ra thay thế hai hàng:
Trang 2Public Class UserControl1
Inherits System.Windows.Forms.UserControl
bằng hai hàng sau:
Public Class vnTextbox
Inherits System.Windows.Forms.TextBox
Đánh dấu theo lối VNI
Ðể đánh dấu cho các nguyên âm chữ Việt, trong vnTextbox ta tạm dùng phương pháp VNI Tức là ta đánh nguyên âm trước, kế đó ta đánh một con số từ 1 đến 9
để bỏ dấu
Các con số 1 6 theo sau chữ a chẳng hạn, sẽ cho ta các chữ á à ả ã ạ â; số 7 theo sau chữ u sẽ cho ta ư; số 8 theo sau chữ a sẽ cho ta ă; số 9 theo sau chữ
d sẽ cho ta đ Để bỏ hai dấu thì ta dùng hai con số, thí dụ a36 thì sẽ đuợc hiển
thị thành ẩ, còn u27 thì sẽ cho ừ Ðể đánh các chữ đ và Ð ta dùng d9 và D9
Chắc chắn bạn sẽ thấy program nầy đơn sơ quá, nhưng nó sẽ dễ hiểu, và sau
đó, nếu thích bạn có thể thêm thắt các chức năng
Để bỏ dấu theo lối VIQR thì thay vì các con số 1,2,3,4,5,6,7,8,9 ta dùng ' ` ? ~
^ + (hay *) ( d (hay -) Ðặc biệt control vnTextbox nầy dùng gần như hoàn
toàn look-up table để tính ra các nguyên âm có dấu Trước hết, mỗi khi user đánh một con số từ 1 đến 9, thì program nhìn xem character phía trước cursor
(gọi là LastCh) là chữ gì Kế đó nó tìm đến hàng chữ chứa toàn bộ những
nguyên âm có thể thay thế LastCh, tùy theo con số mà user vừa đánh vào Ở đây kể cả trường hợp user vừa đánh một Backspace
Cái bảng chứa những hàng chữ ấy đuợc chứa trong một array-of-string tên
ChList và nó được initialised trong Constructor Sub New của vnTextbox như
dưới đây:
Private ChList(148) As String ' List of character groups like
"aáàảãạâ-ă"
ChList(0) =
"aáàảãạăắằẳẵặâấầẩẫậeéèẻẽẹêếềểễệiíìỉĩịoóòỏõọôốồổỗộơớờởỡợuúùủũụưứừửữựyýỳỷ ỹỵdđAÁÀẢÃẠĂẮẰẲẴẶÂẤẦẨẪẬEÉÈẺẼẸÊẾỀỂỄỆIÍÌỈĨỊOÓÒỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢUÚÙỦŨỤƯỨỪỬỮỰY ÝỲỶỸỴD"
ChList(1) = "aáàảãạâ-ă"
ChList(2) = "a^àảãạấ-ắ"
ChList(3) = "aá^ảãạầ-ằ"
ChList(4) = "aáà^ãạẩ-ẳ"
ChList(5) = "aáàả^ạẫ-ẵ"
ChList(6) = "aáàảã^ậ-ặ"
ChList(7) = "aắằẳẵặâ-^"
ChList(8) = "ăắằẳẵặấ-ắ"
ChList(9) = "ăắằẳẵặầ-ằ"
ChList(10) = "ăắằẳẵặẩ-ẳ"
Trang 3ChList(11) = "ăắằẳẵặẫ-ẵ"
ChList(12) = "ăắằẳẵặậ-ặ"
ChList(13) = "aấầẩẫậ^-ă"
ChList(14) = "âấầẩẫậấ-ắ"
ChList(15) = "âấầẩẫậầ-ằ"
ChList(16) = "âấầẩẫậẩ-ẳ"
ChList(17) = "âấầẩẫậẫ-ẵ"
ChList(18) = "âấầẩẫậậ-ặ"
ChList(19) = "eéèẻẽẹê"
ChList(20) = "e^èẻẽẹế"
ChList(21) = "eé^ẻẽẹề"
ChList(22) = "eéè^ẽẹể"
ChList(23) = "eéèẻ^ẹễ"
ChList(24) = "eéèẻẽ^ệ"
ChList(25) = "eếềểễệ^"
ChList(26) = "êếềểễệế"
ChList(27) = "êếềểễệề"
ChList(28) = "êếềểễệể"
ChList(29) = "êếềểễệễ"
ChList(30) = "êếềểễệệ"
ChList(0) chứa toàn bộ các nguyên âm Tương ứng với mỗi nguyên âm (LastCh) trong ChList(0) là một hàng chứa tất cả mọi chữ có thể đuợc dùng để thay thế LastCh khi user đánh vào một con số 1 9 hay Backspace
Thí dụ nếu LastCh là à, ta sẽ dùng ChList(3), nó chứa các chữ: aá^ảãạầ-ằ
Kế đó nếu user đánh số 3 ta sẽ thay thế dấu sắc thành dấu hỏi để có chữ ả Còn nếu thay vì đánh số 3, user đánh số 8, thì ta sẽ có chữ ằ, tức là thêm dấu
ă cho chữ à
Nếu user đánh thêm một số 7 thì character tướng ứng với số 7 trong hàng
aá^ảãạầ-ằ là -, hể gặp character - thì ta làm ngơ
Nếu user đánh thêm một số 2 sau chữ à bạn sẽ thấy character tướng ứng với số
2 trong hàng aá^ảãạầ-ằ là ^ Điều nầy nhắc ta biết là user đánh a22, nên ta
sẽ hiển thị a2
Nếu user đánh Backspace, thay vì một con số, ta sẽ dùng nguyên âm nằm ở đầu dòng, tức là chữ a Như thế nếu LastCh là ẩ, thì sau một Backspace ta có ả, sau thêm một Backspace kế tiếp ta sẽ còn lại a
Kỹ thuật Program dùng để thay thế LastCh là select (highlight) LastCh rồi Paste nguyên âm mới
Dưới đây là Listing của Function GetToneCharPos() để trả về một giá trị từ 1
đến 9 tượng trưng cho dấu:
Private Function GetToneCharPos( ByVal KeyChar As Integer) As Integer
Trang 4' If Typing stype is VNI, see if user enters "1" "9" or "d"
' If so return 1 9 and also 9 for "d" Otherwise return -1
'
' If Typing stype is VIQR, return 1 9 for characters '`?~.^+(d Otherwise return -1
' We also allow for * and - to be same as + and d successively.
' i.e u+ or u* and dd or d- are OK.
GetToneCharPos = -1
If mTypingStyle = "VNI" Then
If (KeyChar = 68) Or (KeyChar = 100) Then ' ie "d" for dd or DD
GetToneCharPos = 9
ElseIf (KeyChar >= &H31) And (KeyChar <= &H39) Then
' it's a digit KeyChar of "1" is &H31
GetToneCharPos = KeyChar - &H30
End If
ElseIf mTypingStyle = "VIQR" Then
Console.WriteLine("KeyChar:{0}", KeyChar)
Select Case KeyChar
Case 39 '
GetToneCharPos = 1 ' '
Case 96
GetToneCharPos = 2 ' `
Case 126
GetToneCharPos = 4 ' ~
Case 63
GetToneCharPos = 3 ' ?
Case 46
GetToneCharPos = 5 '
Case 94
GetToneCharPos = 6 ' ^
Case 43, 42 ' + or *
GetToneCharPos = 7
Case 40
GetToneCharPos = 8 ' (
Case 100, 68, 45 ' d D or
GetToneCharPos = 9
End Select
End If
End Function
Trong Control vnTextbox ta không thể để code hỗ trợ đánh dấu chữ Việt trong
Sub vnTextbox_KeyDown hay Sub vnTextbox_KeyUp được vì một khi
KeyDown hay KeyDown Events đã được raised rồi ta không thể bỏ qua Keystroke hay thay đổi trị giá của nó thành 0 như trong VB6 Do đó, ở đây ta Override
Function ProcessKeyMessage Nếu giá trị trả về (Returned value) của hàm
ProcessKeyMessage là True thì ta ngăn cản không cho Keyboard Event xẩy ra
Loại Event có thể xẩy ra sau đó tùy thuộc vào trị số của m.Msg Trong hàm
ProcessKeyMessage, ta chỉ xử lý thông điệp m.Msg = KeyUp (có giá trị 258) Nếu m.Msg là cho KeyDown hay KeyPress thì ta làm ngơ và cho ProcessKeyMessage return False để KeyDown hay KeyPress events xẩy ra như bình thường
Protected Overrides Function ProcessKeyMessage( ByRef m As
System.Windows.Forms.Message) As Boolean
' Get out if this is not a KeyUp message
Trang 5If m.Msg <> 258 Then Return False
Const Delay As Integer = 100
' Obtain the Keystroke character
Dim KeyChar As Integer = m.WParam.ToInt32
' Process a keystroke
Dim Pos, ToneCharPos, Offset As Integer
Dim NewCh As String
If KeyChar = 8 Then ' It's a backspace character
If Me.SelectionStart = 0 Then Return True
' Obtain the position of the line containing all possible modified characters
Pos = GetLastCharMapPos()
' Select the character just on the left of the cursor
Me.SelectionStart -= 1
Me.SelectionLength = 1
If Pos > 0 Then
If LastCh <> ChList(Pos).Substring(0, 1) Then
' Get here if backspace means removing ^ or ', ` etc
' Copy the new (modified) character to clipboard, it's the leftmost
' character on the line
Clipboard.SetDataObject(ChList(Pos).Substring(0, 1))
' Paste it to replace the character on the left
Me.Paste()
ConcatCharacterIfFailed(ChList(Pos).Substring(0, 1))
Else
' get here if it's a genuine backspace
Me.Cut()
End If
Else
' Select the character just on the left of the cursor
Me.Cut()
End If
' Swallow the actual keystroke
Return True
ElseIf KeyChar = 92 Then ' it's a back slash \ which is the Escape character
If Not EscapeFlag Then
EscapeFlag = True ' Set the Escape flag
Return True ' Swallow the actual keystroke
End If
Else
' Map the key entered (i.e: "1" "9", "d", or "'", "`" , "?" ,
"~", ".", "+", "(" )
' to the position 1 9, to be used for selecting the new character from a string like:
' eg: a a' a` a? a~ a a^ - a(
ToneCharPos = GetToneCharPos(KeyChar)
If ToneCharPos > 0 Then
' Get here if a digit in range 1 9 has been entered
' Ignore the digit if Escape Flag is set
If Not EscapeFlag Then
' Obtain the position of the line containing all possible modified characters
Pos = GetLastCharMapPos()
' If Pos = 0 then simply display the character, ie leave
Trang 6the keystroke alone
If Pos > 0 Then
' Work out the offset of the new character on the line
Offset = ToneCharPos + 1
If Offset <= ChList(Pos).Length Then
' Extract the new character
NewCh = ChList(Pos).Substring(Offset - 1, 1)
' Console.WriteLine("ChList:{0} Pos:{1} Offset-1:{2}", ChList(Pos), Pos, Offset - 1)
If NewCh = "^" Then ' roll back last character
' eg: letter a followed by 11 => á1 to become a1
' Select the character just on the left of the cursor
Me.SelectionStart -= 1
Me.SelectionLength = 1
' Copy leftmost character on the line to clipboard
Clipboard.SetDataObject(ChList(Pos).Substring(0, 1))
' Paste it to replace the character on the left
Me.Paste()
ConcatCharacterIfFailed(ChList(Pos).Substring(0, 1))
' Leave keystroke alone to let it fall through and
be displayed
' Forget it if the new character is "-", let the keystroke displayed
ElseIf NewCh <> "-" Then
' Select the character just on the left of the cursor
Me.SelectionStart -= 1
Me.SelectionLength = 1
' Copy the new (modified) character to clipboard
ToClipboard(NewCh)
' Paste it to replace the character on the left
Me.Paste()
ConcatCharacterIfFailed(NewCh)
Return True ' Swallow the actual keystroke
End If
End If
End If
End If
End If
End If
EscapeFlag = False ' Reset the Escape Flag
End Function
Để vnTextbox hỗ trợ hai lối bỏ dấu, VNI và VIQR, ta cho nó Property
TypingStyle như sau:
Property TypingStyle() As String
Get
Return mTypingStyle
End Get
Set ( ByVal Value As String)
' Chỉ chấp nhận "VNI" hay "VIQR" mà thôi
If Value = "VNI" Or Value = "VIQR" Then
Trang 7mTypingStyle = Value
End If
End Set
End Property
Lưu ý cách copy một character vào Clipboard:
' Copy it to clipboard
Clipboard.SetDataObject(Ch)
Việc lấy Unicode text string từ Clipboard gồm có hai bước:
1 Tạo một DataObject Interface với Clipboard.GetDataObject()
2 Dùng Interface ấy để lấy data từ Clipboard dưới dạng Unicode
(DataFormats.UnicodeText), rồi đổi nó ra string
' Create a new instance of the DataObject interface.
Dim data As IDataObject = Clipboard.GetDataObject()
' Retrieve LastCh the character in Unicode Text format from clipboard
LastCh = data.GetData(DataFormats.UnicodeText).ToString()
Chắc bạn đã để ý, chữ Việt ta dùng ở đây là Unicode, mặc dầu ta không nhắc gì đến encoding của nó hay code point của mỗi character Nếu bạn chưa quen với Unicode cho chữ Việt thì hãy đọc bài Dùng Unicode chữ Việt trong NET
Rất tiếc vì method Paste bên trong vnTextbox không reliable (bất chừng), nhiều khi nó không Paste được nên LastCh vẫn còn bị highlighted Trong trường hợp
đó Sub ConcatCharacterIfFailed sẽ dùng string concatenation (ghép strings)
để khắc phục khó khăn Nhưng cách ghép strings không hiệu năng bằng Paste
Control vnTextbox có hỗ trợ Escape character \ Con số theo sau Escape
character \ sẽ không bị dùng vào việc bỏ dấu cho nguyên âm ngay trước đó
Xin lưu ý: Ðể program nầy chạy bỏ dấu đuợc bạn phải tạm thời ngưng các
programs như VPSkey hay VietKey, UniKey v.v Lý do là các programs kia sẽ giựt trước các keystrokes của những con số 1 đến 9, sau khi kiểm tra rồi không chịu buông ra cho program nầy thấy
Bạn có thể tải về mã nguồn của control vnTextbox và chương trình thử Hai Zip files nầy là cho 2 projects Bạn load vnTextbox và compile trước để dùng
WindowsControlLibrary2.dll trong bin folder làm reference cho project
TestvnTextbox Sau khi load TestvnTextbox, bạn hãy remove
WindowsControlLibrary2 từ References của nó rồi dùng Menu Command Project
|Add Reference để refernce library WindowsControlLibrary2.dll vừa mới
compile
Nếu bao giờ IDE than phiền về Licence bạn chỉ cần delete file licences.licx
trong Project Folder
Dưới đây là hình form chính của program TestvnTextbox
Trang 8Học Microsoft NET
</< Font>
Vovisoft © 2000 All rights reserved.