Bouwen van een invoegtoepassing voor Excel

Inhoud

Inleiding

Excel is een krachtige applicatie met duizenden opties en functies om rekenmodellen, rapporten en analyses te bouwen. Het komt toch nog regelmatig voor dat je in je dagelijkse werk wat functionaliteit zou kunnen gebruiken die Excel niet biedt.

Met behulp van VBA is het mogelijk om functionaliteit aan Excel toe te voegen. In dit artikel laat ik zien hoe je een kleine invoegtoepassing maakt in Excel VBA. Het artikel bespreekt alle benodigde stappen die ik nam om de invoegtoepassing te bouwen. De principes die ik tijdens het bouwen heb gebruikt helpen jou hopelijk bij het maken van je eigen tool!

Download

Ik heb een voorbeeldbestand beschikbaar gesteld dat je kunt downloaden.

Specificatie

Een heel belangrijke stap bij het maken van software is het bepalen wat de software moet kunnen; de specificatie. Laten we eens proberen een specificatie op te stellen.

Doel

De primaire doelstellingen van de invoegtoepassing die ik voor ogen heb zijn:

  • Een eenvoudige methode maken zodat de gebruiker aan zijn Excel bestand een inhoudsopgave toe kan voegen (of bijwerken);
  • Een hulpmiddel op het lint om het navigeren tussen werkbladen makkelijker te maken.

Zoals je je kunt voorstellen is meer detail nodig voordat we ons in het programmeerwerk onder kunnen dompelen. We hebben nog meer specificaties nodig.

Meer gedetailleerde specificatie

Werking van de inhoudsopgave

Ik preciseer hier nader wat de invoegtoepassing zal doen

  • De Inhoudsopgave zal geplaatst worden op een tabblad genaamd TOC (Table Of Content), beginnende in cel C2;
  • De tabel zal worden “Opgemaakt als tabel”;
  • De tabel zal in kolom C een lijst met alle werkbladnamen bevatten, met in kolom D een directe snelkoppeling naar cel A1 van dat werkblad. Kolom E geeft de gebruiker ruimte om naast het werkblad een opmerking in te voegen;
  • Deze opmerkingen zullen behouden blijven bij het vernieuwen van de Inhoudsopgave, zodanig dat –op basis van de tabnaam– de opmerking bij het juiste tabblad blijft staan;
  • De inhoudsopgave krijgt deze opmaak:
    Mockup of the ToC

Het Lint

De invoegtoepassing zal een aangepaste tab op het lint maken met daarin één groep met daarop:

  • Een vervolgkeuzelijst die alle werkbladen zal bevatten van de actieve werkmap;
  • Een knop om de inhoudsopgave te maken of te vernieuwen:
    The Ribbon

Andere functies

  • Zodra de gebruiker een andere werkmap selecteert wordt de lijst met werkbladen in de vervolgkeuzelijst automatisch bijgewerkt;
  • Als een ander werkblad wordt geselecteerd wordt deze op de vervolgkeuzelijst weergegeven.

Is dat alles?

In “echte” softwareprojecten zijn er natuurlijk nog allerlei andere vragen die ook nog beantwoord moeten worden. In willekeurige volgorde (niet pretenderend dat deze lijst volledig is):

  • Zorg voor een sponsor, je moet tenslotte je rekeningen betalen;
  • Doe marktonderzoek (als je tenminste van plan bent om die nieuwe invoegtoepassing te verkopen. Het zou toch leuk zijn als er ook een markt voor bestaat;)
  • Google. Twitter. Vraag het aan de buurman. Zorg er in ieder geval voor dat je niet iets gaat bouwen dat al bestaat. De kans is aanzienlijk dat iemand jou voorging met dit idee en misschien kan je zijn invoegtoepassing gewoon gebruiken;
  • Planning: Wanneer moet het klaar zijn?

Andere dingen om aan te denken

En dan hier nog een lijstje met dingen die je nodig zou kunnen hebben die eigenlijk weinig te maken hebben met de basisfunctionaliteit van je invoegtoepassing:

  • Ontwerpen van de gebruikersinterface;
  • Internationalisatie (vertalen in andere talen)
  • Bugs waar je omheen zal moeten werken;
  • Installatie;
  • Activatie (Mocht je van plan zijn te licenties te verkopen, hoe zorg je er dan voor dat er ook wordt betaald);
  • Demo versie;
  • Hoe zorg ik ervoor dat updates bij mijn klanten komen.

Zo, dan is het nu tijd om code te gaan schrijven.

Basisfunctionaliteit

Ervaring leert, dat invoegtoepassingen voor Excel iets gemeen hebben. De tijd die je tijdens het bouwen besteedt aan de kernfunctionaliteit is vaak slechts een klein deel van de tijd die nodig is om het project tot een goed einde te brengen. Dit is iets dat overigens voor heel veel softwareprojecten geldt.

De werkmap maken

Een invoegtoepassing voor Excel is niets meer of minder dan een gewone werkmap, die is opgeslagen als een invoegtoepassing. Je kan natuurlijk de invoegtoepassing zelf bewerken en opslaan, zoals ieder ander Excel bestand, maar ik persoonlijk bewerk liever een "normale" werkmap en sla die op als invoegtoepassing als ik klaar ben.

Dus, open een nieuw, leeg Excel bestand (Ik heb hier de VBA editor naast het venster van Excel gezet, met slechts de projectverkenner open):
A new Excel workbook and its VBA project in the project explorer

Net de geur van een nieuwe auto vind je niet?

Kernfunctionaliteit

Een module invoegen

De basis van de invoegtoepassing wordt een werkblad genaamd ToC. Omdat ik ervoor gekozen heb om een commentaar bij ieder werkblad mogelijk te maken, moeten deze commentaren tijdens het vernieuwen van de lijst tijdelijk worden opgeslagen en na het vernieuwen weer naast hun bijbehorende werkbladen worden teruggeplaatst.

Laten we dus eerst een module invoegen:

Inserting a module

En verander de naam van die module in het eigenschappen venster:

The Name property of the module

Het VBA project moet er nu zo uitzien:

The VBAProject with one module

Dubbel-klik op modTOC om het bijbehorende codevenster te openen.

De basiscode

Zonder verder uitgebreid uit de doeken te doen hoe de code werkt (het commentaar geeft al een flinke zet in de goede richting); is hier de code:

'-------------------------------------------------------------------------
' Module    : modMain
' Company   : JKP Application Development Services (c)
' Author    : Jan Karel Pieterse (jkp-ads.com)
' Created   : 30-4-2015
' Purpose   : De hoofdroutinesvan de tool
'-------------------------------------------------------------------------
Option Explicit

Public Sub UpdateTOC()
'-------------------------------------------------------------------------
' Procedure : UpdateTOC
' Company   : JKP Application Development Services (c)
' Author    : Jan Karel Pieterse (jkp-ads.com)
' Created   : 30-4-2015
' Purpose   : Maakt werkblad met inhoudsopgave (of werkt deze bij)
'-------------------------------------------------------------------------
    Dim oSh As Object
    Dim oToc As Worksheet
    Dim vRemarks As Variant
    Dim lCt As Long
    Dim lRow As Long
    Dim lCalc As Long
    Dim bUpdate As Boolean
    bUpdate = Application.ScreenUpdating
    Application.ScreenUpdating = False
    lCalc = Application.Calculation
    Application.Calculation = xlCalculationManual

    'Controleer of er al een werkblad ToC is, Zo niet, voeg er een toe:
    If Not IsIn(Worksheets, "ToC") Then
        With Worksheets.Add(Worksheets(1))
            .Name = "ToC"
        End With
        Set oToc = Worksheets("ToC")
        ActiveWindow.DisplayGridlines = False
        ActiveWindow.DisplayHeadings = False
    Else
        Set oToc = Worksheets("ToC")
        'We hebben een bestaand ToC blad, Sla de tabel met de inhoudsopgave op
        'zodat we de commentaren na vernieuwen terug kunnen zetten
        vRemarks = oToc.ListObjects(1).DataBodyRange
    End If
    'Controleer of er een tabel staat op het ToC werkblad, zo niet, toevoegen
    If oToc.ListObjects.Count = 0 Then
        oToc.Range("C2").Value = "Werkblad"
        oToc.Range("D2").Value = "Snelkoppeling"
        oToc.Range("E2").Value = "Opmerkingen"
        oToc.ListObjects.Add xlSrcRange, oToc.Range("C2:E2"), , xlYes
    End If
    On Error Resume Next
    'Tabel leegmaken
    'Fouten negeren voor het geval de tabel al leeg is

    oToc.ListObjects(1).DataBodyRange.Rows.Delete
    For Each oSh In Sheets
        If oSh.Visible = xlSheetVisible Then
            lRow = lRow + 1
            oToc.Range("C2").Offset(lRow).Value = oSh.Name
            oToc.Range("C2").Offset(lRow, 1).FormulaR1C1 = _
                "=HYPERLINK(""#'""&RC[-1]&""'!A1"",RC[-1])"
            oToc.Range("C2").Offset(lRow, 2).Value = ""
            'Bestaand commentaar voor dit werkblad invoegen
            For lCt = LBound(vRemarks, 1) To UBound(vRemarks, 1)
                If vRemarks(lCt, 1) = oSh.Name Then
                    oToc.Range("C2").Offset(lRow, 2).Value = vRemarks(lCt, 3)
                    Exit For
                End If
            Next
        End If
    Next
    oToc.ListObjects(1).Range.EntireColumn.AutoFit
    Application.Calculation = lCalc
    Application.ScreenUpdating = bUpdate
End Sub

Wellicht heb je al opgemerkt dat deze code een compileerfout geeft als je ze probeert uit te voeren:

Compile error, something's missing

Dit komt omdat er een functieaanroep in staat naar de functie "IsIn" die nog moet worden ingevoerd. IsIn is een functie die ik ooit van mijn collega Excel MVP Bill Manville heb gekregen.

Functies module

Omdat we misschien nog meer algemene functies nodig hebben, voeg ik een module toe die ik modFunctions noem. Daarin staat nu slechts deze functie:

Option Explicit

Function IsIn(vCollection As Variant, ByVal sName As String) As Boolean
'-------------------------------------------------------------------------
' Procedure : IsIn Created by Jan Karel Pieterse
' Company   : JKP Application Development Services (c) 2005
' Author    : Jan Karel Pieterse
' Created   : 28-12-2005
' Purpose   : Bepaalt of een object deel uitmaakt van een collectie
'-------------------------------------------------------------------------
    Dim oObj As Object
    On Error Resume Next
    Set oObj = vCollection(sName)
    If oObj Is Nothing Then
        IsIn = False
    Else
        IsIn = True
    End If
    If IsIn = False Then
        sName = Application.Substitute(sName, "'", "")
        Set oObj = vCollection(sName)
        If oObj Is Nothing Then
            IsIn = False
        Else
            IsIn = True
        End If
    End If
End Function

Nu zou de routine UpdateTOC moeten werken!

De gebruikersinterface

Invoegtoepassingen zijn verborgen bestanden en hebben dus geen werkbladen waar je bijvoorbeeld knoppen op kunt zetten. Er is dus iets nodig zodat de gebruiker ermee kan werken zoals misschien invoerschermen. Of ze moeten werkbladen toevoegen waar de gebruiker data in in kan voeren. Deze invoegtoepassing gebruikt enkele elementen op het lint.

Lint aanpassingen

Onze invoegtoepassing heeft dus slechts een beperkte gebruikersinterface, alles wat er nodig is zal op het lint komen te staan. Lintaanpassingen doen is geen eenvoudige klus. Gelukkig zijn er enkele zeer goede bronnen met informatie te vonden:

Met hulp van de Custom UI Editor, open ik het bestand waarin we aan het werk zijn (Ik heb dit bestand daarvoor opgeslagen en Excel gesloten om conflicten te voorkomen.

Na openen in de editor voeg ik een "Office 2007 CustomUI part" toe aan het bestand:

Inserting a customUI part

Door deze variant te nemen zorgen ik ervoor dat de lintaanpassingen in alle Excel versies werken. Vervolgens heb ik onderstaande XML code ingevoegd:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="rxJKPSheetToolscustomUI_onLoad">
    <ribbon>
        <tabs>
            <tab id="rxJKPSheetTools" label="SheetTools">
                <group id="rxJKPSheetToolsGeneral" label="Sheet Tools">
                    <dropDown id="rxJKPSheetToolsbtnSheets"
                        getItemCount="rxJKPSheetToolsbtnSheets_Count"
                        getItemLabel="rxJKPSheetToolsbtnSheets_getItemLabel"
                        onAction="rxJKPSheetToolsbtnSheets_Click"
                        sizeString="MMMMMMMMMMMMMMMMMMMMMMMM"
                        label="Sheets"
                        getSelectedItemIndex="rxJKPSheetToolsbtnSheets_getSelectedItemIndex"
                    />
                <button id="rxJKPSheetToolsbtnInsertToc"
                    label="Table Of Contents"
                    size="large"
                    onAction="rxJKPSheetToolsbtnInsertToc"
                    imageMso="CustomTableOfContentsGallery" />
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

Na invoegen van die code ziet de Custom UI Editor er zo uit:

Custom UI Editor

Van groot belang zijn de zogeheten callbacks die in de xml staan. Die geven aan dat er voor die acties VBA code in de werkmap in kwestie moeten staan. Door op de meest rechtse knop op de toolbar te klikken laat je de Custom UI editor de lege Sub ... End Sub kapstokken voor je genereren.

De xml bevat deze callbacks:

  • onLoad (Aangeroepen wanneer het bestand wordt geopend)
  • getItemCount (geeft het aantal elementen in een dropdown)
  • getItemLabel (Haalt het n-de element van een dropdown op)
  • onAction (Aangeroepen bij het klikken op een knop of het kiezen van een element uit een dropdown)
  • getSelectedItemIndex (geeft door welk element in de dropdown moet worden geselecteerd)

Misschien is het je opgevallen wat voor complexe routinenamen ik heb gemaakt (zoals "rxJKPSheetToolsbtnSheets_Click"). Vooral het "rxJKPSheetTools" deel. Callback namen moeten namelijk strikt uniek zijn binnen de contaxt van een lopende instantie van Excel. En dan bedoel ik ook echt uniek. Geen enkel ander openstaand Excel bestand kan een callback hebben met een routinenaam die samenvalt met een andere. Is dat wel het geval, dan loop je de kans dat de routine in de andere werkmap wordt aangeroepen en kunnen dus zeer onverwachte dingen gebeuren. Daarom zet ik altijd een stukje tekst voor iedere routinenaam waardoor ik er zeker van kan zijn dat deze uniek zijn.

Na kopieren van de kapstokjes uit de Custom UI editor sla ik de werkmap op en open deze in Excel. Vervolgens plak ik ze in een module in het VBA project:

Option Explicit

Sub rxJKPSheetToolscustomUI_onLoad(ribbon As IRibbonUI)
End Sub

Sub rxJKPSheetToolsbtnInsertTOC(control As IRibbonControl)
End Sub

'Callback for rxJKPSheetToolsbtnSheets getItemCount
Sub rxJKPSheetToolsbtnSheets_Count(control As IRibbonControl, ByRef returnedVal)
End Sub

Public Sub rxJKPSheetToolsbtnSheets_getItemLabel(control As IRibbonControl, Index As Integer, ByRef returnedVal)
End Sub

'Callback for rxJKPSheetToolsbtnSheets getSelectedItemIndex
Sub rxJKPSheetToolsbtnSheets_getSelectedItemIndex(control As IRibbonControl, ByRef returnedVal)
End Sub

Sub rxJKPSheetToolsbtnSheets_Click(control As IRibbonControl, id As String, Index As Integer)
End Sub

Ribbon callbacks

Ribbon load

Zodra het lint wordt vernieuwd wordt als eerste de callback aangeroepen die een verwijzing geeft naar het lint object. We gebruiken een object variabele op module niveau en wijzen het Ribbon object eraan toe:

Option Explicit

Dim moRibbon As IRibbonUI

Sub rxJKPSheetToolscustomUI_onLoad(ribbon As IRibbonUI)
    Set moRibbon = ribbon
End Sub

Zo. VBA onthoudt nu het ribbon object zodat we het lint vanuit onze code kunnen laten vernieuwen. Zodra het Excel bestand wordt geopened, wordt onLoad aangeroepen.

De dropdown voorzien van de tabnamen

Als het lint moet worden vernieuwd wordt als eerste de routine “rxJKPSheetToolsbtnSheets getItemCount” aangeroepen. In die routine moet worden doorgegeven aan het lint hoeveel werkbladen er in de lijst moeten worden geladen:

'Callback for rxJKPSheetToolsbtnSheets getItemCount
Sub rxJKPSheetToolsbtnSheets_Count(control As IRibbonControl, ByRef returnedVal)
    Dim lCt As Long
    Dim oSh As Object
    For Each oSh In Sheets
        If oSh.Visible = xlSheetVisible Then lCt = lCt + 1
    Next
    returnedVal = lCt
End Sub

De getoonde routine telt simpelweg het aantal zichtbare werkbladen in het huidige Excel bestand en geeft dat getal door aan de variabele returnedVal.

Vervolgens zal de routine “rxJKPSheetToolsbtnSheets getItemLabel” vanzelf dat aantal keer worden aangeroepen om de naam van ieder werkblad op te vragen, dus als er drie werkbladen zijn, wordt die routine drie keer aangeroepen om de naam van dat werkblad op te vragen:

Public Sub rxJKPSheetToolsbtnSheets_getItemLabel(control As IRibbonControl, Index As Integer, ByRef returnedVal)
    Dim lCt As Long
    Dim oSh As Object
    For Each oSh In Sheets
        If oSh.Visible = xlSheetVisible Then lCt = lCt + 1
        If lCt = Index + 1 Then
            returnedVal = oSh.Name
            Exit For
        End If
    Next
End Sub

Dus iedere keer dat deze routine wordt aangeroepen moet deze één tabnaam teruggeven.

Ik zou het zeer op prijs hebben gesteld als de makers van Excel slim genoeg waren geweest om vooraf te bedenken of tellers van lijstjes (collections) met het getal 0 of het getal 1 moeten beginnen. Maar dat hebben ze helaas niet gedaan, met als gevolg dat tellers dan weer bij 0, dan weer bij 1 beginnen in VBA.

Nadat de dropdown de tabnamen heeft opgehaald willen we de naam van het huidige tabblad tonen in die dropdown. Dat wordt gedaan door onderstaande callback:

'Callback for rxJKPSheetToolsbtnSheets getSelectedItemIndex
Sub rxJKPSheetToolsbtnSheets_getSelectedItemIndex(control As IRibbonControl, ByRef returnedVal)
    Dim lCt As Long
    Dim oSh As Object
    For Each oSh In Sheets
        If oSh.Visible = xlSheetVisible Then lCt = lCt + 1
        If oSh.Name = ActiveSheet.Name Then
            returnedVal = lCt - 1
            Exit Sub
        End If
    Next
End Sub

En dan willen we natuurlijk ook nog naar eeh tab gaan als die uit de keuzelijst wordt gekozen:

Sub rxJKPSheetToolsbtnSheets_Click(control As IRibbonControl, id As String, Index As Integer)
    Dim lCt As Long
    Dim oSh As Object
    For Each oSh In Sheets
        If oSh.Visible = xlSheetVisible Then lCt = lCt + 1
        If lCt = Index + 1 Then
            oSh.Activate
            Exit Sub
        End If
    Next
End Sub

Weet je nog dat ik zei dat de index van de dropdown bij 0 begint? Nou, de index van Excel's tabbladen begint bij 1.

De knop de inhoudsopgave laten vernieuwen

O wacht, wezijn er nog niet; de knop om de inhoudsopgave te vernieuwen doet het nog niet. We hadden er al een lege Sub ... End Sub voor, dus laten we die gebruiken::

Sub rxJKPSheetToolsbtnInsertTOC(control As IRibbonControl)
    UpdateTOC
End Sub

Zo, dat was niet zo moelijk, wel?

Applicatie events

In zijn huidige staat laadt onze invoegtoepassing netjes de lijst met tabbladnamen van de actieve werkmap. Maar dat is dan ook alles; zodra we van map wisselen of van tabblad wisselen wordt de keuzelijst niet bijgewerkt. Dat is ook logisch, want er is niets in de programmacode dat dat regelt.

De benodigde events

Wat hebben we nodig? We willen dat het lint wordt bijgewerkt zodra:

  • We een ander tabblad selecteren;
  • We een tabblad verbergen of zichtbaar maken;
  • We een andere werkmap selecteren.

Normaalgesproken, als je VBA code in een werkmap schrijft, dan zou je event macro's toevoegen aan de ThisWorkbook module. Events als deze:

Private Sub Workbook_Activate()
End Sub

Private Sub Workbook_SheetActivate(ByVal Sh As Object)
End Sub

Maar deze events reageren alleen op gebeurtenissen binnen die werkmap. Wat wij nodig hebben zijn events die voor iedere werkmap gelden. We noemen dat Applicatie events.

Een klasse module

Houd je vast, we gaan een klassemodule invoegen. Jazeker! We hebben een klassemodule nodig om dergelijke applicatie events te kunnen gebruiken.

Chip Pearson heeft een uitstekend artikel over Applicatie events geschreven. Ik hoef niet meer naar zijn website te gaan om dat artikel te lezen om deze stof te doorgronden, maar als dit nieuw voor je is, dan raad ik je aan het artikel te lezen.

Dus voeg een klasse module in en noem deze clsApp:

Class module

Bovenaan de module declareren we een object variabele met het speciale sleutelwoord "WithEvents":

Public WithEvents App As Application

Hiermee weet de compiler dat App een variabele is van het type Application die tevens events moet ophalen uit het applicatie object. Het lijkt of er niets bijzonders is gebeurd, maar de kleine dropdowns bovenaan het modulevenster bevatten nu links een nieuw object (App):

The top-left dropdown of the classes code window

als je die kiest kan je in de rechter dropdown alle Application Events zien staan. Het standaard event wordt tevens ingevoegd in de module:

Private Sub App_NewWorkbook(ByVal Wb As Workbook)

End Sub

Meestal is dat niet degene die ik wil hebben, maar met de dropdown kan je nu degene kiezen die je wel wilt. (de eerste halen we later wel weer weg):

The lefthand dropdown, showing the available events

Jazeker, alle applicatie events staan tot je beschikking! Kies degenen die je nodig hebt, tot je deze regels hebt:

Private Sub App_SheetActivate(ByVal Sh As Object)
    InvalidateRibbon
End Sub

Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
    InvalidateRibbon
End Sub

Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
    InvalidateRibbon
End Sub

Private Sub Class_Terminate()
    Set App = Nothing
End Sub

Merk op dat ik InvalidateRibbon ertussen heb gezet, een subroutine in modRibbonX die er zo uitziet:

Sub InvalidateRibbon()
    moRibbon.Invalidate
End Sub

Alleen die simpele "Invalidate" methode is afdoende om Excel duidelijk te maken dat het onze hele lintaanpassing opnieuw moet doen. Simpeler kan niet. Tenslotte heb ik nog het terminate event van de klasse zelf toegevoegd om ervoor te zorgen dat bij beeindigen van onze code alle object variabelen netjes op "Nothing" worden gezet. Het huis altijd opgeruimd achterlaten is ook voor VBA developers belangrijk!

De klasse aan het werk krijgen

Een klasse module is niets meer dan een blauwdruk van code. Anders dan bij een normale module kane je code in een klasse module niet zomaar uitvoeren. Je moet een kopie van de klasse in het geheugen laten laden. Het is die kopie (ontwikkelaars noemen dat een "instantie") die het werk gaat doen. Ik heb dit gedaan in een normale module genaamd modInit.

Bovenaan deze module is een object variabele genaamd mcApp gedeclareerd. Deze variabele gaat een pointer bijhouden naar de geheugenlokatie waar de instantie van onze klasse wordt geladen. De module variabele is noodzakelijk omdat module variabelen hun waarde niet verliezen bij het beeindigen van een subroutine. En zolang er tenminste 1 pointer naar de klasse instantie is blijft deze in het geheugen en dus ook reageren op de events:

Option Explicit

'Variabele die instantie van klasse clsApp vasthoudt
Dim mcApp As clsApp

Public Sub Init()
    'mcApp resetten indien deze al geladen is
    Set mcApp = Nothing
    'Een nieuwe instantie van clsApp laden
    Set mcApp = New clsApp
    'Geef het Excel object door aan clsApp zodat deze weet op welke applicatie
    'deze moet reageren
    Set mcApp.App = Application
End Sub

Ik verwacht dat de commentaren in bovenstaande code duidelijk genoeg zijn. Begrijp je het nog niet helemaal, lees dan dat artikel van Chip Pearson eens door...

Tenslotte willen we dat deze sub Init gestart wordt als we het bestand openen zodat onze invoegtoepassing direct gaat reageren op de events. Dus voegen we toe aan de ThisWorkbook module:

Private Sub Workbook_Open()
    Application.OnTime Now, "'" & ThisWorkbook.FullName & "'!Init"
End Sub

Ik gebruik de OnTime methode, omdat dat een aloude truc is die ervoor zorgt dat Excel helemaal klaar is met laden voordat Init wordt gestart. Soms start Excel het workbook_open event namelijk al voordat het zelf klaar is met al zijn opstartwerk. Met deze truc geef je Excel even de ruimte om dat af te maken.

De invoegtoepassing maken

Zo, het lastige deel zit erop, het programmeerwerk is af. Het enige dat ons nog te doen staat is het maken van de invoegtoepassing zelf. En natuurlijk testen!

Een invoegtoepassing maken

Het maken van een invoegtoepassing is simpel, gewoon op bestand, Opslaan Als klikken:

Save-As

In dat Opslaan Als venster, klikken we op het "Opslaan Als" dropdowntje en selecteren we" Excel Invoegtoepassing (*.xlam)":

Save As type

Zodra je voor "Excel Invoegtoepassing kiest, is Excel vriendelijk genoeg om zelf de standaard map voor invoegtoepassingen voor je te activeren. Maar omdat dat eigenlijk nooit de plaats is waar ik mijn invoegtoepassingen bewaar, ergerde ik mij enorm hieraan. Totdat iemand mij erop wees, dat je de "Terug" knop op dat opslaan als venster kunt gebruiken om terug te gaan naar de oorspronkelijke lokatie:

Back button

Zo, dat is alles, klik op Opslaan en je invoegtoepassing is klaar voor gebruik!

Gerelateerde artikelen

Hieronder een aantal artikelen die met invoegtoepassingen te maken hebben:


Vragen, suggesties en opmerkingen

Laatste 8 commentaren van in totaal 10 (Toon ze allemaal):

 


Commentaar van: glenn (9-4-2018 18:19:01) deeplink naar dit commentaar

Mooie uitleg
het maken van eigen menu is nog al ingewikkeld vind ik
Is het mogelijk om 2 dropboxen uit te lijnen zodat de dropboxen mooi onder elkaar staan


Commentaar van: Jan Karel Pieterse (10-4-2018 11:27:17) deeplink naar dit commentaar

Hoi Glenn,

ALs je objecten sleept over Excel kan je door indrukken van de Alt toets deze laten uitlijnen op het raster. Ook kan je door control+klikken meerdere objecten selcteren en dan in het opmaak menu de optie uitlijnen gebruiken.


Commentaar van: JanJaapJoris (13-10-2020 11:47:00) deeplink naar dit commentaar

Hallo Jan Karel,

In een complexe excel bestand (Excel 365worden over verschillende sheets (tabbladen) waardes ingevuld. Op een sheet worden de gegevens verzameld en komen in cel T3:Y3 waarden te staan, die aangeven hoever iets is ingevuld. Het invullen wordt door een aantal mensen gedaan, over een tijdsbestek van maanden.
Nu wil ik op een nieuwe sheet, per week, de waarden van T3:Y3 in een tabel vorm neerzetten. Zodat ik een grafiek kan laten zien wat de voortgang is.
Zijn hier binnen Excel handige functies voor?


Commentaar van: Jan Karel Pieterse (13-10-2020 14:12:00) deeplink naar dit commentaar

Hallo JanJaapJoris,

Jazeker! Kijk maar eens naar de opties op de tab "Gegevens". Stel anders je vragen op:
https://excelexperts.nl/forum/index.php


Commentaar van: John Philippen (18-6-2021 08:23:00) deeplink naar dit commentaar

Beste Jan Karel,
ik heb een aantal VBA codes geschreven en in mijn persoonlijke werkmap geplaatst.
Deze kan ik exporteren en door andere gebruikers laten importeren.
Dat werkt allemaal.
Ik heb ook een aangepast lint, maar als ik dat exporteer en vervolgens importeer, werken de knoppen bij die gebruiker niet.
Bestand kan niet twee keer worden geopend.
Hoe kan ik een lint met gekoppelde macro's exporteren zodat anderen dat ook kunnen gebruiken?
m.v.g.
John


Commentaar van: Jan Karel Pieterse (18-6-2021 11:40:00) deeplink naar dit commentaar

Hoi John,

Heb je deze pagina al gelezen? Die geeft eigenlijk al het antwoord:
https://jkp-ads.com/Articles/buildexceladdinnl.asp

Mocht je het lastig vinden dit aan de praat te krijgen ben ik gaarne bereid om een korte trainsessie op te zetten waarin ik uitleg hoe dit in zijn werk gaat. Daar zijn natuurlijk wel enige kosten aan verbonden.

Mail me maar als je daar interesse in hebt (zie email adres onderaan deze pagina, of antwoordt gewoon op je bevestigingsmail die je kreeg omdat je bericht geplaatst is)


Commentaar van: Ben Holleman (3-7-2023 13:52:00) deeplink naar dit commentaar

I.p.v. een riutine IsIn kun je ook anders checken of een tabblad bestaat.


On Error Resume Next
    Sheets("Kolommen").Select
    If Err.Number = 9 Then 'blad bestaat nog niet
        Sheets.Add After:=Worksheets(Worksheets.Count)
    End If
    Sheets(Worksheets.Count).Name = "Kolommen"


Je selecteert de tab van je dromen. Is die er niet, dan genereert Excel een foutnummer 9. Vang die af en maak deze tab alsnog aan. Selecteer nog maals.


Commentaar van: Jan Karel Pieterse (3-7-2023 14:32:00) deeplink naar dit commentaar

Hoi Ben,

Dank je. Dat klopt en dat is in de basis ook wat IsIn doet. Alleen is Isin algemener zodat ik die functie ook kan gebruiken om de aanwezigheid van een objectnaam in andere soorten collecties kan controleren. Zoals bereiknamen, werkmappen, draaitabellen etc.


Heeft u vragen, suggesties of opmerkingen? Gebruik dan dit formulier.

Mocht uw vraag niet direct relevant zijn voor deze pagina, maar een algemene Excel vraag betreffen, dan adviseer ik om deze hier te stellen: excelexperts.nl/forum/index.php.




Als u VBA code in uw commentaar plaatst, gebruik dan [VB] tags: [VB]Uw code[/VB].