ActiveX programmering eller vart tog minnet vägen?
Förord
Hej, jag tänkte att jag skulle skriva en introduktion till ActiveX-programmering i VB avsedd för nybörjare. Till att börja med så måste vi klargöra begreppet ActiveX. Vad ActiveX innebär för mig som programmerare är inte detsamma som det innebär för Microsoft som uppfinnare av tekniken. För mig innebär ActiveX ett enklare sätt att hantera koden i stora program, en centralisering och generalisering av funktioner samt funktionalitet, det innebär också ett enkelt sätt att skapa återanvändbar kod i VB. Vad Microsoft vill att det skall innebära är oväsentligt då jag enbart tänker visa hur jag använder ActiveX och vad man skall tänka på när man använder konceptet i sin egen kod.Det finns flera typer av ActiveX-komponenter som har sina egna användningsområden. Först och främst har den som är enklast (både att förstå och att använda) nämligen OCX-komponenterna. En OCX används (oftast!) för att på ett enkelt sätt skapa synliga kontroller för formulär. Textboxar, checkboxar och optionbuttons är exempel på synliga ocx-komponenter medan Timerkontroller är ett exempel på osynliga ocx-komponenter.
Den andra mest vanliga ActiveX-komponenten är DLL´n. Exempel på dessa dll´r är ADO-komponenterna, Microsoft VB-Script runtime komponenterna och så vidare.
Jag tänkte att vi ska börja med att göra en ytterst enkel och begränsad OCX som vi kommer att fylla med funktionalitet efterhand. Men först skall vi gå igenom vad man bör tänka på innan man gör en kontroll.
· Syfte – Vad skall kontrollen användas till?
· Innehåll – Vad skall det finnas för egenskaper för att uppfylla syftet.
· Funktionalitet - Vad skall det finnas för funktionalitet för att uppfylla syftet.
· Händelser – Vilka händelser behöver kontrollen kunna ge ifrån sig?
· Minnesåtgång – Ocx´r man skapar själv kan vara väldigt minneshungriga framför allt äter dom GDI-minne på ett fruktansvärt sätt!
Vi börjar med syftet för exemplet jag tänkte genomföra steg för steg. Idén är att vi skall skapa en textkontroll som bara kan ta emot vissa tangenttryckningar. Vilka tangenter kontrollen skall kunna fånga är följande: Enbart numeriska, enbart bokstäver eller enbart de som användaren av kontrollen bestämmer skall släppas igenom. Kontrollen skall gå att binda mot en datakälla.
Vad behöver vi för egenskaper (properties) för att kunna genomföra dessa begränsningar då? De nya egenskaperna blir i följande: AllowedCharacters. Hmm, tänker många räcker det med bara en egenskap för att få all denna funktionalitet? Jodå om vi trixar lite så skall det inte vara något problem!
Vilken funktionalitet behöver vi då? Egentligen ingen alls. Men bara för att exemplifiera hur man implementerar hur man lägger till funktioner och så vidare skall jag lägga till funktionalitet för att kontrollen skall kunna returnera strängar i med viss formatering.
Vilka händelser som behövs då? Annat än textboxkontrollens egna händelser skall jag bara lägga till en som gör samma sak som den funktionen jag tänkte lägga till.
Minnesåtgången bryr vi oss inte om än! För de som är intresserade i ämnet så kan jag rekommendera att man kollar upp vad en kontroll som är Windowless innebär.
Då skall vi börja med kodandet då!
Steg 1: Öppna VB och skapa ett nytt Projekt av typen ”Standard EXE”, detta projekt blir våran tesplattform för OCX´n.
Steg 2: Gå till menyn ”File” och välj alternativet ”Add project”. Välj ett projekt av typen ”ActiveX Control”.
Steg 3: Du har nu två projekt öppna markera ”Project 1” och namnge det till ” TestApp”, namnge det andra projektet till ” MinaKontroller”. Namnge formuläret i TestApp-projektet till ”frmTest” och ”Usercontrol1´” skall byta namn till ”MinTextKontroll”.
Steg 4: Lägg till en textbox på UserControl-formuläret och namnge den till ”txt”.
Nu har vi en det utgångsmaterial som vi behöver!
Dubbelklicka nu på UserControl-formuläret så kommer du in i kod delen av det i sub ”UserControl_Initialize”. Det är där allt händer när kontrollen laddas första gången. Den behöver vi inte bry oss om än på ett tag. Tag istället bort den koden som finns och lägg in koden som står nedan så går vi igenom den steg för steg senare, stäng sedan ner alla formulär utom frmTest och lägg till en kontroll av den typen vi just skapade på det formuläret (kontrollen ligger sist av alla kontroller och ser ut som ett litet formulär med en penna på):
Vad är det vi har lagt till för kod då?
Jo, vi börjar med deklarationerna: Alla variabler, typer och enumereringar som är publika kommer man åt varifrån som helst. De som är privata kommer man bara åt inifrån kontrollen. Och sedan finns det en typ till de som är deklarerade som Friend, dessa kommer man bara åt inom projektet.
Alltså så kan vi från ett formulär där kontrollen finns med deklarera en variabel av typen AllowedCharactersEnum, men inte komma åt variabeln sAllowedCharacters.
Nu har vi dessutom skapat en Event som heter MinHandelse och lämnar ifrån sig ett strängvärde. Vi återkommer till Eventet lite senare.
Private Sub UserControl_Resize() är ett event som sker när kontrollen ändrar storlek (vare sig du är i Runtime eller Designtime) precis som Form_Resize(). I UserControl_Resize använder vi oss av ett nytt objekt nämligen UserControl-objektet. Detta objekt ÄR din kontroll med de egenskaper den har precis som ett formulär. Man kan också använda Me-objektet och på så sätt komma åt kontrollens egenskaper. Förvirrande?
UserControl-objektet innehåller information om kontrollens container medan Me-objektet innehåller info om kontrollen och det gränssnitt som kontrollen har för användaren.
Nästa grej vi ska kolla på är vad en Property är och hur den fungerar: En property är en egenskap man kan tilldela värden och samtidigt styra hur man får tilldela värden i. Vi börjar med ”Public Property Let AllowedCharacters(vValue As Variant)”, hit kommer vi när egenskapen AllowedCharacters får ett värde och värdet levereras i formatet Variant i variabeln vValue, dvs när vi skriver följande kod i vårt formulär (frmTest) så är det hit vi kommer:
En Property kan ha suffixet Let, Get och Set. Let har jag just visat vad den gör, Set gör exakt samma sak men tar emot ett objekt istället (Vi kommer att gå närmare på den när vi lägger till funktionalitet för att binda kontrollen mot en datakälla). Get ska vi kolla lite närmare på nu…
”Public Property Get AllowedCharacters () As Variant” är stället där vi hämtar vår information om en egenskapen ”AllowedCharacters” hos kontrollen. Den fungerar som en funktion och returnerar ett värde. Typerna hos Let, Get och Set måste vara samma (i det här fallet Variants) annars så får man en massa elaka felmeddelanden. För att testa Get så kan du lägga till följande kod i formuläret (frmTest):
Varje gång du klickar på formuläret så kommer de tecken som är tillåtna inmatningstecken att synas i Debug-fönstret.
Nu vill jag också att ni lägger till följande kod i formuläret:
Den här koden anropar min funktion när du dubbelklickar på formläret.
Lägg slutligen till denna kod i formuläret:
Det här är händelsen som vi reser i subrutinen ”txt_Click” på kontrollen.
Konstigare än så här är det egentligen inte att skapa en egen kontroll. Jag vet att min pedagogik inte är den bästa men jag hoppas att någon lärde sig något nytt. Om intresset för den här artikeln är tillräckligt högt så kommer jag i nästa artikel ta upp ämnen såsom Propertybags, datakällor och lite annat smått och gott.
Fil: activex_del1.zip
För att jag skall veta om kursen är bra eller om den måste skrivas om så rösta gärna här uppe till höger. Skicka gärna ett iMail om du vill kommentera något som är felaktigt eller du tycker borde förtydligas.
/Pontus Wång
Den andra mest vanliga ActiveX-komponenten är DLL´n. Exempel på dessa dll´r är ADO-komponenterna, Microsoft VB-Script runtime komponenterna och så vidare.
Hur gör man en ActiveX-komponent och vad skall man tänka på?
Jag tänkte att vi ska börja med att göra en ytterst enkel och begränsad OCX som vi kommer att fylla med funktionalitet efterhand. Men först skall vi gå igenom vad man bör tänka på innan man gör en kontroll.· Syfte – Vad skall kontrollen användas till?
· Innehåll – Vad skall det finnas för egenskaper för att uppfylla syftet.
· Funktionalitet - Vad skall det finnas för funktionalitet för att uppfylla syftet.
· Händelser – Vilka händelser behöver kontrollen kunna ge ifrån sig?
· Minnesåtgång – Ocx´r man skapar själv kan vara väldigt minneshungriga framför allt äter dom GDI-minne på ett fruktansvärt sätt!
Vi börjar med syftet för exemplet jag tänkte genomföra steg för steg. Idén är att vi skall skapa en textkontroll som bara kan ta emot vissa tangenttryckningar. Vilka tangenter kontrollen skall kunna fånga är följande: Enbart numeriska, enbart bokstäver eller enbart de som användaren av kontrollen bestämmer skall släppas igenom. Kontrollen skall gå att binda mot en datakälla.
Vad behöver vi för egenskaper (properties) för att kunna genomföra dessa begränsningar då? De nya egenskaperna blir i följande: AllowedCharacters. Hmm, tänker många räcker det med bara en egenskap för att få all denna funktionalitet? Jodå om vi trixar lite så skall det inte vara något problem!
Vilken funktionalitet behöver vi då? Egentligen ingen alls. Men bara för att exemplifiera hur man implementerar hur man lägger till funktioner och så vidare skall jag lägga till funktionalitet för att kontrollen skall kunna returnera strängar i med viss formatering.
Vilka händelser som behövs då? Annat än textboxkontrollens egna händelser skall jag bara lägga till en som gör samma sak som den funktionen jag tänkte lägga till.
Minnesåtgången bryr vi oss inte om än! För de som är intresserade i ämnet så kan jag rekommendera att man kollar upp vad en kontroll som är Windowless innebär.
Min första OCX!
Då skall vi börja med kodandet då!Steg 1: Öppna VB och skapa ett nytt Projekt av typen ”Standard EXE”, detta projekt blir våran tesplattform för OCX´n.
Steg 2: Gå till menyn ”File” och välj alternativet ”Add project”. Välj ett projekt av typen ”ActiveX Control”.
Steg 3: Du har nu två projekt öppna markera ”Project 1” och namnge det till ” TestApp”, namnge det andra projektet till ” MinaKontroller”. Namnge formuläret i TestApp-projektet till ”frmTest” och ”Usercontrol1´” skall byta namn till ”MinTextKontroll”.
Steg 4: Lägg till en textbox på UserControl-formuläret och namnge den till ”txt”.
Nu har vi en det utgångsmaterial som vi behöver!
Dubbelklicka nu på UserControl-formuläret så kommer du in i kod delen av det i sub ”UserControl_Initialize”. Det är där allt händer när kontrollen laddas första gången. Den behöver vi inte bry oss om än på ett tag. Tag istället bort den koden som finns och lägg in koden som står nedan så går vi igenom den steg för steg senare, stäng sedan ner alla formulär utom frmTest och lägg till en kontroll av den typen vi just skapade på det formuläret (kontrollen ligger sist av alla kontroller och ser ut som ett litet formulär med en penna på):
' Berättar bara att vi inte får glömma bort att deklarera variabler
Option Explicit
' En enumerering för att enklare kunna välja inmatningsbegränsning
Public Enum AllowedCharactersEnum
AllowOnlyNumerical = 1
AllowOnlyAlpha = 2
End Enum
' Här kommer vi att hålla reda på vilka tecken som är giltiga att mata in
Private sAllowedCharacters As String
' En händelse som ger dig det inmatade datat med den första bokstaven som versal och resten som gemener
Public Event MinHandelse(sValue As String)
' När du lägger ut kontrollen på formuläret är det viktikt att den ändrar storlek på rätt sätt
Private Sub UserControl_Resize ()
txt.Move UserControl.ScaleLeft, UserControl.ScaleTop, UserControl.ScaleWidth, ScaleHeight
End Sub
' Hit kommer vi när vi LÄMNAR information om vilka giltiga tecken vi skall ha i kontrollen
Public Property Let AllowedCharacters(vValue As Variant)
If IsNumeric(vValue) Then
Select Case vValue
Case AllowOnlyAlpha
sAllowedCharacters = "abcdefghijklmnopqrstuvwxyzåäö"
Case AllowOnlyNumerical
sAllowedCharacters = "0123456789"
End Select
Else
sAllowedCharacters = vValue
End If
End Property
' Här valideras om inmatningen är giltig
Private Sub txt_KeyPress(KeyAscii As Integer)
If InStr(1, sAllowedCharacters, Chr(KeyAscii), vbTextCompare) = 0 Then
KeyAscii = 0
End If
End Sub
' Här reser vi händelsen "MinHandelse"
Private Sub txt_Click ()
RaiseEvent MinHandelse(MinFunktion)
End Sub
' Hit kommer vi när vi HÄMTAR information om vilka giltiga tecken som finns i kontrollen
Public Property Get AllowedCharacters() As Variant
AllowedCharacters = sAllowedCharacters
End Property
' En funktion som ger dig det inmatade datat med den första bokstaven som versal och resten som gemener
Public Function MinFunktion() As String
If Len(txt.Text) = 0 Then
MinFunktion = vbNullString
Exit Function
ElseIf Len(txt.Text) = 1 Then
MinFunktion = UCase(txt.Text)
Exit Function
End If
MinFunktion = UCase(Left(txt.Text, 1)) & LCase(Mid(txt.Text, 2))
End Function
Vad är det vi har lagt till för kod då?
Jo, vi börjar med deklarationerna: Alla variabler, typer och enumereringar som är publika kommer man åt varifrån som helst. De som är privata kommer man bara åt inifrån kontrollen. Och sedan finns det en typ till de som är deklarerade som Friend, dessa kommer man bara åt inom projektet.
Alltså så kan vi från ett formulär där kontrollen finns med deklarera en variabel av typen AllowedCharactersEnum, men inte komma åt variabeln sAllowedCharacters.
Nu har vi dessutom skapat en Event som heter MinHandelse och lämnar ifrån sig ett strängvärde. Vi återkommer till Eventet lite senare.
Private Sub UserControl_Resize() är ett event som sker när kontrollen ändrar storlek (vare sig du är i Runtime eller Designtime) precis som Form_Resize(). I UserControl_Resize använder vi oss av ett nytt objekt nämligen UserControl-objektet. Detta objekt ÄR din kontroll med de egenskaper den har precis som ett formulär. Man kan också använda Me-objektet och på så sätt komma åt kontrollens egenskaper. Förvirrande?
UserControl-objektet innehåller information om kontrollens container medan Me-objektet innehåller info om kontrollen och det gränssnitt som kontrollen har för användaren.
Nästa grej vi ska kolla på är vad en Property är och hur den fungerar: En property är en egenskap man kan tilldela värden och samtidigt styra hur man får tilldela värden i. Vi börjar med ”Public Property Let AllowedCharacters(vValue As Variant)”, hit kommer vi när egenskapen AllowedCharacters får ett värde och värdet levereras i formatet Variant i variabeln vValue, dvs när vi skriver följande kod i vårt formulär (frmTest) så är det hit vi kommer:
Private Sub Form_Load()
MinTextKontroll1.AllowedCharacters = AllowOnlyNumerical
End Sub
En Property kan ha suffixet Let, Get och Set. Let har jag just visat vad den gör, Set gör exakt samma sak men tar emot ett objekt istället (Vi kommer att gå närmare på den när vi lägger till funktionalitet för att binda kontrollen mot en datakälla). Get ska vi kolla lite närmare på nu…
”Public Property Get AllowedCharacters () As Variant” är stället där vi hämtar vår information om en egenskapen ”AllowedCharacters” hos kontrollen. Den fungerar som en funktion och returnerar ett värde. Typerna hos Let, Get och Set måste vara samma (i det här fallet Variants) annars så får man en massa elaka felmeddelanden. För att testa Get så kan du lägga till följande kod i formuläret (frmTest):
Private Sub Form_Click()
Debug.Print MinTextKontroll1.AllowedCharacters
End Sub
Varje gång du klickar på formuläret så kommer de tecken som är tillåtna inmatningstecken att synas i Debug-fönstret.
Nu vill jag också att ni lägger till följande kod i formuläret:
Private Sub Form_DblClick()
Debug.Print MinTextKontroll1.MinFunktion
End Sub
Den här koden anropar min funktion när du dubbelklickar på formläret.
Lägg slutligen till denna kod i formuläret:
Private Sub MinTextKontroll1_MinHandelse(sValue As String)
MsgBox sValue
End Sub
Det här är händelsen som vi reser i subrutinen ”txt_Click” på kontrollen.
Konstigare än så här är det egentligen inte att skapa en egen kontroll. Jag vet att min pedagogik inte är den bästa men jag hoppas att någon lärde sig något nytt. Om intresset för den här artikeln är tillräckligt högt så kommer jag i nästa artikel ta upp ämnen såsom Propertybags, datakällor och lite annat smått och gott.
Fil att tanka
Fil: activex_del1.zip
Avslutningsvis
För att jag skall veta om kursen är bra eller om den måste skrivas om så rösta gärna här uppe till höger. Skicka gärna ett iMail om du vill kommentera något som är felaktigt eller du tycker borde förtydligas./Pontus Wång
0 Kommentarer