Hændelser

Auto-hændelser
Nøgleordet On
Workbook-hændelser
Worksheet-hændelser


I dette afsnit skal jeg fortælle lidt om hændelsesprogrammering. Selv om hændelsesprogrammering er et meget væsentligt element, når man skal automatisere sine regneark, er det noget, som de fleste bøger om VBA programmering går forholdsvist let hen over. Men lad mig starte med at definere to begreber, nemlig hændelser og hændelsesprocedurer.

 

En hændelse er noget, der indtræffer i fx skærmbillede, regneark eller brugerdefinerede formularer mm. En definition er, at "en hændelse er et begreb, der bruges om en meddelelse, der sendes fra Windows til et program, når noget bestemt indtræffer". Klikker jeg fx med min mus på printknappen i Excel, sender Windows en besked til Excel om, at et "museklik" har fundet sted i forbindelse med objektet "Print knap". Nu kan Excel så reagere på hændelsen og udføre den funktion, der er forbundet med knappen. Der er mange forskellige hændelser, der kan indtræffe i Excel. Alle sendes fra Windows til Excel, men Excel reagerer kun på nogle af dem. Et dobbeltklik med musen i Statuslinjen vil således ikke medføre nogen reaktion fra Excel, mens et højreklik samme sted vil vise en genvejsmenu. Der er formodentlig langt flere hændelser, der ikke medfører en reaktion, end det omvendte.

 

NB! Det er ikke kun "eksterne" påvirkninger, der udløser hændelser. Det kan interne ting også gøre, fx at Excel udfører en beregning.

 

Der findes en lang række hændelser som ikke umiddelbart medfører en reaktion, men som alligevel opfanges. I disse tilfælde kan man så selv programmere en procedure, som gør et eller andet, når hændelsen indtræffer. En sådan procedure, som udføres som reaktion på en hændelse, kaldes en hændelsesprocedure.

 

Excel har et større antal hændelser, som der kan knyttes hændelsesprocedurer til. Disse hændelser kan være knyttet til projektmappen, et enkelt ark i en mappe, kontrolelementer i et ark, brugerdefinerede formularer, elementer i formularer osv. Herudover har Excel et antal såkaldte "On" nøgleord. Også disse anvendes til at knytte kode til hændelser. Endelig har Excel et antal såkaldte "Auto" procedurer, som igen udføres når bestemte ting indtræffer. Forskellen på disse nøgleords- og autoprocedurer og andre hændelsesprocedurer er, at nøgleords- og autoprocedurerne gemmes i almindelige moduler, mens de øvrige hændelsesprocedurer skal gemmes i særlige klassemoduler.

 

- Til Top - 

"Auto"-hændelser

Alle "Auto" funktionerne er altid knyttet til hele projektmappen. Der findes fire af slagsen: Auto_Open, Auto_Close, Auto_Activate, og Auto_Deactivate. De pågældende hændelser indtræffer når en projektmappe åbnes, lukkes, aktiveres eller deaktiveres.

 

Prøv at skrive følgende kode i et almindeligt modul. Gem og luk projektmappen og åbn den så igen:

 

Sub Auto_Open()

    MsgBox "Så er den åbnet"

End Sub

 

Auto_Open bruges ofte til at indstille de forskellige "On" funktioner. Ret ovenstående kode til:

 

Sub Auto_Open()

    Application.OnKey "{a}", "Mbox"

End Sub

 

I samme modul skriver du så

 

Sub Mbox()

    MsgBox "Du har trykket på a-tasten"

End Sub

 

Gem og luk igen mappen. Åbn den og prøv at trykke på a-tasten. Husk at slette koden igen inden du gemmer og lukker. Ellers får du problemer med a-tasten i den projektmappe fremover :-)

 

- Til Top -

"On…"

De 12 "on" nøgleord, der kan bruges i Excel er

 

OnAction

Dette kodeord er knyttet til et givent objekt i et ark, og indtræffer, når der klikkes på objektet.

OnCalculate

Indtræffer nået et regneark genberegnes.

OnData

Indtræffer når Excel modtager data fra et andet program.

OnDoubleClick

Dette kodeord er knyttet til et givent objekt i et ark, og indtræffer, når der dobbeltklikkes på objektet.

OnEntry

Indtræffer når brugeren trykker Enter efter at have tastet data ind i regnearket.

OnKey

Indtræffer når en bruger trykker på en bestemt tast eller tastekombination. Se nedenfor omkring tastekombinationer.

OnRepeat

Indtræffer når brugeren vælger Gentag fra Redigermenuen.

OnSheetActivate

Indtræffer når der skiftes til det ark, der er angivet i koden, fra et andet ark.

OnSheetDeactivate

Indtræffer når der skiftes væk fra det ark, som er angivet i koden.

OnTime

Indtræffer på et bestemt tidspunkt. Dog forudsat at koden er aktiveret og Excel startet på det pågældende tidspunkt.

OnUndo

Kører når brugeren fortryder en kommando.

OnWindow

Kører når brugeren skifter til et bestemt vindue eller når Excel vinduet aktiveres.

 

For disse kodeord skal virke, skal de altså være aktiveret via en anden makro, typisk Auto_Open, men det kan også være andre makroer. Søg på de pågældende nøgleord i VBA hjælpen for at lære syntaksen for de enkelte ord. Specielt omkring OnKey skal man være opmærksom på, at en række knapper "fanges" ved at skrive navnet på knappen, og disse er ikke alle lige gennemskuelige. Fx fanges Pil Ned med {DOWN}, ikke med {DOWN ARROW}. Læg også mærke til at navnene på tasterne, med en enkelt undtagelse, altid skrives mellem tuborgparenteser og i øvrigt pakkes ind i anførselstegn. Vær specielt opmærksom på, at Enter tasten på det numeriske tastatur fanges med {ENTER}. Undetagelsen fra reglen om Tuborg-prarenteserne er Enter-tasten på skrivemaskinetastaturet, der fanges med ~ (accent tilde). Af én eller anden for mig ukendt grund skal netop denne kommando IKKE i tuborgparenteser.

 

Skal man bruge tastekombinationer som Skift+noget, Alt+noget eller Ctrl+noget, bruger man et eller flere foranstillede tegn, der står uden for tuborgparentesen. "+" for Skift, "^" for Ctrl og "%" for Alt.

 
Application.OnKey "+^{INSERT}", "Mtext"
 

Betyder altså at proceduren MText udføres, hvis der trykkes på Skift+Ctrl+Insert.

 

- Til Top -

Workbook-hændelser

Udover de allerede omtalte Auto-procedurer og On-kommandoer, har Excel en lang række hændelser, der alle er knyttet til såkaldte klassemoduler. Jeg vil vende tilbage til, hvordan man selv kan oprette og bruge klassemoduler i en senere artikel. I denne omgang vil jeg nøjes med at se på de klassemoduler, som allerede findes i Excel.

 

Hvis man starter Visual Basic editoren i en tom projektmappe, vil man typisk se noget der ligner følgende i venstre side af skærmen. Dette ses i den såkaldte Project Explorer.  Er denne ikke vist, skal du vælge View – Project Explorer. Her ses mappens ark. Har du omdøbt arkene, vil dine navne stå i parentesen i stedet for fx Ark1. Til hvert ark, er der knyttet et klassemodul. Det samme er der til hele projektmappen. Klassemodulet til hele projektmappen er det, der hedder ThisWorkbook. Dobbeltklik på det klassemodul, du vil arbejde med.

 

I første omgang vil jeg se nærmere på ThisWorkbook, senere vender jeg tilbage til arkene. Når der dobbeltklikkes på ThisWorkbook, åbnes et modul, der ligner alle andre moduler. På en enkelt undtagelse nær. Når man klikker på ruden, hvor der står General i et almindeligt modul, er det, det eneste der står. I et klassemodul er der yderligere en valgmulighed. Hvilken afhænger af om klassemodulet vedrører ThisWorkbook eller et ark.

 

 

I dette tilfælde ses punktet Workbook. Vælges dette punkt, vil der blive indsat en procedurestart/slut, og i ruden ved siden af, vil der blive vist Open.

 

Private Sub Workbook_Open()

 

End Sub

 

I ruden, hvor der står Open kan der nu vælges et antal hændelser, der er knyttet til projektmappen. Skal man ikke bruge den hændelsesprocedure, der vises, sletter man bqre de to kodelinjer. Der kan vælges mellem næsten 30 forskellige hændelser, og det vil føre alt for vidt at komme ind på dem alle i denne sammenhæng. Jeg vil derfor nøjes med at komme ind på et par af de mest almindeligt brugte hændelser. Et problem med brugen af hændelser, kan være at flere hændelser tilsyneladende kan optræde samtidigt, og derfor kan man være i tvivl om, hvilken hændelse man skal anvende. Imidlertid er der ingen hændelser, der optræder samtidigt. De optræder alle i rækkefølge. Er man i tvivl om, hvilken hændelse af to, der indtræffer først, kan man undersøge det, ved at anvende begge hændelser og lade dem vise en forskellig meddelelsesboks. Så kan man se, hvilken af disse, der bliver vist først. På den måde kan man fx konstatere at Workbook_Open indtræffer før Auto_Open, og at Sheet_Change indtræffer før Sheet_SelectionChange.

 

Workbook_Open indtræffer når projektmappen åbnes. Denne hændelse kan man bruge til fx at bede brugerne om at gøre noget eller til at iværksætte ”ON”-kommandoer osv.

 

Private Sub Workbook_Open()

    Sheets(1).(Range("A1").Value = InputBox("Indtast dit navn og klik OK")

End Sub

 

Når projektmappen åbnes bliver brugeren bedt om at indtaste sit navn. Dette skrives i celle A1 i det først ark.

 

Workbook_BeforeClose indtræffer, når brugeren klikker på Luk-knappen eller vælger Luk i menuen. Hændelsen indtræffer lige inden der lukkes, og det kan så udnyttes til forskellige ting.

 

Private Sub Workbook_BeforeClose(Cancel As Boolean)

        Application.EnableEvents = False

        If IsEmpty(Range("a1")) Then

            MsgBox "Du skal udfylde celle A1 og gemme igen inden du lukker"

            Cancel = True

        End If

        Application.EnableEvents = True

End Sub

 

Sikrer at celle A1 er udfyldt inden der lukkes. Linjerne Application.EnableEvents = False og Application.EnableEvents = True samt Cancel = True, sikrer  at hændelsen ikke indtræffer efter at koden er udført, hvis A1 faktisk er tom. Er disse linjer ikke tilstede, vises meddelelsesboksen godt nok, men derefter indtræffer hændelsen alligevel og regnearket lukkes selv om A1 er tom.

 

Workbook_Activate og Workbook_Deactivate indtræffer når projektmappen aktiveres/ deaktiveres. Disse er interesante hvis brugeren kan skifte til en anden projektmappe og tilbage igen.

 

Workbook_BeforePrint indtræffer når brugeren vil udskrive projektmappen og indtræffer lige inden udskriften finder sted. Dette kan bruges til at styre forhold omkring udskrift. Under makroer, kan du finde et eksempel der udnytter BeforePrint hændelsen til at ændre baggrundsfarve i et regneark, inden der printes.

 

- Til Top -

Worksheet-hændelser

Der er altså mange andre hændelser, der kan bruges i en projektmappe, men jeg vil lade det ligge ved dette, og så vende mig mod de enkelte ark.

 

For at komme ind i et enkelt arks klassemodul, skal man dobbeltklikke på arknavnet i Project Explorer. Ellers er metoden den samme som anført for ThisWorkbook, bortset fra at man skal vælge Worksheet i stedet for Workbook i ruden øverst til venstre over modulet. Standardhændelsen, der vælges, er Worksheet_SelectionChange. På arkniveau er der kun ni hændelser, der kan anvendes. Jeg vil også her gennemgå nogle udvalgte og så overlade resten til egen nysgerrighed J.

 

Worksheet_Activate indtræffer når der skiftes mellem ark i mappen, og det ark, som indeholder koden, aktiveres. I koden nedenfor vises bare en meddelelsesboks, der fortæller brugeren, at arket er aktivt. Worksheet_Deactivate indtræffer modsætningsvis når arket gøres inaktivt ved at man skifter til et andet ark.

 

Private Sub Worksheet_Activate()

    MsgBox (ActiveSheet.Name & " er aktivt")

End Sub

 

Har jeg en Deactivate i Ark2 og en Activate i Ark1, vil et lille forsøg vise, at når der skiftes fra Ark2 til Ark1, indtræffer Deactivate før Activate.

 

Worksheet_BeforeDoubleClick indtræffer når der dobbeltklikkes i en celle og Worksheet_BeforeRightClick indtræffer på samme måde når der højreklikkes. Begge dele indtræffer umiddelbart før den hændelse, der ellers er forbundet med aktiviteten. Fx vil et dobbeltklik i en celle aktivere cellen for indtastning. Også her kan man med fordel anvende Application.EnableEvents osv. til at ”annullere” den oprindelige hændelse, hvis det er nødvendigt.

 

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

    MsgBox "Du har dobbeltklikket"

End Sub

 

Koden her vil vise meddelelsesboksen uanset hvilken celle, der klikkes i. Det er man sjældent interesseret i. Derfor indbygger man ofte en test på, hvilken celle, der er dobbeltklikket på eller om cellen der dobbeltklikkes på ligger inden for et bestemt celleområde. Dette kan gøres på flere forskellige måder, men de udnytter alle den ”indbyggede” variabel Target. Denne indeholder netop oplysninger om den celle, som hændelsen udføres på. De metoder, jeg skitserer nedenfor kan tilsvarende bruges i alle andre hændelser, hvor der skal testes på Target.

 

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

    If Target.Address = "$A$1" Then

        MsgBox "Du har dobbeltklikket"

    End If

End Sub

 

Koden her undersøger om der er dobbeltklikket i A1 og i det tilfælde udløses koden. Target.Row = 1 eller  Target.Column = 3 udløser meddelelsesboksen i hele række 1 eller kolonne 3. De to kan selvfølgelig også parres: If Target.Row = 1 Or Target.Column = 3 Then…


Skrives der i stedet If Target.Row = 1 And Target.Column = 3 Then… svarer det til, at der skrives    If Target.Address = "$C$1" Then…

 

Der er altså mange måder at opnå det samme på. En sidste mulighed, hvis der er tale om et større område er at bruge kommandoen Intersect. Den bruges til at undersøge sammenfald mellem to områder. Den kan bruges som følger:

 

   If Not Intersect(Target, Range("A1:D100")) Is Nothing Then

 

og undersøger om Target ligger inden for det område der specificeres i Range. Intersect undersøger sammenfaldet. ”Is Nothing” indtræffer, hvis der ikke er sammenfald og Not vender det om. Det vil altså sige, at vi siger ”hvis der ikke, ikke er sammenfald” skal der ske noget. Se eksemplet nedenfor under Worksheet_Change.

 

Worksheet_Calculate indtræffer, når der er foretaget en ændring i regnearket, der forårsager en genberegning. Det sker fx hvis der ændres i en celle, der påvirker en formel.

 

Worksheet_SelectionChange indtræffer når markøren flyttes fra en celle til en anden. Target er her den celle som der skiftes til. Flytter jeg cellemarkøren fra A2 til A1, er det A1, der er Target.

 

Worksheet_Change indtræffer, når der ændres i en celle. Selve hændelsen indtræffer først, når indtastningen ”accepteres” fx ved tryk på Enter. Target er her den celle, der ændres i.

 

Private Sub Worksheet_Change(ByVal Target As Range)

    If Not Intersect(Target, Range("A2:B10")) Is Nothing Then

        If Target.Value <> "" Then

            If IsNumeric(Target.Value) Then

                Target.Offset(0, 1).Value = Target.Offset(0, 1).Value + Target.Value

            End If

            Target.Value = ""

        End If

    End If

End Sub

 

Ovenstående kode undersøger først om der tastes i området A2 til B10. Er det tilfældet undersøges om det, der tastes er ”tomt”. Tastes der faktisk en værdi, undersøges om der er tale om et tal. Hvis der er tale om et tal, vil tallet blive lagt til i C-kolonnen ud for den række, hvor der er tastet i enten A- eller B-kolonnen. Står der fx 7 i C3 vil en indtastning af 3 i enten A3 eller B3 blive lagt til i C3, så der nu står 10 her. Indtastes der en tekst eller ingenting, sker der heller ingenting. Under alle omstændigheder slettes indtastningen så A2:B10 altid er tomme.

 

Et spørgsmål, som man ofte stilles overfor, er om ikke der er en hændelse, der indtræffer MENS man taster i en celle i stedet for først når der trykkes Enter. Svaret på det er ganske kort: Nej! Der findes ikke en sådan hændelse og der kan i det hele taget slet ikke afspilles kode mens en celle er under redigering. Derimod er det muligt at få afspillet kode, når der tastes i en tekstboks i en brugerdefineret formular.

 

Udover de hændelser, der kan knyttes til ark og projektmapper, kan der også knyttes hændelser til kontrolelementer og brugerdefinerede formularer. Koden til kontrolelementer i ark gemmes i arkets klassemodul. Kode til kontrolelementer i brugerdefinerede formularer gemmes i et klassemodul tilhørende den konkrete formular. Jeg vil ikke komme yderligere ind på disse hændelser på nuværende tidspunkt, men vender tilbage til dem senere i en artikel om opbygning af applikationer.

 

- Til Top -
- Tilbage til Programmering -
- Tilbage til makroer -
- Tilbage til Excel -