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