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