Kirjautuminen

Haku

Tehtävät

Koodit: VB6: Unicode VB:n formeissa ja kontrolleissa

Kirjoittaja: Merri

Kirjoitettu: 14.09.2008 – 14.09.2008

Tagit: teksti, koodi näytille, vinkki

On varmaan tullut jossakin vaiheessa selväksi, etteivät VB:n peruskontrollit tue Unicodea. Enimmäkseen tämä on totta, ei yksinkertaisesti ole teknisesti mahdollista saada Unicodea irti labelista tai tekstilootasta tekemättä kokonaan uusia kontrolleja itse alusta alkaen.

On kuitenkin olemassa mahdollisuus Unicoden käyttöön formeissa ja muutamissa kontrolleissakin. Nimeltä nämä sopivat kontrollit ovat CheckBox, CommandButton, Frame ja OptionButton. Nämä neljä ovat Windowsin näkökulmasta itseasiassa yksi ja sama Button-kontrolli, vaikka VB6 erotteleekin ne omilleen. Itse temppu on varsin yksinkertainen: sen sijaan että käyttää VB:n tarjoamia toimintoja, niin heittääkin tekstin vaihtokomennot kulkemaan oletusikkunaproseduurin Unicode-version kautta.

Koodilistaus 1 sisältää esimerkin, jolla voi vaihtaa edellä mainittujen kontrollien tekstiä siten, että Unicode toimii. Käyttö on helponpuoleista, UniCaption(Form1) = ChrW$(&H3042) näyttää yhden japanilaisen tavumerkin Form1:n nimenä (huomaa että Itä-Aasian kielien tuen pitää olla asennettuna Ohjauspaneelin kautta). Lopputuloksena on Unicodea surullisenkuuluisien kysymysmerkkien sijaan... mutta vain Windows XP:ssä ja Vistassa. Temppu ei toimi täysin Windows 2000:ssa. 2000 kyllä näyttää tehtäväpalkissa sen mitä pitääkin, mutta ikkunan otsikossa tulee kysymysmerkkejä.


MDI-ikkunan kanssa toimiessa elämästä tulee hieman monimutkaisempaa mikäli sallit lapsiformien suurentamisen: VB päivittelee MDI-ikkunan otsikkoa automaattisesti mikäli lapsi-ikkuna suurennetaan tai jos suurennettu lapsi-ikkuna suljetaan. Tämän vuoksi tarvitaan funktio, joka päivittää MDI-ikkunan otsikon vähemmällä vaivalla automaagisesti kutsusta.

Katso toinen koodilistaus nähdäksesi esimerkin. Siinä koodi selvittää aktiivisen lapsi-ikkunan ja näyttää sen sitten MDI-ikkunan otsikossa MDI-ikkunan oman otsikon lisäksi. MDI-ikkunan varsinainen otsikko säilötään Tagiin. Mikäli lapsi-ikkuna ei ole suurennettu, niin silloin lapsi-ikkunan otsikkoa ei näytetä MDI-ikkunan otsikossa.


Myös lapsi-ikkunaan tarvitaan hieman koodia. Kurkkaa koodilistausta kolme. Käytännössä se yrittää vaihtaa kaikkia formin kontrollien tekstejä muutamiin japanilaisiin merkkeihin, tunnistaa milloin ikkunan WindowState muuttuu tietääkseen milloin käskeä päivittää MDI-ikkunan otsikkoa sekä korjaa suurennetun lapsi-ikkunan sulkemistilanteen ongelman, jossa VB päivittäisi väärän otsikon MDI-ikkunaan lapsi-ikkunan tuhoamisen jälkeen. Tämän takia lapsi-ikkuna pitää poistaa näkyviltä ensin, jolloin aktiivinen lapsi katoaa ja MDI-ikkuna saa siitä tiedon.


Ohessa on linkki tämän vinkin englanninkieliseen versioon, josta voi ladata täyden esimerkin. Projektiin on sisällytetty hieman lisätäytteitä, kuten Unicode-versiot Command$- ja MsgBox-funktioista, joiden avulla saat ohjelmalle syötetyt Unicode-tiedostonimet sekä näytettyä viestilootissa Unicode-tekstiä, mikä varmasti helpottaa kivasti Unicode-testailua kun on mahdollista käytännössä nähdä onko tekstimuuttujassa oikeasti Unicodea vai onko se vaan muunneltu ANSIsta.

How to use Unicode with forms and standard controls?

' UniCaption-funktio (moduuliin)
Option Explicit

Private Declare Function DefWindowProcW Lib "user32" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub PutMem4 Lib "msvbvm60" (Destination As Any, Value As Any)
Private Declare Function SysAllocStringLen Lib "oleaut32" (ByVal OleStr As Long, ByVal bLen As Long) As Long

Private Const WM_GETTEXT = &HD
Private Const WM_GETTEXTLENGTH = &HE
Private Const WM_SETTEXT = &HC

Public Property Get UniCaption(ByRef Control As Object) As String
    Dim lngLen As Long, lngPtr As Long
    ' varmista objektin olemassaolo ja sen tyyppi
    If Not Control Is Nothing Then
        If _
            (TypeOf Control Is CheckBox) _
        Or _
            (TypeOf Control Is CommandButton) _
        Or _
            (TypeOf Control Is Form) _
        Or _
            (TypeOf Control Is Frame) _
        Or _
            (TypeOf Control Is MDIForm) _
        Or _
            (TypeOf Control Is OptionButton) _
        Then
            ' hae tekstin pituus
            lngLen = DefWindowProcW(Control.hWnd, WM_GETTEXTLENGTH, 0, ByVal 0)
            ' pituutta pitää olla!
            If lngLen Then
                ' luo uusi samanmittainen BSTR
                lngPtr = SysAllocStringLen(0, lngLen)
                ' palauta kyseinen BSTR paluuarvona
                PutMem4 ByVal VarPtr(UniCaption), ByVal lngPtr
                ' kutsu oletusikkunaproseduurin Unicode-versiota tarjoillen sinne luomamme BSTR
                DefWindowProcW Control.hWnd, WM_GETTEXT, lngLen + 1, ByVal lngPtr
            End If
        Else
            ' kokeillaan hakea oletusarvo
            On Error Resume Next
            UniCaption = Control
        End If
    End If
End Property
Public Property Let UniCaption(ByRef Control As Object, ByRef NewValue As String)
    ' varmista objektin olemassaolo ja sen tyyppi
    If Not Control Is Nothing Then
        If _
            (TypeOf Control Is CheckBox) _
        Or _
            (TypeOf Control Is CommandButton) _
        Or _
            (TypeOf Control Is Form) _
        Or _
            (TypeOf Control Is Frame) _
        Or _
            (TypeOf Control Is MDIForm) _
        Or _
            (TypeOf Control Is OptionButton) _
        Then
            ' kutsu oletusikkunaproseduuria ja tarjoile BSTR:n pointteri
            DefWindowProcW Control.hWnd, WM_SETTEXT, 0, ByVal StrPtr(NewValue)
        Else
            ' kokeillaan asettaa oletusarvo
            On Error Resume Next
            Control = NewValue
        End If
    End If
End Property
' MDI-ikkunan esimerkki
Option Explicit

Public Sub CaptionW(Optional ByRef NewCaption As String)
    ' muuta teksti jos tarjottiin jotain muuta kuin vbNullString
    If StrPtr(NewCaption) Then Me.Tag = NewCaption
    ' onko aktiivista lapsi-ikkunaa?
    If Not Me.ActiveForm Is Nothing Then
        ' onko ikkuna suurennettu?
        If Me.ActiveForm.WindowState = vbMaximized Then
            ' molempien otsikot esiin!
            UniCaption(Me) = UniCaption(Me.ActiveForm) & " - " & Me.Tag
        Else
            ' vain MDI-ikkunan otsikko
            UniCaption(Me) = Me.Tag
        End If
    Else
        ' vain MDI-ikkunan otsikko
        UniCaption(Me) = Me.Tag
    End If
End Sub

Private Sub MDIForm_Load()
    ' aseta otsikko ensikerran
    Me.CaptionW "MDI: " & ChrW$(&H3042)
End Sub
' lapsi-ikkunan esimerkki
Option Explicit

Private Sub Form_Load()
    Dim Ctrl As Control
    ' koeta muuttaa kaikkien kontrollien teksti
    For Each Ctrl In Me.Controls
        UniCaption(Ctrl) = ChrW$(&H3042) & ChrW$(&H3052) & ChrW$(&H3062)
    Next Ctrl
    ' muuta ikkunan otsikko
    UniCaption(Me) = "Child: " & ChrW$(&H3042)
End Sub

Private Sub Form_Resize()
    Static WindowState As FormWindowStateConstants
    ' onko formin WindowState muuttunut?
    If WindowState <> Me.WindowState Then
        ' kutsu omaa funktiotamme MDI-ikkunassa
        MDIForm1.CaptionW
        ' muista nykyinen tila
        WindowState = Me.WindowState
    End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
    ' tällä vältetään ongelma, jolla MDI-ikkunan otsikko muuttuu vääräksi suljettaessa suurennettua lapsi-ikkunaa
    Me.Visible = False
End Sub

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta