Kommunikation med makroer

Meddelelsesboks
Inputboks (Funktionen InputBox)
Metoden InputBox
Annuller i en InputBox
Navngivne argumenter

 

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.

 

Meddelelsesboks

En 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()
' Dette er min første makro
    MsgBox "Hello World"
End Sub

 

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:

 

Gruppe

Konstantnavn

Talværdi

Forklaring

1

vbOkOnly

0

Kun OK knappen vises. Dette er standard hvis man ikke skriver noget.

vbOKCancel

1

Knapperne OK og Annuller vises.

vbAbortRetryIgnore

2

Viser knapperne Afbryd, Prøv igen og Ignorer.

vbYesNoCancel

3

Viser knapperne Ja, Nej og Annuller

vbYesNo

4

Viser knapperne Ja og Nej

vbRetryCancel

5

Viser knapperne Prøv igen og Annuller

2

vbCritical

16

Viser ikonen Kritisk. (Hvis kryds på rød baggrund)

vbQuestion

32

Viser ikonen Advarselspørgsmål (taleboble med blåt spørgsmålstegn)

vbExclamation

48

Viser ikonen Advarselsmeddelelse (gul trekant med sort udråbstegn)

vbInformation

64

Viser ikonen Informationsmeddelelse (taleboble med blåt I)

3

vbDefaultButton1

0

Den første knap er den standardknap, der aktiveres ved tryk på Enter.

vbDefaultButton2

256

Den anden knap er den standardknap, der aktiveres ved tryk på Enter.

vbDefaultButton3

512

Den tredje knap er den standardknap, der aktiveres ved tryk på Enter.

vbDefaultButton4

768

Den fjerde knap er den standardknap, der aktiveres ved tryk på Enter.

4

vbApplicationModal

0

Arbejdet i programmet stoppes indtil brugeren har svaret på meddelelsesboksen.

vbSystemModal

4096

Arbejdet i alle programmer stoppes indtil brugeren har svaret på meddelelsesboksen.

5

vbMsgBoxHelpButton

16384

Der tilføjes en hjælpeknap til meddelelsesboksen.

vbMsgBoxSetForeground

65536

Meddelelsesboksen placeres som et vindue i forgrunden. Den vil også vises i forgrund, hvis man skifter til andre programmer.

vbMsgBoxRight

524288

Teksten i meddelelsesboksen højrestilles.

vbMsgBoxRtlReadin

1048576

Teksten vises var højre mod venstre på hebraiske og arabiske systemer.

 

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

 

Knap

Konstantnavn

Værdi

OK

vbOKOnly

1

Annuller

vbCancel

2

Afbryd

vbAbort

3

Prøv igen

vbRetry

4

Ignorer

vbIgnore

5

Ja

vbYes

6

Nej

vbNo

7

 

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.

 

- Til top - 

Inputboks

En 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.

 

- Til top -

 

Metoden Inputbox

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:

 

Værdi

Tillader

0

Formler

1

Tal

2

Tekst

4

Logiske værdier (SAND, FALSK)

8

Cellereference

16

Fejlværdi

64

Datatabel med værdier

 

 

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.

 

- Til top -

 

Et klik på Annuller

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.

 

- Til top -

Navngivne argumenter

Det 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 -
- Tilbage til Programmering -
- Tilbage til makroer -
- Tilbage til Excel -