• Thứ Hai, 12/01/2004 11:03 (GMT+7)

    Chuyển đổi chữ hoa, chữ thường: Bàn thêm về ToogleCase, chèn hình

    Trên PCW VN A 8/2003, trong phần trả lời câu hỏi của một bạn đọc về chuyển đổi Title Case (tr.112), tòa soạn có đưa ra hàm ToogleCase thực hiện cắt mỗi kí tự trong chuỗi ra và so sánh, nếu là chữ hoa thì chuyển thành chữ thường và ngược lại. Tuy nhiên cách này chỉ chuyển đổi tốt các chữ tiếng Anh (chữ không dấu) còn đối với tiếng Việt thì chương trình... chịu thua. Tôi xin góp ý một cách làm dựa trên ý tưởng trên nhưng xử lý được chữ tiếng Việt bằng VB6.
    Đầu tiên các bạn đặt lên form1 (tên frmmain) một richtextbox (tên rtfText), 1 commandbutton (tên cmdConV), 2 listbox (tên lstUni và listVni, cả hai thiết lập thuộc tính Visible=False). Trong thuộc tính list của lstUni bạn đưa vào  các kí tự Unicode có cả chữ hoa lẫn chữ thường. Nhớ chuyển trình gõ tiếng Việt của bạn qua Unicode và nhập các kí tự chữ hoa đối xứng với các ký tự chữ thường (vd: aáàAÁÀ). Đối với thuộc tính list của lstVni thì hơi khác một chút vì các kí tự Uni chỉ 1 byte trong khi đó các kí tự Vni có cả 1 byte và 2 byte. Bạn nhập vào list sau (nhớ chuyển trình gõ qua kiểu Vni):

    "abcdefghijklmnopqrstvuxyzw  ă  ø  ư    ê    â    đ            ơ  ü    ô ĩ         ì    í   ABCDEF GHIJKLMNOPQRSTVUXYZW  Ă  Ø  Ư    Ê      Đ  Ơ  Ü    Ô Ĩ         Ì    Í"

    (không có dấu ngoặc kép)

    Sở dĩ phải làm như vậy vì VNI có các kí tự 2 byte được tạo thành từ 2 kí tự 1 byte. Vd: ấ = a + á.
    Cốt lõi của chương trình là khi đổi chữ "ấ " sang chữ hoa và ngược lại thì ta lần lượt đổi 'a'->'A' và 'á'-> 'Á' sau đó ghép 2 kí tự lại. Để có thể nhập vào lstVni các kí tự như 'á' thì bạn phải thiết lập thuộc tính font của lstVni là Tahoma hoặc MS Sans Serif,... Chọn bảng mã trình nhập tiếng Việt (VietKey, Unikey,...) là Vni-Times. Cứ gõ bình thường chữ "ấ ", khi này trong lstVni sẽ xuất hiện "aá", chỉ việc xoá 'a' và chừa lại 'á' thì bạn sẽ có kí tự mong muốn. Một điều quan trọng là các kí tự hoa và thường này phải đối xứng nhau. Có thể có một cách đơn giản hơn là soạn thảo một file XML chứa các kí tự trên rồi khi form_load thì load nội dung file này vào lstVni, tuy nhiên chỉ có Win2000 mới hỗ trợ XML. Sau khi hoàn tất bước trên bạn chuyển qua nhập code vào viewcode của frmmain:

    Option Explicit

    Dim Pos Integer

    Dim HalfLen as String

    Dim EnCrypt as String

    Dim FontName as String

    Dim i as String

    Dim Str as String

    Dim Ch as String

    Function ChangeCaseUni(ch) As String

    Pos = InStr(lstUni.List(0), ch) ' Tìm xem kí tự ch nằm ở vị trí thứ mấy trong lstUni.

    HalfLen=len(lstUni.List(0))/2 ' Xem có bao nhiêu chữ hoa và bao nhiêu chữ thường

    If Pos = 0 Then

    ChangeCaseUni = ch

    Else

      If Pos > HalfLen Then

    ' Nếu vị trí kí tự nằm bên phần chữ hoa(>HalfLen)

    ' thì chuyễn kí tự thành chữ thường và ngược lại

    ' bằng cách cộng hoặc trừ vị trí của kí tự đó với HalfLen( do

    ' các kí tự đối xứng nhau)

        ChangeCaseUni = Mid(lstUni.List(0), Pos - HalfLen, 1)

      Else

        ChangeCaseUni = Mid(lstUni.List(0), Pos + HalfLen, 1)

      End If

    End If

    End Function

    Function ChangeCaseVNI(ch) As String

    Pos = InStr(lstvni.List(0), ch)

    HalfLen=Len(lstVni.list(0))/2

    If Pos = 0 Then

    ChangeCaseVNI = ch

    Else

      If Pos > HalfLen Then

         ChangeCaseVNI = Mid(lstvni.List(0), Pos - HalfLen, 1)

      Else

         ChangeCaseVNI = Mid(lstvni.List(0), Pos + HalfLen, 1)

      End If

    End If

    End Function

    Private Sub cmdConV_Click()

    '  Lấy xem font của rtfText thuộc họ nào

    '  nếu thuộc họ Vni thì dùng ChangeCaseVni

    '  và nếu thuộc họ Uni thì dùng ChangeCaseUni

    Str=rtfText.SelText

     FontName=rtfText.SelFontName

    If Ucase(Left(FontName,3))='VNI' then 

    EnCrypt=''

    For Ch=1 to Len(Str)

      i=Mid(Str,Ch,1)

      EnCrypt=EnCrypt & ChangeCaseVni(i)

    Next

      rtfText.SelText=EnCrypt

    Else ' Nếu font thuộc họ Uni

      Encrypt=''

    For ch=1 to Len(str)

      i=Mid(Str,Ch,1)

    EnCrypt=EnCrypt & ChangeCaseUni(i)

    Next

      rtfText.SelText=EnCrypt

    End if

    Mỗi lần bạn muốn chuyển đổi dạng chữ chỉ cần quét phạm vi chữ cần chuyển và nhấn cmdConV.
    Nếu ứng dụng linh hoạt chương trình này thì bạn có thể làm được rất nhiều thứ như tạo trình gõ tiếng Việt riêng cho mình, ví dụ khi nhấn a1 thì bạn xóa 2 kí tự này và thay thế bằng 'á'.

    BÀN THÊM VỀ RICHTEXTBOX
    Đối tượng RichTextBox mà Microsoft cung cấp khi cài VB6 chỉ là RichTextBox version 1.0 không hỗ trợ tốt UniCode nên nhiều khi cho kết quả không mong muốn, tốt nhất là nên sử dụng Texbox có hỗ trợ Unicode có sẵn trong VB6. Nếu bạn yêu thích lập trình thì có thể xây dựng cho mình RichTextBox riêng tham chiếu đến Windows\System\riched20.dll (RichtextBox verion 2.0 &3.0) bằng cách Load library riched20.dll, sau đó sử dụng TOM (Text Object Model) thì công việc rất nhẹ nhàng, chỉ cần một dòng lệnh:

    m_CD.TextDocument.Font.ChangeCase=tomToggleCase (đương nhiên là còn có tomSentenCase, tomUpperCase,....)

    Với TOM, bạn có thể làm được mọi thứ mà MS Word làm được.

    CHÈN HÌNH ẢNH
    Cũng cùng trong câu hỏi, phần số 1 có đề cập đến việc chèn hình ảnh (hay icon) vào trước các menu hay menu-popup, tôi xin trình bày một cách làm như sau:

    o Tạo một project mới (Standard EXE)

    o Đặt imagelist (tên img) lên form. Vào custom\image và insert khoảng năm picture (*.bmp)

    o Vào MenuEditor của VB tạo một menu 'cha' và 5 menu 'con' (submenu).

    Nhập đoạn code sau:

    Option Explicit

    Private Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long

    Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) _ As Long

    Private Declare Function GetMenuItemID Lib "user32" (ByVal hMenu As Long, ByVal nPos As _ Long) As Long

    Private Declare Function ModifyMenu Lib "user32" Alias "ModifyMenuA" (ByVal hMenu As Long, _ ByVal nPosition As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpString _ As String) As Long

    Private Declare Function SetMenuItemBitmaps Lib "user32" (ByVal hMenu As Long, ByVal _ nPosition As Long, ByVal wFlags As Long, ByVal hBitmapUnchecked As Long, ByVal hBitmapChecked As Long) As Long

    Private Declare Function GetMenuCheckMarkDimensions Lib "user32" () As Long

    Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

    Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long

    Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth _ As Long, ByVal nHeight As Long) As Long

    Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long

    Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal nHeight As _ Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long

    Private Declare Function GetDesktopWindow Lib "user32" () As Long

    Private Declare Function PatBlt Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As _ Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal dwRop As Long) As Long

    Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long

    Function AddImage()

    Dim i%

      Dim hMenu, hSubMenu, menuID, x

      hMenu = GetMenu(hwnd)

      hSubMenu = GetSubMenu(hMenu, 0)

      For i = 1 To 4

        menuID = GetMenuItemID(hSubMenu, i - 1)

        x = SetMenuItemBitmaps(hMenu, menuID, &H4, img.ListImages(i).Picture, _ img.ListImages(i).Picture)

      Next

      menuID = GetMenuItemID(hSubMenu, 5)

      x = SetMenuItemBitmaps(hMenu, menuID, 0, img.ListImages(5).Picture, 0&)

    End if

    End Function

    Private  sub Form_Load()

     AddImage

    End Sub
    Tuy nhiên chương trình còn hạn chế là chỉ chèn được các ảnh bitmap chứ chưa chèn được icon và các bitmap có màu sẽ hiển thị không tốt.ÿ

    Nguyễn Quốc Việt
    bamby084@hotmail.com

     

     

    ID: A0310_111