|
Copyright © Mats Hindhede 2000 - 2010. All rights reserved. Uppdaterad 2010-11-06. Lathunden skapades ursprungligen för deltagarna på
en Visual Basic-kurs som jag höll
Grundläggande syntax
Denna lathund är en snabbkurs i Visual Basic för ambitiösa nybörjare och en hjälpreda för dig som redan kan språket. Uppgifterna i lathunden gäller Visual Basic 6.0, om inget annat anges. Det mesta i lathunden kan även tillämpas i Visual Basic 4.0 och 5.0. Lathunden beskriver inte hur man använder formulär och kontroller, utan bara själva programmeringsspråket. Resten är lätt att lära sig själv. Eftersom lathunden inte beskriver kontroller beskriver den heller inte ActiveX-kontroller. Den tekniken är också lätt att lära sig själv när man väl kan själva programmeringsspråket. Visual Basic .NET då? Vore det inte bra med en lathund för Visual Basic .NET? Visst vore det bra, men det finns många som fortsätter att arbeta i Visual Basic 6.0. Behovet av bra undervisningsmaterial på svenska är lika stort idag som 1998, när Visual Basic 6.0 lanserades. Visual Basic 6.0 används även som programmeringsspråk i Office 2000 - 2010 under namnet Visual Basic for Applications (VBA). Versionsnumret höjdes till 6.3 i Office XP, 6.5 i Office 2003 och 7.0 i Office 2010, men språket är detsamma. Många kommer att skriva makron i Office i många år till. Vi börjar med språkets grundläggande syntax. Att välja mellan stora och små bokstäver är inget bekymmer. Visual Basic ändrar automatiskt till stor eller liten bokstav när det behövs. Vid namngivning av procedurer, variabler och konstanter skiljer man inte på stora och små bokstäver. I Visual Basic kan man inte ha en variabel som heter X och en annan som heter x i en och samma procedur, vilket man kan i andra programmeringsspråk, t ex Java. I Visual Basic anses X och x vara ett och samma namn. Blanksteg kan man inte göra för många, för onödiga blanksteg tas bort automatiskt. Man radbryter koden om och endast om satsen är slut, med följande undantag:
Normalt skulle man skriva Select Case intA men man kan också skriva Select Case intA eller Select Case intA Man kan t o m skriva Select Case intA: Case 1: MsgBox "Yes": Case 0: MsgBox "No": End Select fast det är nog lite svårare att läsa.
VARNING!
VARNING!
Indrag på lämpliga rader gör koden lättare att förstå. Ett exempel: If blnOK = False Then Lägg märke till att Visual Basic kan öka eller minska indraget på flera rader samtidigt. Det är bara att markera raderna och trycka på Tab eller Shift+Tab. Hur många blanksteg ett tryck på Tab motsvarar kan man själv bestämma om man klickar på Options... på menyn Tools och väljer fliken Editor. Standardvärdet är 4. Många tycker att 2 är mera lagom. På fliken Editor finns även avbockningsrutan Auto Syntax Check. Ta bort bocken i den rutan! Då slipper du alla tjatiga meddelanden om dina syntaxfel. Du blir ändå påmind om syntaxfelen. De får automatiskt en avvikande färg.
Kommentarer inleds med en apostrof ('). Man kan skriva en kommentar till höger om koden på samma rad eller på en egen rad. Alternativt kan man inleda kommentarer med uttrycket Rem. Om man skriver kommentaren till höger om koden på samma rad måste man dessutom infoga ett kolon mellan koden och uttrycket Rem. Om man vill infoga en kommentar som är flera rader lång måste man tyvärr skriva en apostrof eller uttrycket Rem i början av varje rad. T o m HTML är smartare än Visual Basic i det fallet och det är svårt att förstå varför Microsoft inte har hittat en bättre lösning. Det är en viss tröst att man kan lägga till och ta bort apostrofer i början av flera rader samtidigt. Markera raderna och klicka på knapparna Comment Block och Uncomment Block på verktygsfältet Edit:
Private Sub cmdDiff_Click()
VARNING!
VARNING! Typkonverteringsfunktionerna CDbl, CSng och CCur kan ge ett annat returvärde om användarens inställningar i Windows innebär att decimaltecknet är punkt istället för komma. I Sverige används komma. I USA används punkt. Ditt program kan därför behöva kontrollera den aktuella användarens inställningar när det gäller decimaltecknet. Hur ditt program kan kontrollera den saken förklaras i avsnittet Procedurer och deras räckvidd.
Välj namn som upplyser om procedurens, variabelns eller konstantens användning. Om en variabel tilldelas namn på olika företag bör den inte heta strMyLittleString, utan strCompany eller något liknande. Variabelnamn som intA, intB och intC bör användas sparsamt. De är visserligen korta, men säger inget om variabelns användning, vilket gör koden svårare att förstå.
VARNING!
Explicit variabeldeklaration är ett måste i Visual Basic. Man använder explicit variabeldeklaration genom att skriva Option Explicit överst i modulens huvud. Det betyder att alla variabler och konstanter som förekommer i modulen måste deklareras. Observera att denna sats måste skrivas överst i varje modul där man vill att regeln ska gälla. Om man använder explicit variabeldeklaration gör det inte så mycket om man råkar felstava namnet på en redan deklarerad variabel eller konstant. Om man inte använder explicit variabeldeklaration tror Visual Basic att den felstavade variabeln är en ny och odeklarerad variabel. Vilket i sin tur kan leda till en mängd följdfel. Man hamnar inte i den situationen om man skriver Option Explicit överst i modulens huvud. Då får man istället ett felmeddelande när man försöker kompilera eller när man försöker köra det aktuella kodavsnittet:
Om man klickar på Options... på menyn Tools och väljer fliken Editor finner man avbockningsrutan Require Variable Declaration. Sätt en bock i den rutan! Då skriver Visual Basic automatiskt Option Explicit i huvudet av alla nya moduler. Man slipper att skriva det själv. Så här kan det se ut när man deklarerar tre variabler i huvudet av en procedur: Private Sub cmdMyButton_Click() Uttrycket Dim är en förkortning av det engelska verbet dimension, som betyder dimensionera. Man kan även skriva så här: Private Sub cmdMyButton_Click()
VARNING! Private Sub cmdMyButton_Click() I Visual Basic .NET är det inga problem att deklarera variabler som i exemplet närmast ovan. Både strCompany och strLastName får datatypen String. I Visual Basic bör man däremot inte deklarera variabler som i exemplet närmast ovan. Variabeln strCompany får inte datatypen String, utan datatypen Variant, som alla variabler får när man struntar i att ange datatyp eller struntar i att deklarera överhuvudtaget. Dessa regler gäller inte om man använder uttryck som DefStr och DefInt (vilket inte många gör). Antag t ex att man skriver DefStr S i huvudet av en modul. Då får alla variabler och konstanter datatypen String i den modulen om man ger dem namn som börjar på S och deklarerar dem utan att ange datatyp. Författaren rekommenderar inte uttryck som DefStr och DefInt. I Visual Basic .NET har de avskaffats.
Variabler med datatypen String kan deklareras med fast längd: Private Sub cmdMyButton_Click() I detta exempel kommer variabeln strCompany alltid att innehålla åtta tecken. Om den tilldelas en kortare text kommer kvarstående positioner att fyllas med blanksteg. Om den tilldelas en längre text kommer överskjutande tecken att försvinna. I hjälptexterna skriver Microsoft att en String med fast längd kan innehålla "ungefär" 65536 tecken. Om man kontrollerar själv verkar den exakta gränsen vara 65526. Från början fanns det sju datatyper i Visual Basic:
I Visual Basic 4.0 kom det fyra nya datatyper:
I Visual Basic 6.0 kom det ytterligare en datatyp:
Med startvärde menas variabelns värde när den har deklarerats, men ännu inte tilldelats något värde. En del programmerare tycks tro att variabler då är "tomma" eller på något sätt "opålitliga". Så är inte fallet. De är mycket pålitliga. En Boolean har värdet False. En String innehåller en "nollängdssträng", alltså "". En Byte, Integer, Long, Single och Double har alla värdet 0. En Date har också värdet 0, vilket motsvarar 1899-12-30. (Se avsnittet Typkonvertering.) Empty är ett speciellt "värde" som en variabel med datatypen Variant har innan den tilldelas något värde. Man kan även tilldela en sådan variabel "värdet" Null för att visa att variabeln avsiktligen är "tom". Av samma orsak kan man tilldela en variabel med datatypen Object "värdet" Nothing. En Decimal kan inte deklareras på vanligt sätt i Visual Basic 6.0, utan deklareras först som en Variant och omvandlas sedan till en Decimal med typkonverteringsfunktionen CDec. Datatypen Decimal bör inte användas i onödan. Single och Double bör heller inte användas i onödan. Dessa datatyper tar mera plats i datorns arbetsminne. Datatypen Variant bör i möjligaste mån undvikas, för den tar mest plats. Använd gärna ovannämnda prefix (int, lng, sng, dbl, cur, str, vnt, bln, byt, dte, obj och dec) i början av variabelnamn. Att använda prefix i början av variabelnamn kallas ungersk notation efter den ungerske programmeraren Charles Simonyi på Microsoft. Ska man använda ungersk notation bör man göra det konsekvent. Många tycker att ungersk notation gör koden lättare att förstå. Varför? Jo, för det första ser man på variabelnamnet vilken datatyp det är frågan om, vilket är bra i ett programmeringsspråk med automatisk typkonvertering (se avsnittet med samma namn). För det andra ser man lättare vilka ord som är namn på variabler och vilka ord som är andra ord i koden. Det finns ett tredje skäl, som ofta glöms bort. Om man använder ungersk notation kan man använda samma namn till olika variabler genom att kalla en för strNamn, en annan för intNamn, en tredje för lngNamn osv. Det kan vara praktiskt. Tyvärr har inte Microsoft själva varit konsekventa under årens lopp. I de tre första versionerna av Visual Basic förespråkades enställiga prefix som s (för String), i (för Integer) och l (för Long). När det gäller API-anrop (se avsnittet Procedurer och deras räckvidd) har man haft för vana att använda exotiska prefix som lp och dw. En C-programmerare förstår innebörden av dessa prefix. En Visual Basic-programmerare gör det inte. Använd gärna ungersk notation, men ta inte saken alltför högtidligt. Konstanter deklareras med uttrycket Const enligt följande exempel: Private Sub cmdMyButton_Click() Observera att man använder tecknet " på ömse sidor när man tilldelar ett värde till en variabel eller konstant med datatypen String. Observera även att man använder tecknet # på ömse sidor när man tilldelar ett värde till en variabel eller konstant med datatypen Date. I kod från äldre versioner av Visual Basic ser man ofta att programmerare har deklarerat konstanternas namn med stora bokstäver, utan prefix och utan att ange datatyp, vilket numera inte rekommenderas. Att man gjorde så berodde delvis på att man inte fick ange datatyp när man deklarerade konstanter i Visual Basic 3.0 och äldre versioner. Stora bokstäver tycker somliga är bra att använda för att man ska se på namnet att det är frågan om en konstant, men i Visual Basic är det viktigare att se på namnet vilken datatyp det är frågan om. Det går inte att ta den här saken alltför högtidligt heller. Namnen på alla hundratals systemkonstanter som förekommer i API-anrop (se avsnittet Procedurer och deras räckvidd) har av tradition alltid skrivits med stora bokstäver och det är inte lätt att ändra på. Suffixen % (Integer), & (Long), ! (Single), # (Double), @ (Currency) och $ (String) kan användas för att deklarera variabler och konstanter på ett snabbare sätt: Private Sub cmdMyButton_Click() I detta exempel får variablerna strCompany och strLastName datatypen String, liksom konstanten strEmployer. Variabeln intNumber får datatypen Integer, liksom konstanten intBonus. Visual Basic tillåter suffix när det gäller sex av de sju ursprungliga datatyperna. Somliga tycker att detta skrivsätt är svårtolkat och inkonsekvent, eftersom det inte kan tillämpas på alla datatyper. Även vissa funktioner som ingår i själva programmeringsspråket är försedda med suffix, t ex Format$, Left$, Right$, Mid$, Trim$ osv. Microsoft ville på detta sätt poängtera att returvärdet har datatypen String. Tyvärr är det många som inte använder dessa funktioner. Istället använder man funktionen utan suffix. Returvärdet får då datatypen Variant. Funktionerna med suffix kan ge programmet en viss prestandaförbättring. Man kan sätta suffix på sina egna funktioner också. Följande funktion fungerar utmärkt och har ett returvärde med datatypen Long: Public Function Summa&(A&, B&) Skriv inte svårtolkad kod i Visual Basic! Skriv istället Public Function Summa(lngA As Long, lngB As Long) As Long Det är också bra att känna till prefixet &H, som används i koden framför tal i hexadecimal form, och prefixet &O, som används i koden framför tal i oktal form. 15 i decimala talsystemet är samma sak som F i hexadecimala talsystemet. I koden går det inte att bara skriva F. Man måste skriva &HF. Man kan lägga till ett &-tecken efter talet också, men det är frivilligt. Om ett tal i koden är ett heltal och absolutbeloppet är mindre än 32768 tillåter kompilatorn att man skriver ett &-tecken efter talet. Är heltalets absolutbelopp större än 2147483647 lägger Visual Basic till ett #-tecken automatiskt. Det är även tillåtet att lägga till ett @-tecken eller ett !-tecken efter ett tal i koden, om talets absolutbelopp inte är för stort. Effekten blir att man ändrar undertypen för en Variant. & ändrar undertypen till Long, @ till Currency, ! till Single och # till Double. Ett exempel: Private Sub cmdTypeTest_Click() Det första meddelandet blir "Integer", medan det andra blir "Long". En Variant med undertypen Long är inte samma sak som en vanlig Long. Det är t ex effektivare att använda en vanlig Long som räknare i en slinga.
Visual Basic-programmerarens viktigaste kortkommandon Kortkommandona Shift+F2 och Ctrl+Shift+F2 är viktiga för en Visual Basic-programmerare. Utan dem är det svårt att orientera sig i koden. Placera den blinkande markören någonstans i namnet på en procedur, variabel eller konstant. Tryck på Shift+F2. Vips hamnar du på den plats i koden där proceduren, variabeln eller konstanten deklareras. På så sätt kan du snabbt kontrollera datatyp, räckvidd, returvärde eller något annat du behöver veta. Tryck sedan på Ctrl+Shift+F2. Vips är du tillbaka där du var förut.
Objektvariabler Objektvariabler deklareras med tidig bindning ("early binding") eller sen bindning ("late binding"). Tidig bindning är ofta att föredra. Programmets prestanda kan i viss mån förbättras när man använder tidig bindning. Ett undantag är en ActiveX EXE. (Se avsnittet Historik.) Ett sådant objekt kan tjäna på sen bindning. Med "tidig" menas att man i ett tidigt skede (redan när man deklarerar objektvariabeln) specificerar vilket slags objekt det är frågan om. Med "sen" menas att man först i ett senare skede (när objektvariabeln för första gången tilldelas ett objekt) specificerar vilket slags objekt det är frågan om. När man tilldelar ett objekt till en objektvariabel kan man använda uttrycket Set och ordet New. Ett exempel på tidig bindning: Private Sub cmdStartExcel_Click() Objekt kan ha metoder ("methods") och egenskaper ("properties"). Ibland grupperas ett antal objekt i en samling ("collection"). Excel är ett objekt. Detta objekt har egenskapen Application. Egenskapen Application returnerar i sin tur ett objekt, en instans av programmet Microsoft Excel. Detta objekt har egenskapen Visible, som kan vara True eller False, och egenskapen Workbooks, som returnerar samlingen Workbooks. Denna samling består av alla öppna arbetsböcker i den aktuella instansen av Microsoft Excel. Samlingen Workbooks har i sin tur metoden Add, som öppnar en ny arbetsbok. Så där håller det på. Detta och mycket annat beskrivs i Excels objektmodell. Allt man kan göra för hand i Word och Excel kan automatiseras med hjälp av Visual Basic. Program som Access och Project kan också automatiseras med hjälp av Visual Basic, liksom de senaste versionerna av Outlook, PowerPoint, Publisher och Visio. Eftersom dessa program har vitt skilda ändamål är objektmodellerna och tillvägagångssätten olika, men själva programmeringsspråket är detsamma. En rad program från andra företag än Microsoft kan numera också automatiseras med hjälp av Visual Basic. De mest kända är CorelDRAW, WordPerfect och AutoCAD. Man kan använda ordet New redan när objektvariabeln deklareras: Private Sub cmdStartExcel_Click() I detta exempel används ordet New redan när objektvariabeln xlApp deklareras. Objektvariabeln xlBook deklareras och tilldelas ett objekt utan att ordet New används överhuvudtaget. Istället tilldelas objektvariabeln xlBook ett objekt med hjälp av metoden Add. Tidig bindning ger tillgång till IntelliSense, vilket är en stor hjälp när man ska orientera sig i objektmodellerna i Word och Excel:
För att tidig bindning ska fungera krävs i ovanstående exempel en referens till Microsoft Excel i dialogrutan References, som visas om man klickar på References... på menyn Project:
Naturligtvis förutsätter detta att du har installerat Excel på din dator. Ett exempel på sen bindning: Private Sub cmdStartExcel_Click() När man använder sen bindning deklarerar man objektvariabler As Object. Det är viktigt att förstå att en objektvariabel egentligen inte tilldelas ett objekt, utan en referens till ett objekt. Två olika objektvariabler kan referera till samma objekt. När man ändrar en egenskap hos den ena ändras denna egenskap även hos den andra.
Arrayer Att använda arrayer (kallas vektorer eller matriser på svenska) är effektivt. Arrayer hanteras mycket snabbt av Visual Basic, särskilt om du använder optimeringstipsen i slutet av denna lathund. Några exempel på hur man deklarerar och använder arrayer: Dim strMyFriends(2) As String Index för en array börjar alltid med 0 om man inte deklarerar något annat. Det kan man ändra genom att skriva Option Base 1 i huvudet av en modul. Då kommer index alltid att börja med 1 om man inte deklarerar något annat. Observera att detta endast gäller den aktuella modulen. Om man inte vet hur många element som behövs i en array kan man börja med att deklarera den utan att ange antalet element. Man brukar säga att man skapar en dynamisk array: Dim strMyFriends() As String Senare i koden kan man ändra antalet element med uttrycket ReDim: ReDim strMyFriends(1 To 20) Om man inte vill att innehållet ska försvinna när man ändrar antalet element använder man uttrycket ReDim Preserve: ReDim Preserve strMyFriends(1 To 50) Upp till 60 dimensioner kan man använda i arrayer. En tredimensionell array skulle kunna deklareras så här: Dim strMulti(1 To 10, 1 To 50, 1 To 30) As String Om man använder uttrycket ReDim Preserve kan man endast ändra antalet element i den sista dimensionen i en flerdimensionell dynamisk array. Varken ReDim eller ReDim Preserve kan ändra antalet dimensioner i en dynamisk array när den väl har fått ett visst antal dimensioner. ReDim kan inte ändra datatypen för en dynamisk array, om den inte var deklarerad som Variant från början. När man använder uttrycket ReDim är det alltså inte nödvändigt att på nytt ange datatyp, om man inte ändrar från Variant till en annan datatyp och då kan man inte använda ReDim Preserve, bara ReDim.
VARNING!
Funktionerna LBound och UBound är mycket användbara. Dessa funktioner returnerar lägsta respektive högsta index för en array. Man kan även tillämpa dessa funktioner på flerdimensionella arrayer. Antag att variabeln lngSecondLimit ska tilldelas det tal som är högsta index i den andra dimensionen av en tredimensionell array som heter strMulti. Då kan man skriva lngSecondLimit = UBound(strMulti, 2)
VARNING!
VARNING!
VARNING!
Antag att man deklarerar en array så här: Dim strMyArray(0) As String Vad får man? En array? Nej, i praktiken får man bara en variabel med datatypen String, för denna array kan endast rymma ett element. Antag att man deklarerar en array så här: Dim strMyArray(4, 0) As String Vad får man? En tvådimensionell array? Nej, i praktiken får man bara en endimensionell array med fem element, för "på andra ledden" kan denna array endast rymma ett element.
Kopiering av arrayer I Visual Basic 5.0 kan man inte tilldela en array till en annan array. Däremot kan man tilldela en array till en variabel med datatypen Variant. På så sätt kan man kopiera en array. Ett exempel: Private Sub cmdCopyArray_Click() Observera att elementen i vntCopy inte får datatypen String. De får datatypen Variant med undertypen String. Den skillnaden kan medföra en försämring av det färdiga programmets prestanda. I Visual Basic 5.0 kan det vara bättre att kopiera arrayen element för element till en annan array med datatypen String: Private Sub cmdCopyArray_Click() I Visual Basic 6.0 kan man tilldela en array till en annan array om den senare deklarerades som en dynamisk array och båda arrayerna har samma datatyp. Ett exempel: Private Sub cmdCopyArray_Click()
Ett snabbare sätt att fylla en array Det finns Visual Basic-programmerare som känner sig tvingade att skriva som i följande exempel när de tilldelar värden till elementen i en array. Koden kan bli lång. Väldigt lång. Public Sub GetCapitals() Ju fler element, desto snyggare blir det att skriva så här istället: Public Sub GetCapitals() Den inbyggda funktionen Array returnerar en array med datatypen Variant, i detta fall med undertypen String. Lägsta index är alltid 0. For-slingan tilldelar elementens värden till elementen i en array med datatypen String, som ger bättre prestanda.
Arrayer och procedurer Man kan använda en array som argument i en procedur: Private Sub cmdMyButton_Click() Private Sub Talk(strIntro As String, strNames() As String) Lägg märke till att man måste skriva argumentet strNames() med parenteser i procedurens argumentlista, för att visa att endast en array accepteras. Däremot spelar det ingen roll om man använder dessa parenteser när man anropar en procedur. I exemplet ovan kan man skriva strMembers eller strMembers(), det spelar ingen roll. När man vill skapa en procedur med ett varierande antal argument skriver man som i detta exempel: Private Sub TalkMore(strIntro As String, ParamArray vntNames()
As Variant) Subrutinen TalkMore kan säga hej till hur många vänner som helst, så länge du inte har fler än 2147483648. Det högsta index man kan använda i en array är nämligen 2147483647, men det kräver mycket arbetsminne! Lägg märke till att det argument som är ParamArray alltid placeras sist bland argumenten. Datatypen för en ParamArray är alltid Variant och index börjar alltid med 0. En funktion kan även returnera en array. Det kan man åstadkomma på två olika sätt. Dels kan man låta funktionen returnera en Variant som innehåller en array och dels kan man låta funktionen returnera själva arrayen. Det senare kräver Visual Basic 6.0. Här returneras en Variant som innehåller en array (observera att det även är en Variant som tilldelas funktionens returvärde): Private Sub TalkDays() Private Function DayArray() As Variant Här returneras själva arrayen (observera att det är en dynamisk array med rätt datatyp som tilldelas funktionens returvärde): Private Sub TalkDays() Private Function DayArray() As String()
Hur man snabbast överför data mellan tvådimensionella arrayer och cellområden i Excel Man kan inte överföra data från ett cellområde i Excel till vilken tvådimensionell array som helst, bara till en Variant: Function GetData(strRange As String) As Variant Argumentet strRange anger vilket cellområde som avses, t ex "C8:E12". När man överför data i motsatt riktning, från en tvådimensionell array till ett cellområde i Excel, ger Range-objektets Resize-egenskap bäst prestanda: Sub SetData(strUpperLeft As String, vntData As Variant) Argumentet strUpperLeft anger referensen till cellen överst till vänster i cellområdet, t ex "B2". Resize-egenskapen kan även tilldelas tvådimensionella arrayer med andra datatyper än Variant. Om Resize-egenskapen tilldelas en endimensionell array måste elementen placeras på en rad i kalkylbladet i Excel, inte i en kolumn: Sub RowOfCapitals() Låt oss därför förbättra subrutinen SetData ovan, så att den även kan hantera en endimensionell array och placera den i en kolumn i kalkylbladet, inte bara på en rad. Även om Excel 2007 har lika många kolumner som Excel 95 hade rader (16384) är antalet rader i Excel 2007 mycket större (1048576) än antalet kolumner. Den förbättrade subrutinen har även felhantering (se avsnittet Felhantering och avlusning): Sub SetAnyData(strUpperLeft As String, vntData As Variant, _
Samlingar Samlingar (kallas collections på engelska) har vissa fördelar som arrayer saknar. Man kan använda en slinga av typen For Each (se avsnittet Operatorer, slingor och inbyggda funktioner) för att nå alla medlemmarna i en samling. Att nå alla elementen i en array på detta sätt är inte möjligt om inte datatypen är Variant. Om man vill öka eller minska antalet element i en array måste den omdimensioneras. Samlingar omdimensioneras inte, antalet medlemmar går att öka eller minska ändå. Att nå en viss medlem i en samling är dessutom lättare än att nå ett visst element i en array.
VARNING!
En samling deklareras på samma sätt som ett objekt: Dim colCapitals As Collection En samling har fyra metoder. Add, Item, Remove och Count. Metoden Add har fyra argument. Det första argumentet är den nya medlemmens värde. Det kan vara ett numeriskt värde eller en textsträng inom citationstecken. Det andra argumentet är en frivillig nyckel som kan användas om man senare vill läsa medlemmens värde med hjälp av metoden Item eller ta bort medlemmen med hjälp av metoden Remove. Nyckeln måste vara en textsträng inom citationstecken. Tredje och fjärde argumentet är också frivilliga. De kan användas för att ange var i samlingen den nya medlemmen ska placeras. colCapitals.Add "London", "Great Britain" Metoden Item har bara ett argument. strCapital = colCapitals.Item("Italy") och strCapital = colCapitals.Item(3) ger samma resultat. Variabeln strCapital tilldelas värdet av den tredje medlemmen i samlingen colCapitals, alltså "Rome". Samlingar har alltid ett index som börjar med 1. Metoden Remove har också bara ett argument. colCapitals.Remove("Italy") och colCapitals.Remove(3) ger samma resultat. Den tredje medlemmen i samlingen colCapitals tas bort. Metoden Count returnerar det aktuella antalet medlemmar i samlingen. Ett exempel: MsgBox "Samlingen colCapitals har " & colCapitals.Count & " medlemmar"
Egna datatyper Om man vill kan man använda egna datatyper i Visual Basic. De kallas även "användardefinierade typer" ("user-defined types" på engelska). Dessa mindre lyckade benämningar började Microsoft använda i föregångaren QuickBasic på 80-talet. I C++ och Java säger man structure. I Pascal säger man record. Egentligen är det lätt. Man hittar på ett gemensamt namn för ett antal variabler med de gamla vanliga datatyperna. Ibland kan det vara praktiskt att hantera vissa variabler tillsammans, istället för att hantera dem var för sig. I huvudet av en standardmodul kan man t ex skriva Public Type Member I en procedur i samma projekt kan man sedan skriva Dim udtNewMember As Member och senare i samma procedur udtNewMember.MemberID = 1234 udtEmptyMember då? Vad är den variabeln till för? Jo, det är bra att ha en tom variabel med samma egna datatyp. Då kan man lätt tömma innehållet i andra variabler med samma egna datatyp. Skriv bara så här: udtNewMember = udtEmptyMember Det är förstås lättare än att skriva så här: udtNewMember.MemberID = 0 Om man deklarerar en egen datatyp i huvudet av en formulärmodul måste man använda ordet Private. Då kan den egna datatypen bara användas för att deklarera lokala eller modulära variabler i den aktuella formulärmodulen. (Se avsnittet Variablers och konstanters räckvidd.) Vill man kunna deklarera variabler med egen datatyp i vilken modul som helst måste den egna datatypen deklareras i huvudet av en standardmodul. Man kan utelämna ordet Public, men för tydlighets skull bör det vara med. För att få global räckvidd måste variabler med egen datatyp också deklareras i huvudet av en standardmodul. Ordet Public måste användas. Det går bra att använda en variabel med egen datatyp som argument i en procedur. När det passar dina syften kan du även göra en array av en variabel med egen datatyp: Dim udtAllMembers(1 To 10) As Member
VARNING!
Numreringar Med uttrycket Enum kan man skapa något som påminner om egna datatyper, fast man grupperar inte ett antal variabler med olika datatyper, utan ett antal konstanter med datatypen Long. Det kallas numreringar. En del säger enumeratorer. En numrering passar bra som datatyp för en variabel vars tillåtna värden är ett begränsat antal heltal, eller rättare sagt ett begränsat antal alternativ som vart och ett representeras av ett heltal. Som följande exempel visar kan en numrering vara bra att använda som argument i en procedur. När proceduren anropas får man som synes en praktisk lista över argumentets tillåtna värden.
Numreringar har samma begränsningar som datatypen Long, så alla heltal mellan -2147483648 och 2147483647 kan användas, även i hexadecimal form. I en numrering behöver inte alternativen numreras i ordning. Om man struntar i att numrera alternativen får de automatiskt en numrering som börjar med 0.
En programmerare vill ofta tilldela variabeln A till variabeln B. Om A och B är deklarerade med olika datatyper kan tilldelningen vara begränsad av olika regler eller helt förbjuden. Visual Basic är ett mycket snällt språk i den situationen och tillåter det mesta. I Visual Basic kan man alltid tilldela en Byte, Integer, Long, Currency, Single, Double, Date eller Boolean till en String, utan att använda typkonverteringsfunktionen CStr. Man kan till och med konkatenera (sammanfoga) en Byte med en Integer och en Long och en Currency och en Single och en Double och en Date och en Boolean och tilldela resultatet till en String. Motsatsen, att tilldela en String till en Byte, Integer, Long, Currency, Single, Double, Date eller Boolean går också bra, under förutsättning att värdet av variabeln med datatypen String är "lämpligt" för den andra variabelns datatyp. Variabler med de numeriska datatyperna Byte, Integer, Long, Currency, Single, Double, Date och Boolean kan även tilldelas varandra om de har "lämpliga" värden. Följande kod fungerar: Private Sub Test() Följande kod fungerar inte: Private Sub Test() I det andra exemplet har variabeln lngX ett värde som är för stort för datatypen Integer. När det gäller datatypen Date är det bra att veta att alla datum sedan år 1900 numreras med positiva heltal. Den 25 januari 2001 numreras 36916. Den dagen hade det gått 36916 dagar sedan förrförra sekelskiftet. (Så gör kalkylprogrammet Excel också, men det finns en skillnad: Visual Basic 6.0 räknar konstigt nog inte år 1900 som ett skottår, vilket Excel gör, men den 1 januari 1900 numreras 1 i Excel och 2 i Visual Basic 6.0, så det uppstår inte någon förskjutning mellan Excel och Visual Basic 6.0 efter skottdagen 1900.) Visual Basic kan hantera alla datum mellan år 100 och år 9999. När det gäller datatypen Boolean är det bra att veta att False kan bytas ut mot 0 och True kan bytas ut mot -1. Nu kommer en hemlighet om datatypen Boolean. Det är inte bara -1 som motsvarar True. Alla tal överhuvudtaget motsvarar True, utom 0, som motsvarar False! Faktum är att alla textsträngar också motsvarar True! Utom "0" och "False", som motsvarar False! Vad motsvarar 1899-12-30? Rätt gissat! False! Alla andra datum motsvarar True! Låt oss säga att vi har en variabel med datatypen Integer. Variabeln heter intX. Vi vill kontrollera om intX = 0 och meddela resultatet av kontrollen. Då kan vi kort och gott skriva If intX Then Skriv inte svårtolkad kod i Visual Basic! Skriv istället If intX <> 0 Then Vid anrop av procedurer är Visual Basic strängare. Ofta kräver Visual Basic att de variabler som den anropande proceduren skickar som argument har rätt datatyp. Då kan man bli tvungen att använda typkonverteringsfunktionerna CStr, CByte, CInt, CLng, CCur, CSng, CDbl, CDate, CBool, CDec och CVar för att undvika "type mismatch" och följande välkända felmeddelande:
Kravet på rätt datatyp gäller inte när det står ByVal eller As Any i den anropade procedurens argumentlista. As Any kan bara användas vid API-anrop. (Se avsnittet Procedurer och deras räckvidd.)
Räckvidden för variabler och konstanter beror på två saker:
Om man vill skapa en lokal variabel eller konstant, som bara kan användas i en viss procedur, så deklarerar man variabeln eller konstanten som vanligt i procedurens huvud och använder uttrycken Dim eller Const. Om man vill skapa en modulär variabel eller konstant, som kan användas i alla procedurer i en viss modul, så deklarerar man i modulens huvud och skriver Private eller Private Const. Man kan även använda de vanliga uttrycken Dim eller Const, men då syns det inte lika tydligt att räckvidden är begränsad till den aktuella modulen. Det är tydligare att skriva Private eller Private Const. Exempel: Private m_strCompany As String Ibland vill man skapa en global variabel eller konstant, som kan användas i alla moduler i hela projektet. Då deklarerar man i huvudet av en standardmodul och skriver Public eller Public Const istället för Dim eller Const. (I Visual Basic 3.0 och äldre versioner använde man inte ordet Public, utan Global. Det fungerar fortfarande, men rekommenderas inte.) Exempel: Public p_strCompany As String Man brukar hänga på ett m_ (för modular) och ett p_ (för public) framför namnet på modulära och globala variabler och konstanter. Dessa prefix rekommenderas, särskilt i större projekt med många moduler. Det är bra att kunna se på namnet vilken räckvidd som gäller. (I Visual Basic 3.0 och äldre versioner brukade man använda bokstaven g istället för p.) Globala variabler kan även deklareras i klassmoduler (se avsnittet med samma namn). Det är inte förbjudet att deklarera globala variabler i formulärmoduler, men formulärmodulens namn måste i så fall anges när variablerna används i andra moduler, vilket är en nackdel: intX = frmTestForm.p_intTestVariable Globala konstanter måste deklareras i standardmoduler. Det gäller även arrayer och variabler med egna datatyper om räckvidden ska vara global. En String med fast längd måste också deklareras i en standardmodul om variabeln ska vara global. Numreringar har inte dessa begränsningar. De kan deklareras i vilken modul som helst, även om räckvidden ska vara global. Det gäller både numreringarna själva och de variabler som använder dem som datatyp.
VARNING! I princip har globala variabler varit onödiga sedan Visual Basic 4.0, då klassmoduler började användas. Istället för att använda globala variabler kan man skapa en klass, vars egenskaper ersätter de globala variablerna. (Se avsnittet Klassmoduler.) Det har flera fördelar. Sedan skapar man en global instans av klassen, så egenskaperna kan nås från alla moduler i projektet. Ett annat alternativ är att deklarera en egen datatyp som innehåller alla globala variabler och sedan deklarera en enda global variabel med denna egna datatyp. Skriv alltså inte så här: Public p_strA As String Skriv så här istället i huvudet av en standardmodul: Private Type ExPublics Public p_Pub As ExPublics Nu slipper du hoppa fram och tillbaka med Shift+F2 och Ctrl+Shift+F2 för att kontrollera vad den och den globala variabeln heter. Så fort du skriver p_Pub följt av en punkt visas en lista över alla dina (före detta) globala variabler! Som framgår av detta exempel behöver inte en egen datatyp vara global bara för att en variabel med den egna datatypen ska vara global.
Onödig räckvidd "Excess scope" är ett vanligt misstag i Visual Basic. På svenska kan man säga "onödig räckvidd". Vad det handlar om är globala variabler som lika gärna kan vara modulära, eftersom de bara används i en enda modul, eller lokala, eftersom de bara används i en enda procedur. Programmeraren trodde kanske att variabeln skulle komma till användning i flera moduler, men glömde att kontrollera om så verkligen blev fallet. Onödig räckvidd kan försämra programmets prestanda och bör därför undvikas. Även procedurer kan ha onödig räckvidd.
Döda procedurer, variabler och konstanter Döda variabler och konstanter är variabler och konstanter som deklareras utan att användas. Naturligtvis bör de undvikas, eftersom de komplicerar koden i onödan. När det gäller döda variabler försämrar de även programmets prestanda. Döda konstanter sållas bort av kompilatorn. Det finns kanske hela procedurer som aldrig anropas i ditt projekt. Även de komplicerar koden i onödan och försämrar programmets prestanda. Att försöka hitta alla döda procedurer, variabler och konstanter i ett projekt kan vara tidsödande. Att försöka hitta alla som har onödig räckvidd är också besvärligt. Därför är det bra att det finns program som gör jobbet automatiskt, t ex Project Analyzer från Aivosto.
Inbyggda konstanter I Visual Basic finns det hundratals inbyggda konstanter för alla möjliga ändamål. Deras namn brukar börja med bokstäverna vb och deras datatyp är ofta Long eller Integer. Det finns t ex två inbyggda konstanter som heter vbYes och vbNo. Båda har datatypen Integer. Värdet av vbYes är 6. Värdet av vbNo är 7. Vad är vitsen med detta? Jo, den inbyggda funktionen MsgBox, som visar en meddelanderuta, har returvärdet 6 om användaren klickar på knappen Ja i meddelanderutan. Om användaren klickar på knappen Nej har funktionen returvärdet 7. För att slippa komma ihåg talen 6 och 7 kan man använda konstanterna vbYes och vbNo. Det finns en annan konstant som heter vbYesNo. Den används som argument i funktionen MsgBox när man vill visa en meddelanderuta med två knappar, en för Ja och en för Nej. Vill man visa en knapp för OK och en för Avbryt använder man konstanten vbOKCancel. Ett exempel: Public Function IsSmart() As Boolean Ännu smartare är att skriva så här: Public Function IsSmart() As Boolean Allra smartast är att skriva så här: Public Function IsSmart() As Boolean Man behöver inte skriva att funktionen ska returnera False om användaren klickar på Nej. Om en funktion ska ha ett returvärde med en viss datatyp och inte tilldelas något returvärde returnerar funktionen startvärdet för en variabel med samma datatyp. För en variabel med datatypen Boolean är startvärdet False. Om en funktion ska ha ett returvärde med datatypen Boolean och inte tilldelas något returvärde blir alltså konsekvensen att funktionen returnerar False.
Variablers livslängd beror på deras räckvidd. Lokala variabler förlorar sitt värde när proceduren avslutas. Om man ersätter uttrycket Dim med ordet Static behåller variabeln sitt värde när proceduren avslutas, men är fortfarande lokal. En sådan lokal variabel brukar kallas en statisk variabel. Modulära variabler förlorar sitt värde när programmet avslutas eller när man använder satsen Set frmMyForm = Nothing om den modulära variabeln har deklarerats i formulärmodulen frmMyForm. Observera att det inte räcker att ladda ur formuläret. Globala variabler förlorar aldrig sitt värde förrän programmet avslutas. Även procedurer kan förses med ordet Static framför uttrycken Function och Sub. Detta är en intressant men sällan använd finess i Visual Basic: Private Static Sub cmdTest_Click() Vad blir effekten av detta? Jo, alla lokala variabler i den aktuella proceduren blir statiska och behåller sina värden när proceduren avslutas. Man kan alltså lika gärna skriva så här: Private Sub cmdTest_Click() Statiska variabler kan användas istället för modulära variabler. Visual Basics hjälptexter påstår dock att modulära variabler ger bättre prestanda än statiska.
Från början fanns det två sorters procedurer i Visual Basic: funktioner, som anges med uttrycket Function, och subrutiner, som anges med uttrycket Sub. (Denna terminologi används inte i alla programmeringsspråk. I Pascal kallas subrutiner för procedurer, medan procedurer kallas för subprogram.) I Visual Basic 4.0 började man använda en tredje sorts procedurer, som kallas egenskapsprocedurer. (Se avsnittet Klassmoduler.) Händelseprocedurer är subrutiner som körs när en viss händelse inträffar för ett formulär eller en kontroll som man har placerat på formuläret, t ex när användaren klickar på en knapp. Liksom andra subrutiner kan händelseprocedurer anropas från andra procedurer. Det vanligaste sättet att skapa en händelseprocedur för ett formulär eller en kontroll är att dubbelklicka på formuläret eller kontrollen.
Om man t ex dubbelklickar på en knapp öppnas kodfönstret och den blinkande markören placeras i händelseproceduren för knappens standardhändelse, Click. Om denna händelseprocedur inte finns skapas automatiskt den första och sista raden i händelseproceduren. Namnet på en händelseprocedur består alltid av namnet på kontrollen och namnet på händelsen, förenade med ett understreck.
VARNING! När man skriver händelseprocedurer i Visual Basic är det viktigt att förstå vilka händelser som kan inträffa för ett formulär eller en kontroll. När händelserna inträffar är också viktigt att förstå. Det är lätt att förstå när händelsen Click inträffar, men alla händelser är inte lika självklara. Ibland måste man även veta i vilken inbördes ordning händelserna inträffar. När man t ex laddar ett formulär inträffar händelserna Initialize, Load och Activate för formuläret, i den ordningen. När man laddar ur ett formulär inträffar händelserna QueryUnload, Unload och Terminate för formuläret, i den ordningen.
Det finns en viktig skillnad mellan funktioner och subrutiner. Funktioner kan ha både argument och returvärde. Subrutiner kan bara ha argument. Man sätter argumenten inom parentes när man anropar funktioner. När man anropar subrutiner sätter man inte argumenten inom parentes. (Om man anropar subrutinen med uttrycket Call eller om subrutinen endast har ett argument tillåter Visual Basic att man sätter argumenten inom parentes när man anropar subrutinen.) Ett exempel på hur man skriver en funktion: Public Function Add(intA As Integer, Optional intB
As Integer) As Long Vad händer om man skriver lngNumber = Add(3) och utelämnar det frivilliga argumentet intB? Kraschar programmet? Nej, kom ihåg vad du läste om variablers startvärden i avsnittet Deklaration av variabler och konstanter ovan. Startvärdet för variabler med datatypen Integer är 0. Eftersom intB inte tilldelas något värde i exemplet närmast ovan gäller att intB = 0. I Visual Basic kan man även anropa procedurer så här: lngNumber = Add(intB:=7, intA:=4) Man säger att man använder namngivna argument ("named arguments" på engelska). När man använder namngivna argument kan man som synes skriva dem i vilken ordning man vill. Detta skrivsätt används mest i makron i Word och Excel. Många inbyggda funktioner och uttryck i Visual Basic tillåter inte att man använder namngivna argument. Till undantagen hör t ex funktionerna MsgBox och InputBox. Lägg märke till att man skriver ett kolon till vänster om likhetstecknet när man använder namngivna argument, precis som man gör när man tilldelar ett värde till en variabel i programmeringsspråket Pascal. Om man vill att det frivilliga argumentet intB ska få ett annat värde än 0 när argumentet utelämnas, t ex 5, kan man skriva Public Function Add(intA As Integer, Optional intB
As Integer = 5) As Long När ett frivilligt argument har datatypen Variant kan man använda funktionen IsMissing för att kontrollera om argumentet har utelämnats: Public Sub SayHello(Optional vntName As Variant) Argument med ordet Optional framför sig måste stå sist i argumentlistan. Optional kan inte användas om argumentet är en array eller en variabel med en egen datatyp. Man kan heller inte använda Optional om det finns en ParamArray bland argumenten. Funktioner kan avbrytas i förtid med satsen Exit Function, subrutiner med Exit Sub.
VARNING!
VARNING!
Sanningen om procedurernas räckvidd Om man vill skapa en global procedur, som kan anropas från alla moduler i projektet, är det nödvändigt att placera proceduren i en standardmodul eller klassmodul. (Se avsnittet Klassmoduler.) En formulärmodul duger inte, om inte formulärmodulens namn anges när man anropar proceduren från en annan modul: intX = frmTestForm.TestFunction(intArgument As Integer) Man behöver inte använda ordet Public när man skapar globala procedurer i standardmoduler och klassmoduler, men det är en god vana att ändå göra det, för tydlighets skull. Om man istället använder ordet Private begränsas räckvidden till den aktuella modulen.
Sanningen om parenteserna Det händer att man vill anropa en funktion, fast man inte är intresserad av returvärdet. Då märker man vilket snällt språk Visual Basic är! Det är bara att slopa parenteserna runt argumenten när man anropar funktionen, så slipper man ta hand om returvärdet! MsgBox "Returvärdet är 1 och det struntar vi i" Alternativt kan man använda uttrycket Call: Call MsgBox("Returvärdet är 1 och det struntar vi i") När man anropar en procedur med uttrycket Call måste man alltid sätta argumenten inom parentes och man får aldrig något returvärde, varken från funktioner eller subrutiner. Det finns inga fördelar med uttrycket Call och det finns inga tillfällen när detta uttryck måste användas. Microsoft påstår i hjälptexterna att uttrycket Call kan förbättra kodens läsbarhet. Det låter osannolikt. Eftersom uttrycket inte används konsekvent kan det snarare försämra läsbarheten.
Sanningen om ByVal och ByRef När man skapar en procedur kan man skriva ByVal eller ByRef framför vart och ett av argumenten i argumentlistan. Om man skriver ByVal kan proceduren inte påverka värdet av den variabel som den anropande proceduren skickar som argument. Så blir dock fallet om man skriver ByRef: Public Sub VisaKubiken(ByRef lngHeltal As Long) Att varken skriva ByVal eller ByRef är samma sak som att skriva ByRef. (Den som använder Pascal eller Visual Basic .NET får vänja sig vid motsatsen. I Pascal skriver man inte ByRef, utan var. Istället för ByVal skriver man ingenting. Det är bra att Visual Basic .NET har fått liknande regler.) För tydlighets skull kan man uttryckligen skriva ByRef när man avsiktligen låter en procedur påverka värdet av en variabel som den anropande proceduren skickar som argument. Läroböcker i Visual Basic 6.0 brukar missa ett undantag. Om en subrutin har exakt ett argument är det konstigt nog tillåtet att sätta parenteser runt argumentet när man anropar subrutinen utan att använda uttrycket Call. Då tror Visual Basic att man har skrivit ByVal, oavsett om man har skrivit ByRef, ByVal eller ingenting. Testa följande tre varianter, så får du se: Private Sub cmdVisaKubikenAvTre_Click() Private Sub cmdVisaKubikenAvTre_Click() Private Sub cmdVisaKubikenAvTre_Click() Läroböcker i Visual Basic 6.0 brukar även missa ett annat undantag. Om en funktion har exakt ett argument är det konstigt nog tillåtet att sätta parenteser runt argumentet när man anropar funktionen utan att ta hand om returvärdet och utan att använda uttrycket Call. Även då tror Visual Basic att man har skrivit ByVal, oavsett om man har skrivit ByRef, ByVal eller ingenting. Microsoft har aldrig rättat till dessa brister, vilket är synd. Det är inte svårt att föreställa sig hur förvirrade många nybörjare har blivit. I konsekvensens namn borde parenteser vara förbjudna vid alla anrop av subrutiner och vid alla funktionsanrop som inte tar hand om returvärdet, även om den aktuella subrutinen eller funktionen endast har ett argument. Det är god programmeringssed i Visual Basic att införa dessa förbud själv. Om man använder en array eller en variabel med en egen datatyp som argument kan man inte skriva ByVal framför. Däremot kan man skriva ByRef. Det är ju samma sak som att skriva ingenting. Att använda ByRef är ett sätt att skapa en funktion som indirekt returnerar flera värden. Om man inte är intresserad av det (och det är man för det mesta inte) har man knappast någon anledning att använda ByRef. Många har frågat sig vilket alternativ som ger bäst prestanda, ByVal eller ByRef. Visual Basics hjälptexter påstår att ByVal ger bättre prestanda. Noggranna undersökningar har dock visat att prestandaskillnaden är ytterst liten, utom när datatypen är String och variabelns värde är en lång textsträng. Då är faktiskt ByRef mycket snabbare. Om långa textsträngar inte förekommer är det bättre att hålla sig till ByVal. Det ger ingen nämnvärd prestandavinst, men det minskar risken att man av misstag påverkar värdena av den anropande procedurens variabler. Att man uttryckligen skriver ByRef istället för ingenting har ingen som helst betydelse för prestandan.
VARNING! Sådana Visual Basic-programmerare borde inte få komma i närheten av ett tangentbord, för att inte tala om sådana människor som ger en lokal variabel samma namn som en modulär variabel i samma modul, eller samma namn som en global variabel i samma projekt. Man kan undra hur deras hjärnor ser ut. Visual Basic har tyvärr inget försvar mot dessa virriga människor. Koden blir svårtolkad, men fungerar ändå. Visual Basic prioriterar alltid den lokala variabeln eller konstanten om en sådan har deklarerats. Annars tror Visual Basic att man syftar på en modulär eller global variabel om det finns en sådan med samma namn. Å andra sidan, om du vill göra din arbetsgivare beroende av dig genom att göra koden obegriplig för alla utom dig själv, så har du nu lärt dig några av de absolut bästa knepen. Om du sedan använder tillräckligt många virriga variabelnamn, tillräckligt många onödiga anrop till procedurer med lika virriga namn och krånglar till dina For-slingor och If-satser så mycket det går, så ska du se att det biter.
Att starta ett program I Visual Basic kan ett program starta på två olika sätt. Det ena sättet går ut på att man laddar ett av de formulär som ingår i projektet. Det andra sättet går ut på att man har en subrutin som heter Main i en standardmodul (en formulärmodul eller klassmodul duger inte). Denna subrutin körs när programmet startar. Eventuella formulär som ska laddas måste i så fall laddas med hjälp av koden i subrutinen Main: Public Sub Main()
Man kan välja hur programmet ska starta i listrutan Startup Object på fliken General i dialogrutan Project Properties, som visas om man klickar längst ner på menyn Project. Om man väljer Sub Main kommer programmet att köra subrutinen Main vid start. Om man väljer namnet på ett formulär kommer programmet att ladda detta formulär vid start.
Att kompilera ett program Klicka på Make... på menyn File när du vill kompilera ditt program till en färdig EXE- eller DLL-fil.
I bakgrunden sköts kompileringen av programmen c2.exe och link.exe. Se optimeringstipsen i slutet av denna lathund.
API-anrop Det är en fördel att kunna anropa procedurer i sådana DLL-filer som ingår i själva operativsystemet Windows. Då måste man först deklarera proceduren genom att använda uttrycket Declare framför Function eller Sub. Ett exempel: Public Declare Function Beep Lib "Kernel32.dll"
_ Man kan skriva detta i huvudet av en standardmodul. Filändelsen .dll kan utelämnas. Ordet Public kan också utelämnas, men bör vara med, för tydlighets skull. Att skriva i huvudet av en formulärmodul eller klassmodul går också bra, men då måste man ersätta ordet Public med Private. Därmed begränsas räckvidden till den aktuella modulen. I exemplet närmast ovan deklarerades en funktion som heter Beep. Funktionen Beep finns i filen Kernel32.dll och har två argument med datatypen Long. Argumenten kan man kalla vad man vill. I exemplet kallas de lngFrequency och lngDuration. Funktionen har ett returvärde med datatypen Long. På en annan plats i projektet kan man sedan deklarera en lokal variabel med datatypen Long, den kan t ex heta lngReturnValue, och anropa funktionen Beep genom att skriva lngReturnValue = Beep(3000, 5000) om man vill höra ett 5000 millisekunder långt pip med frekvensen 3000 Hz. Detta fungerar i Windows NT 4.0, 2000 och XP, samt i 32-bitarsversionerna av Windows Vista och 7. I Windows 95, 98 och Me hörs bara ett av standardljuden i Windows, oavsett vilka värden man ger funktionens argument. Returvärdet är ointressant, så man kan lika gärna skriva Beep 3000, 5000 Ovan beskrivna teknik kallas API-anrop. (API betyder Application Programming Interface.) Som synes kan man inte räkna med att alla API-anrop fungerar lika bra i alla versioner av Windows. Om en procedur har deklarerats med uttrycket Declare gäller ett särskilt undantag för argument med datatypen String. Även om man skriver ByVal framför argumentet kan proceduren ändå påverka värdena av de strängvariabler som anropande procedurer skickar som argument. Detta undantag beror på att strängvariabler hanteras annorlunda i programmeringsspråken C och C++, som Microsoft har använt för att skapa DLL-filerna i Windows. I Visual Basic använder man främst anrop till procedurer i filerna User32.dll, Kernel32.dll, Gdi32.dll, Shell32.dll, Advapi32.dll, Comdlg32.dll och Winmm.dll. På så sätt kan man komma åt många finesser som är inbyggda i Windows. Hur kan man veta vilka procedurer som finns i olika DLL-filer, vilka argument och returvärden procedurerna har och vad de kan användas till? Den hjälp som Microsoft erbjuder programmerare på det här området är dålig. AllAPI Network är däremot en mycket bra webbplats för dig som vill veta mera om API-anrop. Här kommer ett annat exempel. Skriv detta längst upp i en standardmodul... Public Declare Function GetLocaleInfo Lib "Kernel32"
_ Public Const LOCALE_SDECIMAL = &HE ...och detta längst ner: Public Function GetDecimalSeparator() As String Funktionen GetDecimalSeparator returnerar ett komma eller en punkt. Returvärdet beror på valet av decimaltecken i Kontrollpanelen i Windows. Med hjälp av denna funktion kan du kontrollera om användarens inmatningar är giltiga. Antag att ditt program innehåller en textruta. I textrutan får användaren skriva ett tal mellan 0,01 och 0,99. Ditt program måste kunna validera användarens inmatning, alltså kontrollera om den är giltig. Om ditt program ska klara den uppgiften måste programmet veta om decimaltecknet är komma eller punkt. I Sverige används komma. I USA används punkt. Om ditt program ska bli en storsäljare i både Sverige och USA måste programmet veta vilket decimaltecken som gäller, oavsett var programmet används. Funktionen GetLocaleInfo heter egentligen GetLocaleInfoA i filen Kernel32.dll. Som synes får funktionen ett nytt namn med hjälp av ordet Alias. När du använder ett API-anrop kan ordet Alias döpa om en procedur till vad du vill. Det finns faktiskt ett mycket enklare sätt att ta reda på decimaltecknet: Public Function GetDecimalSeparator() As String
VARNING! Public Function IsReallyNumeric(ByVal strValue As String, _ Jämförande operatorer som Like och logiska operatorer som Not förklaras i nästa avsnitt.
Här kommer ett exempel som visar hur man öppnar en webbsida eller påbörjar ett mail till en viss mailadress. Skriv detta längst upp i en standardmodul... Public Declare Function ShellExecute Lib "Shell32" Alias _ ...och detta längst ner: Public Sub NewPage(ByVal strURL As String) Public Sub NewMessage(ByVal strEmailAddress As String) Här kommer ett exempel som visar hur man laddar ner en fil. Skriv detta längst upp i en standardmodul... Public Declare Function URLDownloadToFile Lib "Urlmon" Alias _ ...och detta längst ner: Public Function DownloadFile(ByVal strURL As String, _ Funktionen DownloadFile returnerar True om nerladdningen gick bra, annars False. Om man vill skriva eller läsa i Registret, där Windows lagrar mängder av inställningar för operativsystemet och andra program, kan man använda API-anrop till funktioner i filen Advapi.dll, t ex RegQueryValueExString och RegSetValueEx.
Egna kalkylbladsfunktioner i Excel Att skapa egna kalkylbladsfunktioner i Excel är praktiskt. Här kommer ett bra exempel. Den inbyggda kalkylbladsfunktionen för veckonummer i Excel, WEEKNUM (VECKONR på svenska), är inte så lätt att använda om man vill ha svenska veckonummer. Låt oss bygga en bättre. Starta Excel, använd kortkommandot Alt+F11 för att öppna Visual Basic Editor och välj Modul (Module) på menyn Infoga (Insert). Skriv Public Function WEEKNUMSWEDEN(dteDate As Date) As Integer Stäng sedan Visual Basic Editor med samma kortkommando. Skriv nu ett datum, t ex 2010-12-24, i en cell, t ex A1, och använd formeln =WEEKNUMSWEDEN(A1) i en annan cell. Praktiskt, eller hur? Observera att du måste ange datum i Excel med ett datumformat som överensstämmer med inställningarna i Kontrollpanelen i Windows.
Makron i Excel Man kan spela in makron i Word och Excel. Sedan kan man öppna Visual Basic Editor och studera den källkod som automatiskt skapades när man spelade in makrot. Det är ett bra sätt att lära sig hur Visual Basic for Applications (VBA) kan användas i Word och Excel. En del makron är dock omöjliga att spela in, de måste skrivas för hand. Säg t ex att du behöver ett makro som tar bort alla tomma rader i vilket markerat cellområde som helst. Gör så här: Starta Excel, använd kortkommandot Alt+F11 för att öppna Visual Basic Editor och välj Modul (Module) på menyn Infoga (Insert). Skriv Public Sub DeleteBlankRows() Stäng sedan Visual Basic Editor med samma kortkommando. Nu kan du markera ett cellområde där några av raderna är tomma, men inte alla. Använd sedan kortkommandot Alt+F8 för att öppna dialogrutan Makron (Macros). Markera makrot DeleteBlankRows och klicka på knappen Kör (Run). Dina tomma rader försvinner. Makrot ovan innehåller ett trick som ofta ökar prestandan i makron i Excel. Automatiska beräkningar och skärmuppdateringar inaktiveras i början av makrot och aktiveras i slutet. Här är ett makro som skapar hyperlänkar av alla cellvärden i ett markerat cellområde: Public Sub CreateLinks() Detta makro är användbart om du har klistrat in ett lång lista av webbadresser i ett kalkylblad och snabbt vill göra alla adresserna klickbara.
VBScript Skriptspråket VBScript är en förenklad version av Visual Basic. Detta skriptspråk kan användas för att snabbt skapa små program för olika ändamål. Stöd för VBScript finns i alla versioner av Windows sedan Windows 98. VBScript förtjänar egentligen en egen lathund, men låt oss pröva ett enkelt exempel: Starta programmet Anteckningar (Notepad på engelska), som ingår i Windows. Skriv Today = Now och spara filen med filnamnet Vecka.vbs på Skrivbordet (filändelsen måste vara vbs). Dubbelklicka på filen och se vad som händer. (Om inget händer använder du förmodligen inte standardinställningarna för VBScript i Windows.)
De aritmetiska operatorerna prioriteras på samma sätt som i matematiken. Exponentiering tillämpas först. Sedan multiplikation och division. Sist addition och subtraktion. Parenteser kan därför behöva användas på samma sätt som i matematiken. Modulus betyder att man intresserar sig för restvärdet. Om man dividerar 14 med 5 blir resultatet 2 och restvärdet 4. Konkatenera, sammanfoga textsträngar, kan man även göra med +-tecknet. Det kan leda till misstag. &-tecknet rekommenderas.
Följande kod fungerar: If UCase$(strName) Like "N*" Then Följande kod fungerar inte: If UCase$(strName) = "N*" Then
De fyra logiska operatorerna Not, And, Or och Xor prioriteras i den ordningen av Visual Basic. Om de logiska, jämförande och aritmetiska operatorerna blandas i en och samma utsaga tillämpar Visual Basic de aritmetiska operatorerna först. Sedan de jämförande. Sist de logiska. Därför behövs inga parenteser i exemplen närmast ovan, om man inte vill använda...
Bitvis And, Or och Xor Ibland ser man uttryck som lngX = 3 And 5 Nybörjaren kliar sig i huvudet. Vad i hela världen är detta? Tja, det är något som kallas bitvis And. Det visar sig att resultatet blir 1. Nybörjaren kliar sig ännu mera i huvudet. Hur kan 3 "och" 5 bli 1? Rent matematiskt betyder det att man utgår från 3 och 5 i binär form, alltså 011 och 101. Sedan jämför man siffrorna steg för steg. Om båda siffrorna är 1 ger bitvis And 1, annars 0. Resultatet blir alltså 001, med andra ord 1. Man kan även använda bitvis Or och bitvis Xor, som fungerar på liknande sätt: Om båda siffrorna är 0 ger bitvis Or 0, annars 1. Om båda siffrorna är lika ger bitvis Xor 0, annars 1.
Eqv kan betraktas som en generösare variant av And. Imp kan betraktas som en generösare variant av Eqv. Om båda siffrorna är lika ger bitvis Eqv 1, annars 0. Om första siffran är 1 och andra siffran är 0 ger bitvis Imp 0, annars 1.
Slingor av typen For ... Next For lngCount = Första Talet
To Sista Talet Step Steglängd Även om det är mera svårtolkat är det tillåtet att bara skriva For lngCount = Första Talet
To Sista Talet Step Steglängd Exit For avbryter slingan i förtid. Om man utelämnar Step Steglängd blir steglängden 1. Om Steglängd är ett negativt heltal stegar man baklänges. Då måste Första Talet vara större än Sista Talet. Uttrycket Continue, som hoppar till nästa varv i slingan, har funnits länge i Java, men infördes inte i Visual Basic förrän 2005. I Visual Basic 6.0 och äldre versioner är det enkelt att åstadkomma samma sak genom att kombinera uttrycket GoTo med en radetikett som placeras i början av slingan. Det är vanligt att man använder funktionerna LBound och UBound när man låter en For-slinga bearbeta en array. Programmets prestanda påverkas inte nämnvärt om man använder dessa funktioner direkt i For-slingan. Man behöver inte skriva så här: lngLower = LBound(strMyArray) Man kan lika gärna skriva så här: For lngCount = LBound(strMyArray) To UBound(strMyArray)
Slingor av typen For Each Denna typ av slinga kan man använda för att nå alla objekt i en samling ("collection"). I Visual Basic finns det många samlingar, t ex samlingen Forms, som består av alla laddade formulär. For Each Objektvariabel In Samling Även om det är mera svårtolkat är det tillåtet att bara skriva For Each Objektvariabel In Samling Exempel: Private Sub cmdCloseAll_Click() Exit For avbryter slingan i förtid.
Slingor av typen Do ... While Do While Villkor Exit Do avbryter slingan i förtid. Man kan även skriva Do
Slingor av typen Do ... Until Do Until Villkor Exit Do avbryter slingan i förtid. Man kan även skriva Do
Slingor av typen While ... Wend While Villkor Slingor av typen While ... Wend kan inte avbrytas i förtid.
VARNING! Do While intA < 100 bör man naturligtvis skriva intB = 3 * intC så att inte beräkningen intB = 3 * intC upprepas varje varv i slingan. Varning för konkateneringar i slingor! Konkateneringar är det segaste som finns i Visual Basic. Att placera ett stort antal konkateneringar i en lång slinga kan medföra en allvarlig försämring av programmets prestanda. Undvik detta till varje pris! Den praktiska och snabba funktionen Join erbjuder ofta en bättre lösning än vanlig konkatenering med &-tecknet. Systerfunktionen Split är också mycket användbar.
Beslutsstrukturer av typen If ... Else If Villkor Then If-satser kan vara utan Else och man kan även kapsla (en del säger nästla) dem inuti varandra: If Villkor A Then Med hjälp av ordet ElseIf kan detta skrivas kortare: If Villkor A Then En del tycker att den kortare varianten är mera svårtolkad. När man använder And och Or i If-satser är det bra att veta att Visual Basic alltid evaluerar vad som står på båda sidorna om den logiska operatorn. Antag att du har en mycket snabb funktion som heter QuickFunction och en mycket långsam funktion som heter SlowFunction. Båda returnerar en Boolean. Då ger det bättre prestanda att skriva If QuickFunction = True Then än att skriva If QuickFunction = True And SlowFunction = True Then I det andra exemplet får du nämligen alltid vänta på resultatet från SlowFunction, även när QuickFunction ger resultatet False. I det första exemplet slipper du vänta på resultatet från SlowFunction när QuickFunction ger resultatet False. Man brukar säga att man kortsluter If-satsen. I Visual Basic .NET finns den nya logiska operatorn AndAlso som ger samma effekt som det första exemplet. Som komplement till Or finns OrElse.
Beslutsstrukturer av typen Select Case Select Case Variabeln Tänkbart värde kan t ex vara något av dessa alternativ: "Skåne" Observera att den enda kod som körs är koden i den första matchande Case-satsen. Om man skriver samma värde i flera Case-satser uppstår inget fel bara för det. Endast koden i den första matchande Case-satsen kommer att köras. Här skiljer sig Visual Basic från andra programmeringsspråk. Motsvarande uttryck i Java heter switch och tillåter inte samma värde i flera Case-satser. Det är inget krav att variabelns värde matchas av någon Case-sats och det är inget krav att ta med en Case Else-sats! Om man tar med en Case Else-sats måste den stå sist! Prestandatips: Placera det mest sannolika värdet i den första Case-satsen.
With Uttrycket With gör koden kortare att skriva och förbättrar programmets prestanda om man behöver ändra många egenskaper samtidigt för ett och samma objekt. Istället för att skriva frmMyForm.ScaleTop = 0 bör man skriva With frmMyForm
En lista över de vanligaste inbyggda funktionerna i Visual Basic 6.0
En lista över några vanliga uttryck i Visual Basic 6.0
I Visual Basic kan man arbeta med ASCII-filer (filer med oformaterad text) på tre olika sätt: sekventiellt, slumpmässigt och binärt. I denna lathund behandlas endast det sekventiella sättet. Det är mest användbart. Exempel på sekventiell skrivning till fil: Private Sub WriteToFile() Istället för ettan kan man använda en Integer som man tilldelar ett värde med funktionen FreeFile. Då kan man vara säker på att numret inte redan är upptaget av en annan öppen fil: Private Sub WriteToFile() Om filen C:\Mina dokument\Min fil.txt inte finns i förväg skapas den. Om den finns i förväg skrivs den över. Om mappen C:\Mina dokument inte finns i förväg uppstår ett fel. Om man vill lägga till text i slutet av en befintlig fil kan man skriva som i nästa exempel: Private Sub AppendToFile() Om man vill skapa en tom rad i filen skriver man endast Print #1, Exempel på sekventiell läsning från fil: Private Sub ReadFromFile() Variabeln strLineOne tilldelas det som står på första raden i filen och variabeln strLineTwo tilldelas det som står på andra raden. Om man inte vet hur många rader filen innehåller kan man göra en slinga: Private Sub ReadFromLongFile() Den inbyggda konstanten vbCrLf ger en radbrytning. Använd alltid denna konstant när du behöver radbrytningar i Visual Basic! EOF(1) betyder slutet av filen. LOF(1) ger totala antalet tecken i filen. Istället för Print #1 kan man skriva Write #1. Då kommer varje rad i filen att omges av citattecken, vilket kanske inte är önskvärt. Om man använder Print #1 för att skriva rekommenderar Microsoft att man använder Line Input #1 för att läsa. Om man däremot använder Write #1 för att skriva rekommenderas Input #1 för att läsa. Ovanstående metoder är dock inte särskilt effektiva om man vill läsa hela texten i en fil och presentera den i en kontroll, t ex en vanlig textruta. Då är funktionen Input mycket bättre. Ett exempel: Private Sub cmdView_Click() Textrutans egenskap MultiLine bör ha värdet True, annars hamnar all text på en enda rad. Vissa filer kan vara bättre att läsa binärt: Open "C:\Mylongfile.txt" For Binary As #1 Det kan vara bra att veta att App.Path ger sökvägen till det aktuella programmets EXE-fil. Att göra en utskrift är enkelt. Man använder objektet Printer, som är systemets standardskrivare, och uttrycket Print. Det är viktigt att avsluta med metoden EndDoc. Metoden NewPage ger en sidbrytning, metoden Line ritar linjer och rektanglar, metoden Circle ritar cirklar och ellipser och metoden PaintPicture skriver ut en bild som man har placerat i en kontroll av typen PictureBox. Objektet Printer har dessutom ett stort antal egenskaper som kan styra teckenformat och textens placering. Ett exempel: Private Sub TestPrinter()
VARNING! Private Sub TestPrinter() Uttrycket With fungerar inte tillsammans med uttrycket Print.
Innan man skapar en fil kan det vara bra att kontrollera om den redan finns. Det kan också vara bra att kontrollera om mappen finns. Dessa enkla API-anrop löser problemet: Public Declare Function PathFileExists Lib "shlwapi.dll" _ Om filen eller mappen inte finns blir returvärdet 0. Windows 98 eller senare version krävs. Windows 95 och NT 4.0 duger om man installerar Internet Explorer 4.0 eller senare version. Följande två funktioner kan också vara nyttiga. Dessa funktioner returnerar namnen på alla filer respektive undermappar i en viss mapp. Om mappen inte innehåller någon fil respektive undermapp returneras ett backslash. Eftersom returvärdena är arrayer med datatypen String krävs Visual Basic 6.0 eller Office 2000. Visual Basic 5.0 eller Office 97 duger inte. Public Function GetFiles(ByVal strPath As String) As String() Public Function GetFolders(ByVal strPath As String) As String()
Man kan kopiera och klistra in text med hjälp av objektet Clipboard och dess tre metoder Clear, SetText och GetText. Observera att man ska använda metoden Clear före metoden SetText. Så här kan man kopiera en text ... Clipboard.Clear ... och så här kan man klistra in samma text ... txtMyNewTextBox.Text = Clipboard.GetText Objektet Clipboard har även tre andra metoder: SetData, GetData och GetFormat. SetData och GetData kan användas för att kopiera och klistra in bilder. GetFormat kan användas för att undersöka vad som har kopierats eller klippts ut. Man kan även kopiera och klistra in med hjälp av API-anrop.
Man kan förhindra att programmet avbryts på grund av fel genom att göra som i följande exempel: Private Sub Test() Om man skriver On Error Resume Next fortsätter programmet på nästa rad när ett fel uppstår. Om man bara skriver On Error Resume fortsätter programmet på samma rad. Raden som orsakade felet körs alltså en gång till. Förutsättningarna har kanske ändrats efter ett antal försök och då slipper man kanske felet. Tyvärr sällsynt i verkligheten. Resume Next kan även kombineras med felhantering: Private Sub Test() Exemplet närmast ovan kan användas om du bara vill logga felet i en loggfil utan att avbryta programkörningen. Strukturerad undantagshantering ("structured exception handling") av det slag som finns i Java finns egentligen inte i Visual Basic. Detta har dock förändrats i Visual Basic .NET. Om man är finurlig kan man åstadkomma samma sak i Visual Basic 6.0: Private Sub Try() Som synes kan både GoTo och Resume kombineras med en radetikett. Enklare buggar kan upptäckas med hjälp av brytpunkter. Man kan placera en brytpunkt på en viss rad i koden genom att klicka på den gråa marginalen till vänster om raden. Brytpunkten visas som en röd punkt. Sedan startar man programkörningen, t ex med kortkommandot F5. Raden före brytpunkten kommer att köras. Sedan bryts programkörningen och man kan undersöka variablernas värden i den aktuella proceduren genom att peka på dem. Raden med brytpunkten kommer inte att köras förrän man kör vidare. Man kan ta bort brytpunkten genom att klicka på den. Om man har flera brytpunkter kan man ta bort alla på en gång med kortkommandot Ctrl+Shift+F9 eller genom att klicka på Clear All Breakpoints på menyn Debug. Det går inte att spara brytpunkter. Alla brytpunkter försvinner när man stänger projektet. Du behöver inte oroa dig för att det finns brytpunkter kvar i den kompilerade EXE-filen. Man behöver man inte städa efter sig. Det gör Visual Basic automatiskt.
Om man vill spara brytpunkter kan man använda uttrycket Stop. Med uttrycket Stop skapar man så att säga en brytpunkt i själva koden. Med uttrycket End stoppar man också programkörningen med omedelbar verkan, men till skillnad från Stop gör inte End en paus i programkörningen, utan avslutar hela programmet. Uttrycket End bör endast användas i undantagsfall. För effektiv avlusning av Visual Basic-program rekommenderas flitig användning av kortkommandona F8 och Shift+F8. Det senare är ofta bättre. Med F8 stegar man en rad i taget. Tryck på F8, så startar programkörningen och bryts omedelbart. Tryck på F8 en gång till, så körs första raden i koden. Tryck på F8 en gång till, så körs andra raden i koden. Det är bara att fortsätta trycka på F8 tills man kommer till en rad som behöver rättas. Om man istället använder kortkommandot Shift+F8 slipper man stega rad för rad i en anropad procedur. Istället körs en anropad procedur i ett enda svep. Skulle man råka slinka in i en anropad procedur med F8 och inte vill stega resten av proceduren rad för rad kan man använda kortkommandot Ctrl+Shift+F8 för att köra resten av proceduren i ett enda svep. Sedan kan man stega vidare rad för rad med F8 eller Shift+F8.
VARNING!
Locals Window och Watch Window är mycket användbara när man avlusar Visual Basic-program. I Locals Window kan man överblicka värdet av alla lokala variabler i den aktuella proceduren medan man stegar rad för rad med F8 eller Shift+F8. Dessutom visar Locals Window värdet av alla modulära och globala variabler som har deklarerats i den aktuella modulen. Gäller det en formulärmodul visas även värdet av alla egenskaper hos formuläret och alla dess kontroller. I Watch Window kan man skapa en watch (bevakning på svenska) som bryter programkörningen om och när ett visst villkor uppfylls. Alternativt kan man använda metoden Debug.Assert Villkor, som bryter programkörningen om Villkor är falskt. Med denna metod skapar man så att säga en watch i själva koden.
VARNING!
Immediate Window, som många läroböcker tjatar om, är mindre intressant. Metoden Debug.Print skriver en viss variabels värde eller resultatet av ett visst uttryck i Immediate Window, men det är ofta bättre att skriva i en loggfil om man behöver testa eller avlusa program på detta sätt. Immediate Window, Locals Window och Watch Window kan man öppna genom att klicka på respektive menyval på menyn View. Det finns en sak som man faktiskt kan använda Immediate Window till, nämligen att kontrollera värdet av en global variabel i brytläge. I Locals Window visas inte globala variabler om de inte råkar vara deklarerade i den aktuella modulen. Om p_intX är en godtycklig global variabel kan man i brytläge skriva print p_intX i Immediate Window och trycka på Enter, så visas det aktuella värdet av p_intX på nästa rad. Om operativsystemet är Windows NT 4.0, 2000, XP, Vista eller 7 kan man även logga saker och ting under rubriken Program i Loggboken (Event Log). Det fungerar endast när man kör den färdiga EXE-filen. Ett exempel: App.LogEvent "Nu skriver vi i Loggboken", vbLogEventTypeInformation Det andra argumentet kan man ge värdet vbLogEventTypeError, vbLogEventTypeWarning eller vbLogEventTypeInformation beroende på vilken ikon man vill se vid meddelandet i Loggboken.
Villkorlig kompilering Med villkorlig kompilering kan man "stänga av och sätta på" olika kodavsnitt, t ex felhantering. Det kan man även göra med hjälp av en vanlig global Boolean och vanliga If-satser, men fördelen med villkorlig kompilering är att de "avstängda" kodavsnitten inte kompileras. På så sätt minskar EXE-filens storlek. För att kunna använda villkorlig kompilering måste man deklarera en eller flera kompileringskonstanter, som kan ha värdena 0 och -1. 0 står för False och -1 står för True. Kompileringskonstanter kan deklareras i huvudet av en procedur eller modul, precis som andra lokala och modulära konstanter, men det går inte att använda orden Public och Private och det går inte att ange datatyp. Man inleder raden med ett #-tecken: #Const Catch = -1 En global kompileringskonstant kan inte deklareras i koden. Istället finns det två andra sätt. Det ena sättet är att skriva den globala kompileringskonstanten och dess värde på fliken Make i dialogrutan Project Properties, som visas om man klickar längst ner på menyn Project:
Vill man ha flera globala kompileringskonstanter skriver man ett kolon mellan varje. Det andra sättet är att kompilera vid en DOS-prompt. Ge kommandot "C:\Program\Microsoft Visual Studio\VB98\VB6.exe" om du sparade projektet i filen D:\Mina projekt\Projekt1.vbp och Visual Basic som vanligt installerades i mappen C:\Program\Microsoft Visual Studio\VB98. Om du vill se alla växlar och parametrar som man kan använda vid DOS-prompten kan du använda kommandot "C:\Program\Microsoft Visual Studio\VB98\VB6.exe" /? Om du vill testa följande exempel behöver du ett nytt projekt med ett formulär och en knapp. Klistra in koden i formulärmodulen och kör. Ändra sedan värdet av kompileringskonstanterna från -1 till 0 och kör igen. Option Explicit Som du ser skriver man även #-tecken framför If, Else, ElseIf och End If när man använder kompileringskonstanterna i koden. Objektet Err ger information om det senast inträffade felet. Detta objekt är inbyggt i Visual Basic och kan användas närsomhelst utan att först deklareras.
Med en klassmodul skapar man en klass står det i läroböckerna. Jaha, det var ju en bra förklaring! Vad betyder det i praktiken? Jo, det betyder att koden i en klassmodul kan användas i många projekt, precis som koden i en standardmodul kan användas i många moduler i samma projekt. Det är bra! Att skriva samma kod flera gånger är det värsta programmerare vet. Klassmoduler förklaras bäst med ett exempel. Öppna ett nytt projekt och välj att skapa en ActiveX DLL. Ge projektet namnet Fordon (genom att klicka längst ner på menyn Project). Klassmodulen kan få namnet Bil. Skriv sedan följande kod i klassmodulen (för tydlighets skull används svenska namn): Option Explicit Private m_dblBensinvolym As Double Public Event Motorstopp() Public Property Get Tankvolym() As Double Public Property Let Bensinvolym(ByVal dblData As Double) Public Property Get Bensinvolym() As Double Public Sub Tanka(dblPåfyllningsvolym As Double) Public Sub Kör(dblKörsträcka As Double) Private Sub Class_Initialize() Varsågod! Här har du en bil med full tank! Du kan använda klassen Bil i andra projekt om du kompilerar koden till en DLL-fil. Klassen Bil har två egenskaper (Tankvolym och Bensinvolym), två metoder (Kör och Tanka), samt två händelser (Motorstopp och Överfyllning). Egenskapen Tankvolym går endast att läsa, inte att ändra. Det är inte mycket som skiljer koden i en klassmodul från koden i standardmoduler. Subrutiner och funktioner är klassens metoder. Egenskapsprocedurer är klassens egenskaper. Händelser deklareras med uttrycket Event (för tydlighets skull kan man skriva Public Event) i huvudet av en klassmodul och triggas i procedurerna i samma klassmodul med uttrycket RaiseEvent. När du ska använda din DLL-fil i andra datorer kan du placera filen i systemmappen (C:\Windows\System32 om du kör Windows XP, Vista eller 7). Det är inget krav, men en god vana. Sedan måste DLL-filen registreras i den andra datorn. Det betyder att uppgifter om något som kallas Interface ID (IID), Class ID (CLSID) och Type Library ID (LIBID) läggs till i Registret i Windows. Om man skapar ett installationsprogram med Package and Deployment Wizard sköter installationsprogrammet registreringen av DLL-filen i den andra datorn. Package and Deployment Wizard kan skapa installationsprogram som enbart installerar en DLL-fil, om man så önskar. I datorn där man kompilerar DLL-filen registreras den automatiskt vid kompileringen, men i den andra datorn kan man bli tvungen att registrera DLL-filen manuellt. Det kan man göra med det lilla DOS-programmet regsvr32, som ingår i Windows. Skriv så här vid en DOS-prompt och tryck på Enter (om vi förutsätter att Windows installerades i mappen Windows och att DLL-filen fordon.dll finns i undermappen System32): regsvr32 c:\windows\system32\fordon.dll Om man tvärtom vill avregistrera DLL-filen kan man göra det med hjälp av växeln /u: regsvr32 /u c:\windows\system32\fordon.dll
VARNING!
Vid den första kompileringen och vid stora ändringar i koden kan du använda inställningen No Compatibility. Med denna inställning får DLL-filen nya Interface ID, Class ID och Type Library ID vid varje kompilering, även om ingenting ändras i koden mellan kompileringarna. Det kan hända att du kompilerar DLL-filen många gånger innan du är nöjd. Då är det bäst att använda inställningen Project Compatibility. Detta är standardinställningen. När du använder inställningen Project Compatibility förnyas bara Interface ID vid kompileringarna. Både No Compatibility och Project Compatibility tillåter att du fritt ändrar koden hur du vill. Det viktiga är att du ändrar till Binary Compatibility och kompilerar med denna inställning när DLL-filen görs redo för distribution. När du kompilerar med inställningen Binary Compatibility förändras varken Interface ID, Class ID eller Type Library ID. Det ger dig stora fördelar. Antag att DLL-filen distribueras och börjar användas av tusentals användare. Efter en tid upptäcker du plötsligt en liten bugg. Låt oss säga att du har råkat skriva minus istället för plus någonstans. Du blir tvungen att rätta felet i koden. Sedan blir du tvungen att kompilera DLL-filen ännu en gång. Tack vare inställningen Binary Compatibility blir det lätt att distribuera den rättade versionen. Användarna kan helt enkelt ersätta den gamla DLL-filen med den nya. Den nya DLL-filen behöver inte registreras, eftersom Interface ID, Class ID och Type Library ID är oförändrade. När du har ändrat till Binary Compatibility måste du följa vissa regler. Om du bryter mot reglerna blir du påmind vid nästa kompilering. Då blir du uppmanad att ångra ditt brott. Om du vägrar får DLL-filen nya Interface ID och du förlorar fördelarna med Binary Compatibility.
Med exponerad menas tillgänglig för andra program.
VARNING! Single betyder att en ny instans av ActiveX-komponenten skapas för varje nytt objekt som skapas. Global betyder att andra program kan anropa klassens metoder och egenskaper som om de vore inbyggda i Visual Basic, vilket inte enbart är en fördel, eftersom koden samtidigt blir mera svårtolkad. Private betyder att andra program varken kan se klassen eller skapa objekt av klassen. Denna inställning är lämplig för klasser som bara ska betjäna andra klasser i samma ActiveX-komponent. PublicNotCreatable betyder att andra program kan se klassen, men inte skapa objekt av klassen. I vissa fall är det bättre att den saken sköts av en annan klass i samma ActiveX-komponent.
Nu ska du få lön för mödan. Öppna ett nytt projekt, välj References... på menyn Project och sätt en bock på rätt rad ...
... så får du tillgång till klassen Bil genom att t ex skriva Public WithEvents Kärran As Bil i huvudet av en formulärmodul eller klassmodul i det nya projektet. Ordet WithEvents kan utelämnas. Om ordet WithEvents utelämnas kan man även skriva i huvudet av en standardmodul, men då får man inte tillgång till händelserna Motorstopp och Överfyllning. När du behöver en ny bil kan du skriva Set Kärran = New Bil och köra en sväng på stan: Kärran.Kör 50 Man kan skriva Set Kärran = Nothing när man inte behöver bilen mera. Det är en god vana att alltid göra så med en objektvariabel i Visual Basic när man inte behöver den mera. På så sätt kan man omedelbart frigöra en del av det arbetsminne som objektvariabeln ockuperar. Dessutom kan man på detta sätt ange exakt när klassmodulens händelse Terminate ska äga rum. Naturligtvis kan man skapa flera klassmoduler i projektet Fordon ovan. Man kan t ex skapa en klassmodul som heter Cykel, en som heter Moped osv. Om man vill att en procedur ska vara tillgänglig i alla moduler i projektet Fordon, men inte tillgänglig för andra program, kan man använda ordet Friend istället för Public. Ordet Friend används bara när man deklarerar procedurer i klassmoduler, inte när man deklarerar variabler och konstanter. Kom ihåg att en konstant, array, variabel med egen datatyp eller string med fast längd måste deklareras i en standardmodul om räckvidden ska vara global. En klassmodul eller formulärmodul duger inte. Glöm inte att skriva ordet Public först. Public Const p_intBonus As Integer = 500
VARNING FÖR FATTIGMANS-DLL:ER! Det finns programmerare som har en ful ovana. De skapar ett antal lösa moduler som inte ingår i något särskilt projekt. Sedan låter de flera projekt dela på dessa lösa moduler. Ett projekt kan på så sätt innehålla moduler som har sparats i helt andra mappar än den förväntade mappen. Du kan själv föreställa dig vad som händer när man ändrar en sådan modul på ett sätt som passar det ena projektet men inte det andra. Fattigmans-DLL:er är vad det är. Ett bra sätt att skapa oreda i stora lösningar.
Samlingsklasser En samlingsklass är en samling som alla andra samlingar. (Se avsnittet Arrayer, egna datatyper och numreringar.) Skillnaden är att medlemmarna är objekt av en viss klass och att man själv kan bestämma hur metoderna Add och Remove ska fungera. Man kan t ex kräva att vissa villkor ska vara uppfyllda när man lägger till eller tar bort en medlem. Här är ett exempel på en enkel klass. Vi kan kalla den Player. Precis som i exemplet ovan skriver man denna kod i en egen klassmodul. Option Explicit Public Sub AddGoal() Public Sub SubtractGoal() Public Property Let Number(lngData As Long) Public Property Get Number() As Long Public Property Let FirstName(strData As String) Public Property Get FirstName() As String Public Property Let LastName(strData As String) Public Property Get LastName() As String Public Property Get Goals() As Long
Här är samlingsklassen. Vi kan kalla den Team. Denna kod skriver man också i en egen klassmodul. Option Explicit Public Function Add(Number As Long, FirstName As String, _ Public Property Get Item(vntIndexKey As Variant) As Player Public Sub Remove(vntIndexKey As Variant) Public Property Get Count() As Long Public Sub Clear() Public Property Get NewEnum() As IUnknown Private Sub Class_Initialize() Private Sub Class_Terminate() Som synes bygger samlingsklassen på en modulär samling. Namnet är förstås valfritt. I detta exempel heter den m_Col. Metoden Clear finns inte i vanliga samlingar. Den kan användas för att ta bort alla medlemmar i samlingsklassen på en gång. Metoden NewEnum innehåller en del hokus pokus som inte är vanlig Visual Basic-kod. Den första röda raden, den med -4, gör det möjligt att använda slingor av typen For Each. Fråga inte vad -4 betyder. Det vet nog bara ett skelett i Microsofts källare. Den andra röda raden, den med "40", döljer metoden NewEnum från IntelliSense-listorna. Denna rad är frivillig och har ingen effekt i en klassmodul i Word, Excel eller något annat Office-program. Om man inte vill skriva de röda raderna för hand kan man använda dialogrutan Procedure Attributes. Den visas när man klickar på Procedure Attributes... på menyn Tools. Välj NewEnum som Name, skriv -4 som Procedure ID och bocka för Hide this member. Dessa inställningar görs automatiskt om man låter Class Builder Utility skapa samlingsklassens kod. Class Builder Utility är ett Add-In som man kan lägga till på menyn Add-Ins med hjälp av Add-In Manager på samma meny. Om man skriver de röda raderna för hand måste man spara, stänga och öppna projektet på nytt innan klassmodulen kan användas. Då blir de röda raderna osynliga.
I Word, Excel och de andra Office-programmen saknas dialogrutan Procedure Attributes. Man skriver den första röda raden för hand. Den andra röda raden kan man strunta i, för den har som sagt ingen effekt i Office-programmen. Sedan måste man i tur och ordning exportera, ta bort och importera klassmodulen för att den ska fungera. Då blir den röda raden osynlig. Knepigt, men det fungerar.
Om man använder DAO (Data Access Objects) kan man skapa databaser av samma typ som används i Microsoft Access. Databasmotorn heter Microsoft Jet. Namnet är något missvisande, för Jet är inte världens snabbaste databasmotor, men den duger bra för mindre databaser som endast har ett fåtal samtidiga användare. För att kunna använda DAO måste man skapa en referens i dialogrutan References, helst till den senaste versionen Microsoft DAO 3.6. Klicka på References... på menyn Project och sätt en bock på rätt rad:
DAO är en teknik som började användas 1993 i Visual Basic 3.0 (även om den inte kallades DAO förrän i Visual Basic 4.0) och har visst stöd för SQL (Structured Query Language) och transaktionshantering. Om man använder DAO kan man även koppla sitt program till andra databaser med hjälp av ODBC (Open Database Connectivity). När Visual Basic 6.0 lanserades 1998 var en av de största nyheterna ADO (ActiveX Data Objects), som är ett annat sätt att hantera databaser i Visual Basic. Man använder inte ADO för att skapa nya databaser, utan för att koppla ett program till redan befintliga databaser. Det är å andra sidan ADO mycket bra på. Följande exempel skapar en databas med hjälp av DAO och sparar den i filen C:\Medlem.mdb. Databasen har endast en tabell och den heter Medlemmar. Tabellen Medlemmar har tre kolumner: Efternamn, Förnamn och Telefon. För tydlighets skull använder vi svenska namn ännu en gång, även om man egentligen bör hålla sig till engelska. Private Sub cmdMakeMyDatabase_Click() Naturligtvis innehåller DAO mycket mer än detta enkla exempel. Så här ser objektmodellen ut i DAO 3.6:
Objektet Workspace styr transaktionshanteringen. Metoderna BeginTrans, CommitTrans och Rollback påverkar alla databaser inom samma Workspace.
Några användbara teckenkoder
från ANSI-tabellen Dessa teckenkoder kan du använda för att skriva ovanliga tecken i Visual Basic, inte bara i koden, utan även på knappar, etiketter och andra kontroller.
Om du är ute efter något annat tecken är det bra att använda ordbehandlingsprogrammet Word. Klicka på Symbol... på menyn Infoga i Word, så kan du infoga mängder av ovanliga tecken, som du sedan kan kopiera och klistra in i Visual Basic. Det är bra att veta att funktionen Chr(x) ger följande resultat vid olika värden på talet x:
Använd alltid konstanten vbCrLf (motsvarar Chr(13) & Chr(10)) för att göra en radbrytning programmatiskt.
Till sist några tips: För att kunna köra program som har kompilerats i Visual Basic 6.0 (utan några extra komponenter eller referenser) behöver man filen MSVBVM60.DLL. Som tur är ingår denna fil i Windows Me, 2000, XP, Vista och 7. Den ingår även i Windows Server 2003, 2008 och 2008 R2. De flesta användare kan alltså köra EXE-filen fristående. Dock inte användare som kör Windows 98 eller äldre versioner, om de inte har skaffat sig MSVBVM60.DLL på något annat sätt, t ex här. För att kunna köra program som har kompilerats i Visual Basic 5.0 (utan några extra komponenter eller referenser) behöver man filen MSVBVM50.DLL. Den ingår i Windows 98, Me, 2000 och XP, men inte i Windows Vista och 7. Skriptspråket VBScript använder filen SCRRUN.DLL. I dialogrutan References (som visas när man klickar på References... på menyn Project) kallas den Microsoft Scripting Runtime. En referens till denna fil ger ditt program tillgång till objektet Dictionary (en förbättrad variant av objektet Collection) och objektet FileSystemObject (ett bättre sätt att hantera filer och mappar). En referens till Windows Script Host Object Model (filen heter WSHOM.OCX) ger ditt program möjlighet att skapa genvägar och hantera Registret i Windows på ett enklare sätt. SCRRUN.DLL och WSHOM.OCX ingår i Windows 2000 och senare versioner. Vissa avancerade tekniker beskrivs inte i detalj i denna lathund. Det kan vara lärorikt att pröva dessa tekniker på egen hand. När du har tränat ett tag på API-anrop kan du testa en teknik som kallas subclassing. Då använder man API-anrop för att påverka sådana egenskaper hos ett formulär eller en kontroll som i vanliga fall inte kan påverkas. Man kan t ex ändra textfärgen i en listruta eller skapa ett formulär med runda hörn. Hooking är en teknik som kan användas när man vill påverka andra program, t ex vad som ska hända när man trycker på en viss tangent eller högerklickar med musen i Windows eller vilket program som helst. Callback-funktioner och ActiveX EXE-projekt kan användas för att skapa Visual Basic-program som ger sken av att göra flera saker samtidigt. I Visual Basic .NET bjuder Microsoft på fullt stöd för trådar ("threads"), vilket är mycket bättre. Det bästa med ActiveX EXE-projekt är att man kan skapa samverkande EXE-filer som anropar och utväxlar data med varandra. I Visual Basic 6.0 bör du lära dig att använda dessa tre Add-Ins på menyn Add-Ins: Package and Deployment Wizard, ActiveX Control Interface Wizard och Class Builder Utility. Om du saknar någon av dem väljer du Add-In Manager... på samma meny. Med Package and Deployment Wizard kan du lätt skapa installationsprogram. Med ActiveX Control Interface Wizard kan du snabbare bygga ActiveX-kontroller. När du har tränat ett tag på det kan du läsa om objektet PropertyBag och hur det fungerar. Med Class Builder Utility kan du lätt bygga klasser och samlingsklasser utan att skriva kod. Det kan verkligen effektivisera din programmering i Visual Basic! Arv ("inheritance"), åsidosättning ("overriding") och överlagring ("overloading") är viktiga begrepp i andra objektorienterade programmeringsspråk, t ex Java. Dessa begrepp finns inte i Visual Basic, men däremot i Visual Basic .NET. När du har lärt dig att bygga klassmoduler kan du lära dig uttrycket Implements, som ger tillgång till gränssnitt. Ett gränssnitt ("interface" på engelska) är helt enkelt en klassmodul i vilken man har deklarerat ett antal globala variabler och procedurer utan att skriva någon kod i procedurerna. I andra klassmoduler kan man sedan använda uttrycket Implements för att skapa olika varianter av samma klass. Ett gränssnitt är en klass som andra klasser kan ärva från, den enda form av arv som finns i Visual Basic 6.0. Till sist några prestandatips. Öppna dialogrutan med det aktuella projektets egenskaper genom att klicka längst ner på menyn Project. Välj fliken Compile. Se till att du har valt Compile to Native Code och Optimize for Fast Code. Alternativet till native code, P-Code, betyder pseudo code. P-Code är varken källkod eller kompilerad kod, utan ett mellanting. När man väljer P-Code brukar kompileringen gå lite snabbare och EXE-filen brukar bli lite mindre, men det färdiga programmet får sämre prestanda. Därför är native code ett bättre val. Detta alternativ finns i Visual Basic 5.0 och 6.0, men inte i äldre versioner.
Om man har valt Compile to Native Code kan man förbättra prestandan ytterligare genom att välja Favor Pentium Pro, under förutsättning att användarna har en Pentium Pro, Pentium II eller ännu bättre processor (en rimlig förutsättning idag). Klicka sedan på knappen Advanced Optimizations..., så ser du denna dialogruta:
Alla sex alternativen kan förbättra det färdiga programmets prestanda. Det översta alternativet, Assume No Aliasing, får du inte bocka för om du
Är du säker på att ditt program inte försöker tilldela ett otillåtet värde till ett arrayindex eller en heltalsvariabel (det bör du vara säker på om du har programmerat ordentligt) kan du tjäna på att bocka för Remove Array Bounds Check och Remove Integer Overflow Check. Ett program som använder arrayer i stor omfattning kan bli mycket snabbare då. Om ditt program gör många räkneoperationer med decimaltal kan du även tjäna på att bocka för Remove Floating Point Error Checks och Allow Unrounded Floating Point Operations. Det förutsätter att ditt program inte försöker tilldela otillåtna värden till variabler med datatyperna Single och Double. Det förutsätter också att det inte blir några avrundningsfel när värdena av två sådana variabler jämförs. Det sista optimeringsalternativet, Remove Safe Pentium FDIV Checks, kan du bocka för om ingen kör det färdiga programmet i en dator med en av de felaktiga 60 MHz-processorerna som såldes under 1994. Dessa processorer fick problem när de skulle dividera stora heltal med varandra och kunde t ex påstå att 4 195 835 - 3 145 727 * 4 195 835 / 3 145 727 är 256 istället för 0. Om du talar om för användarna att en Pentium II-processor är ett minimikrav är du på den säkra sidan.
Lycka till med programmeringen!
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||