Bouwen van een invoegtoepassing voor Excel
Inhoud
- Inleiding
- Download
- Specificatie
- Basisfunctionaliteit
- De gebruikersinterface
- Ribbon callbacks
- Applicatie events
- De invoegtoepassing maken
- Gerelateerde artikelen
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:
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:
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):
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:
En verander de naam van die module in het eigenschappen venster:
Het VBA project moet er nu zo uitzien:
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:
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:
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 is er een zeer goede bron met informatie:
- Hét boek over het lint: RibbonX: Customizing the Office 2007 Ribbon
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:
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:
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:
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:
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:
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:
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:
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:
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::
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:
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:
Bovenaan de module declareren we een object variabele met het speciale sleutelwoord "WithEvents":
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):
als je die kiest kan je in de rechter dropdown alle Application Events zien staan. Het standaard event wordt tevens ingevoegd in de module:
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):
Jazeker, alle applicatie events staan tot je beschikking! Kies degenen die je nodig hebt, tot je deze regels hebt:
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:
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:
'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:
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:
In dat Opslaan Als venster, klikken we op het "Opslaan Als" dropdowntje en selecteren we" Excel Invoegtoepassing (*.xlam)":
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:
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:
- Een serie over het verspreiden van macro's die ik enige tijd geleden geschreven heb Excel-macro's geschikt maken voor anderen.
- Een artikel over het bijwerken van invoegtoepassingen via het internet
- Een artikel over invoegtoepassingen installeren met behulp van Setup Factory
- Een artikel over het repareren van externe koppelingen naar UDFs in invoegtoepassingen
- Een artikel over hoe je userforms bovenop het 2013 venster houdt
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.