|
Kommunikation med makroer
Meddelelsesboks
Med et par enkelte undtagelser, har de makroer, jeg indtil nu har brugt som eksempler, gjort deres arbejde uden i øvrigt at involvere brugerne, når de først er sat i gang. Imidlertid er der ofte behov for, dels at give input til makroen, dels at makroen skal kunne give informationer til brugeren. Dette kan gøres ved hjælp af en såkaldt brugerdefineret formular (Userform) eller ved hjælp af Excels egne, indbyggede dialogbokse, hvilket jeg vender tilbage til ved en senere lejlighed. I først omgang vil jeg se på to indbyggede funktioner i Excel, nemlig Meddelelsesboks og Inputboks. Ved hjælp af den første kan makroen sende beskeder til brugeren, som kan svare på dem, ved at klikke på knapper. Ved hjælp af den anden, kan makroen bede brugeren om input.
MeddelelsesboksEn meddelelsesboks er en boks, hvor makroen kan skrive meddelelses til brugeren. Denne kan så svare ved at klikke på en knap. Kodeordet for at vise en meddelelsesboks er MsgBox. Vi har allerede set eksempler på brugen af denne, fx i HelloWorld makroen.
Sub
HelloWorld()
Koden viser en meddelelsesboks som nedenstående:
Boksen er helt standard, dvs Titellinjen indeholder "Microsoft Excel" og der er en luk-knap og en OK-knap. Dette er imidlertid ikke altid nok, til at skabe en tilstrækkelig dialog mellem bruger og makro. Antag fx at du skal lave en makro, der kan udskrive et bestemt celle område i et regneark. Inden makroen udskriver, skal brugeren tage stilling til, om han ønsker dette eller ej. Dette kan man spørge om med følgende kodelinje:
MsgBox "Du har anmodet om udskrift området B1:D5. Ønsker du det?", vbYesNo + vbQuestion
Hermed styres, hvilke knapper og ikoner, der anvendes i dialogboksen (se oversigten nedenfor). vbYesNo anbringer to knapper, Ja g Nej, i dialogboksen mens vbQuestion anbringer taleboblen med spørgsmålstegnet.
Problemet med den ovenstående kode er, at den godt nok viser dialogboksen, men ikke ved, hvad den skal gøre med svaret. Det skal vi have gjort noget ved. Samtidigt vil vi lige dele teksten op i to linjer i stedet for én.
Dim bytAns As Byte bytAns = MsgBox("Du har anmodet om udskrift området B1:D5." & vbCrLf & "Ønsker du det?", vbYesNo + vbQuestion)
Resultatet bliver nu
vbCrLf er en konstant der indsætter et linjeskift. CrLf står for Carriage Return, Line Feed (og stammer tilbage fra dengang printere virkede som skrivemaskiner: "Vogn retur, Ny linie"). Det andet, der sker, er, at variablen bytAns nu bliver brugt til at gemme den knap, vi trykker på. Denne variabel kan vi så senere i koden teste på, hvor at afgøre hvad der skal ske.
Hvilke muligheder har vi så, når vi skal opbygge vores meddelelsesboks? For det første kan vi altså have en prompt (meddelelsestekst). Denne kan også opbygges så den både består af fast tekst og variabel information, fx
bytAns = MsgBox("Du har anmodet om udskrift området B1:D5 i filen " & _ ActiveWorkbook.Name & vbCrLf & " Ønsker du det?", vbYesNo + vbQuestion)
Her afbrydes teksten efter ordet "filen" for at give plads til at navnet på den aktive projektmappefil indsættes. Det sker ved hjælp af ActiveWorkbook.Name. Derefter fortsættes teksten igen. &-tegnet bruges til at sammenkæde flere tekster, eller tekster med variabler, variabler med hinanden og så videre. Læg mærke til at teksterne her, som alle andre steder i VBA anbringes i anførselstegn. Koden er delt over to linjer, men da den afsluttes med en Underscore (_) i den første linje, opfatter VBA det hele som en lang linje. På denne måde kan man gøre sin kode mere overskuelig og dermed lettere at læse.
For at sætte knapper har man flere forskellige muligheder. I stedet for at skrive konstantnavnet for knapperne og ikonerne kan man bruge en talværdi for samme knap og ikon (vbyesNo og vbQuestion betragtes som en såkaldt interne konstanter (intrinsic constants), som man ikke selv erklærer, det er allerede gjort i VBA).
bytAns = MsgBox("Du har anmodet om udskrift området B1:D5 i filen " & _ ActiveWorkbook.Name & vbCrLf & " Ønsker du det?", 4 + 32)
Eller bare
bytAns = MsgBox("Du har anmodet om udskrift området B1:D5 i filen " & _ ActiveWorkbook.Name & vbCrLf & " Ønsker du det?", 36)
Knappernes talværdier er indrettet på en sådan måde, at der ikke er to kombinationer, der giver samme sum. Selv foretrækker jeg at bruge knappernes navne. Selv om det er længere at skrive, gør det koden meget nemmere at læse. For hvad er det egentlig, det betyder, hvis der står: 528707? Faktisk ville boksen så se således ud:
Hele argumentet som udfyldes efter promptteksen kaldes "buttons", og der kan man bruge følgende værdier:
Det er vigtigt at huske, at der kun kan vælges en værdi fra hver af grupperne 1, 2, 3 og 4, mens der kan vælges flere værdier fra gruppe 5. Rækkefølgen der vælges i er ligegyldig. vbYesNo + vbQuestion er det samme som vbQuestion + 4. Det er altså også muligt at kombinere tal og konstantnavne.
Efter "button" følger argumentet "Title", hvor man kan skrive en "overskrift" som vises i meddelelsesboksens titellinje.
bytAns = MsgBox("Du har anmodet om udskrift området B1:D5 i filen " & _ ActiveWorkbook.Name & vbCrLf & " Ønsker du det?", vbYesNo + vbQuestion, "Bekræft udskrift")
Læg mærke til at her, som alle andre steder i VBA adskilles argumenter af komma, ikke som man er vant til i en dansk Excel, af semikolon.
Sidst i funktionen, kan man angive yderligere to argumenter, nemlig navnet på en eventuel hjælpefil og navnet på et kontekstnummer. Disse argumenter er kun interessante, hvis man lave sin egen hjælpefunktion, og det gør vi ikke i nogen af disse artikler, idet det kræver særlige programmer, som ikke er en del af den almindelige officepakke.
Den ovenstående kode giver nu denne boks:
Når brugeren klikker på en knap, returner meddelelsesboksen en tilhørende værdi til makroen. I vores tilfælde gemmes denne værdi i variablen bytAns, og herfra kan vi så hente den efter behov. Også returværdierne er konstanter, der repræsenterer en given værdi. Værdierne, der returneres er følgende
Hvis Luk-knappen er tilgængelig, og der klikkes på den, returner den værdien 2, svarende til Annuller med mindre der kun er en OK-knap i meddelelsesboksen. I så fald returner luk-knappen værdien 1, svarende til OK.
Nu kan vi altså lave en meddelelsesboks, og ved hjælp af betinget logik kan vi teste på, hvilken knap, der blev klikket på. Betinget logik beskrives nærmere i næste artikel, men her er et lille eksempel
Sub UdskrivOmraade() ' Denne makro udskriver et forudvalgt område (B1:D5)i det aktive ark. ' Udskriften skal bekræftes i en meddelelsesboks. Dim bytAns As Long
bytAns = MsgBox("Du har anmodet om udskrift området B1:D5 i filen " & _ ActiveWorkbook.Name & vbCrLf & " Ønsker du det?", vbYesNo + vbQuestion, _ "Bekræft udskrift")
If bytAns = vbYes Then Range("b1:d5").PrintOut Copies:=1, Collate:=True Else Exit Sub End If End Sub
Koden tester på, hvilken knap, der klikkes på og er det Ja udskrives området. Ellers afsluttes koden uden at der udskrives noget.
InputboksEn inputboks giver brugeren mulighed for at "skrive" noget til makroen. Der er to måder at lave inputbokse på, en funktion og en såkaldt metode. De ligner hinanden meget, men der er dog visse markante forskelle, selv om de bruges til samme formål.
Funktionen InputBox Nøgleordet her er InputBox! Funktionen viser en boks, med en rude, hvor brugeren kan skrive et input til makroen.
strAns = InputBox("Tast dit navn")
giver denne boks (svaret gemmes i strAns
I en InputBox er knapperne altid de samme, nemlig OK og Annuller og det kan ikke ændres. Det man kan styre er en Titel som i MsgBox, en standardværdi, placeringen af boksen, samt hjælpefil og kontekstid som i meddelelsesbokse. Koden til Inputboks kunne se således ud:
strAns = InputBox("Tast dit navn", "Angiv navn", "Jensen", 1700, 1000)
og det giver denne boks
placeret 1700 pixels fra skærmens venstre og 1000 pixels fra skærmens øverste kant. "Jensen" er en standardværdi, som foreslås, hver gang dialogboksen åbnes. Også i inputbokse kan linjerne brydes op, kombineres med variable eller lignende.
Se fx denne kode:
strAns = InputBox("Tast dit navn, hvis det ikke er Jensen eller står i celle A1" _ & vbCrLf & "Er det Jensen står det allerede i boksen. Står det i A1 hedder du " _ & Range("A1") & " og så hentes det automatisk", _ "Angiv navn", "Jensen", 1700, 1000)
Og dens resultat
Den ser lidt mærkeligt ud hvis A1 er tom, men det kan man kode sig ud af J.
Vær opmærksom på erklæringen af dine variable til at gemme input i. Har du fx erklæret en variabel som Integer (heltal) og brugeren taster en tekst, vil koden fejle, med mindre du indbygger fejlhåndtering i den. Det kan være nemmere at erklære variablerne som Variant (der jo kan rumme alt), og så bagefter teste om det indtastede er rigtigt med noget betinget logik. Har man fx
Dim intAns As Integer
intAns = InputBox("Tast et tal", _ "Angiv tal", 1000, 1700, 1000)
og brugeren taster Jensen i stedet for et tal, vises:
og brugeren bringes til kodearket, hvilket ikke særligt elegant!
En løsning kunne være
Dim intAns As Integer
On Error GoTo fejl: intAns = InputBox("Tast et tal", _ "Angiv tal", 1000, 1700, 1000) fejl: If Err.Number = 13 Then MsgBox "Du skal indtaste et tal - prøv igen" End If
Jeg vender tilbage til logiske strukturer i næste artikel og meget mere om fejlhåndtering i en senere.
Resultatet af inputboksen kan så bruges i den videre kode, fx dette geniale program. Læg mærke til de to kommaer lige efter hinanden i inputboksens definition. Det indikerer, at der er et tomt argument, i dette tilfælde standardværdien. Tomme, valgfri argumenter skal altid angives på denne måde, med mindre de står sidst i funktionen. I så fald kan de udelades.
Sub InpBox() ' Beder om et navn og siger God morgen
Dim varAns As Variant
varAns = InputBox("Indtast dit navn", "Personlig hilsen", , 1700, 1000) MsgBox ("God morgen " & varAns) End Sub
Der virker således
Når navnet udfyldes og der klikkes OK, vises
eller hvad man nu har tastet.
Et spørgsmål, som ofte stilles er, om man selv kan bestemme størrelsen på Meddelsesbokse og Inputbokse, og det kan der svares et klart Nej til. De har den størrelse de nu har – eller tildeles af systemet.
En metode er en slags handling, der er knyttet til et bestemt objekt, og som kan "gøre" noget ved dette objekt. Jeg vender tilbage til objekter og metoder i en senere artikel, så her bare en kort introduktion.
Et objekt er en enhed, fx et ark, en projektmappe, et område i et ark, en værktøjslinje osv. Objekter kan have egenskaber, et ark har fx Egenskaben Name, der indeholder arkets navn. Egenskaber kan aflæses og tildeles.
strNavn = Sheets(1).Name Sheets(1).Name = "Jan"
vil give aflæse navnet på det første ark i mappen, gemme det i variablen strNavn og give arket navnet Jan.
Objekter kan altså også have metoder. Delete er fx en metode til objektet Sheets (Ark).
Sheets(1).Delete
vil således slette det første ark i mappen.
Man kan forklare objekter, egenskaber og metoder med at objekter er programmeringssprogets navneord, egenskaber er tillægsordene og metoder er udsagnsord.
Metoden InputBox er altså en metode, og den tilhører objektet Excel. Den skal altså angives med objektnavnet først, på samme måde som Delete ovenfor. Nu skriver man ikke Excel, ligesom man ikke skriver Ark1. I stedet skriver man Application. Altså fx
varAns = Application.InputBox("Indtast dit lykketal", "Vælg et lykketal", , , , , , 1)
De første argumenter er Prompttekst og Titel. Dernæst kommer et antal udeladte argumenter, Standardværdi, Placering fra venstre kant, Placering fra toppen, Hjælpefil, KontekstId. Det sidste argument, er det, der adskiller metoden InputBox fra funktionen InputBox. I dette argument, Type, kan man nemlig fortælle hvilke(n) type data, man vil tillade. I eksemplet ovenfor repræsenter 1-tallet, at vi kun tillader tal. Her vil metoden selv, "brokke sig" hvis vi taster noget andet, og vi kan derfor spare noget kode til fejlkontrol. Undlader man at angive en type, sættes denne automatisk til tekst.
Der kan vælges mellem følgende datatyper:
Også her kan tallene lægges sammen. Skriver man 3 tillades både tal og tekst. I så fald skal modtagervariablen naturligvis være erklæret så den kan rumme begge dele. Koden ovenfor vil vise
og taster jeg så "Jan" vises
uden at jeg behøver at foretage mig yderligere.
Bortset fra denne forskel benyttes Funktionen InputBox og Metoden InputBox på samme måde.
I Funktionen InputBox og Metoden InputBox har man muligheden for at klikke på Annuller eller lukke på Luk-knappen. I begge tilfælde returner boksen en tom tekststreng. Skal man derfor teste for, om der er klikket på en af disse knapper kan man fx bruge:
Sub ipbox() ' Beder om et navn og siger God morgen
Dim varAns As Variant
varAns = InputBox("Indtast dit navn", _ "Personlig hilsen", , 1700, 1000) If varAns = "" Then Exit Sub Else MsgBox ("God morgen " & varAns) End If End Sub
Hvis der klikkes på luk-knap eller Annuller, forlades koden, uden at der sker yderligere.
Navngivne argumenterDet kan måske være svært at huske de forskelle typer eller rækkefølgen af argumenterne. Hvor mange kommaer var det lige, der skulle med før 1-tallet. I stedet kan man så anvende navngivne argumenter, fx
varAns = Application.InputBox("Indtast et tal", Type:=4)
I så fald behøver man ikke sætte kommaerne eller holde rede på rækkefølgen:
varAns = Application.InputBox(Title:="Lykkenummer", Type:=4, Prompt:="Indtast et tal")
vil virke glimrende. Dette gælder både for funktionen, metoden og i øvrigt også for funktionen MsgBox og alle andre funktioner i VBA.
MsgBox Buttons:=vbOKOnly + vbCritical, Title:="Lykkenummer", Prompt:="Dit lykkenummer er 17,04"
Her gælder det om at finde den syntaks, som passer bedst til den enkelte.
- Til top - |