BDJ Toolbar · interne handleiding

Beknopt pyRevit-handboek

Alles wat je nodig hebt om de toolbar te installeren, de opbouw te begrijpen en zelf een eerste knop te bouwen volgens de juiste conventies. Dit is de beknopte versie: structuur en werkwijze — niet de broncode van de toolbar-tools zelf.

Document BDJ-HB-KORT Versie 1.0 Revit 2022+ Engine IronPython 2.7 Auteur Bram de Jong (BDJ)
01

Wat is pyRevit — en wat is deze toolbar?

pyRevit is een gratis uitbreiding op Revit waarmee scripts als gewone ribbon-knoppen beschikbaar komen. Elke knop in de toolbar is een klein Python-script dat via de Revit API met het geopende model praat: elementen verzamelen, parameters lezen of schrijven, views en sheets aanmaken.

De BDJ Toolbar bundelt de scripts die het repeterende tekenkamerwerk overnemen — taggen, opschonen, views en sheets opzetten. Deze handleiding legt uit hoe de toolbar in elkaar zit en hoe je er zelf, veilig, een knop aan toevoegt.

Goed om te weten

pyRevit draait scripts standaard in IronPython 2.7. Dat is een ouder Python-dialect: moderne f"..."-strings werken er níet, en het delen van twee gehele getallen rondt af naar beneden. In hoofdstuk 07 staan de valkuilen op een rij.

02

Installatie & de toolbar koppelen

2.1 pyRevit installeren

  1. Download de nieuwste installer van github.com/pyrevitlabs/pyRevit/releases en installeer met de standaardinstellingen.
  2. Start Revit opnieuw. Er verschijnt een tabblad pyRevit in de ribbon.

2.2 De toolbar-extensie koppelen

  1. Zorg dat je de map van de toolbar-extensie hebt (de map die eindigt op .extension), lokaal of op de netwerkschijf.
  2. Ga naar pyRevit → Settings → Custom Extension Directories, voeg de map toe die de .extension-map bevat en klik Save Settings + Reload.
  3. Het toolbar-tabblad verschijnt in de ribbon. Zie je het niet: controleer of je de bovenliggende map hebt gekozen, niet de .extension-map zelf.
Reload = F5 van pyRevit

Na élke wijziging aan een script of mapnaam: pyRevit → Reload. Revit hoeft niet opnieuw op te starten — reload duurt een paar seconden en je wijziging is actief.

03

Mappenstructuur: mappen wórden knoppen

pyRevit bouwt de ribbon rechtstreeks uit de mappenstructuur op schijf. De naam van de map bepaalt de tekst in Revit; de extensie van de mapnaam bepaalt het type. Zo ziet de opbouw eruit:

MijnToolbar.extension/ └── MijnToolbar.tab/ ← het tabblad in de ribbon ├── 01_Views.panel/ ← een paneel (groep) op het tabblad │ ├── MijnKnop.pushbutton/ ← één knop │ │ ├── script.py ← de code (verplicht) │ │ ├── icon.png ← 32×32 px (aanbevolen) │ │ └── bundle.yaml ← extra opties (optioneel) │ └── Gereedschap.pulldown/ ← uitklapmenu met knoppen erin │ ├── ToolA.pushbutton/ │ └── ToolB.pushbutton/ └── 02_Handleiding.panel/ └── Handboek.urlbutton/ ← knop die een link/bestand opent └── bundle.yaml

3.1 De bundeltypes die wij gebruiken

MapextensieWat het oplevert
.pushbuttonEen gewone knop die script.py uitvoert. Het werkpaard van de toolbar.
.pulldownEen uitklapmenu; de .pushbutton-mappen erbínnen worden de menu-items (zo zijn de Tags- en Purge-menu's gebouwd).
.urlbuttonEen knop die een URL of document opent — bijvoorbeeld deze handleiding. Alleen een bundle.yaml met een hyperlink:-regel nodig.
.smartbuttonEen knop die zijn eigen icoon/status kan bijwerken op basis van het model (zoals de sections-toggle met drie standen).
.stackStapelt 2–3 knoppen verticaal binnen een paneel om ruimte te besparen.

3.2 Naamgeving

Let op

Hernoem of verplaats je een map, doe dan altijd een Reload en controleer of de knop nog werkt — een typfout in .pushbutton of een ontbrekende script.py laat de knop stilletjes uit de ribbon verdwijnen.

04

Anatomie van een script — het vaste sjabloon

Elk script in de toolbar volgt hetzelfde stramien, van boven naar beneden: header → imports → variabelen → config → main → rapportage. Wie één script kan lezen, kan ze daardoor allemaal lezen. Dit is het volledige, generieke sjabloon:

script.py — het standaard-stramienpython · IronPython 2.7
# -*- coding: utf-8 -*-
__title__   = "Knopnaam"
__author__  = "Bram de Jong"
__version__ = "1.0"
__doc__     = """Version: 1.0
Date:    14 juli 2026
Author:  Bram de Jong (BDJ)
__________________________________________________________
Description:
[NL] Korte omschrijving van wat het script doet.
__________________________________________________________
How-to:
-> Stap 1
-> Stap 2
__________________________________________________________
"""

# IMPORTS
# ==================================================
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')

from Autodesk.Revit.DB import *
from pyrevit import revit, forms, script

# VARIABLES
# ==================================================
doc    = revit.doc
uidoc  = revit.uidoc
output = script.get_output()

# CONFIG  (benoemde constanten - nooit losse getallen in de logica)
# ==================================================
SOME_LIMIT_MM = 1200

# MAIN
# ==================================================
elements = FilteredElementCollector(doc)\
           .OfCategory(BuiltInCategory.OST_DuctCurves)\
           .WhereElementIsNotElementType().ToElements()

if not elements:
    forms.alert("Niets gevonden.", exitscript=True)

changed, errors = 0, []

# context manager -> automatische rollback bij een fout
with revit.Transaction("Omschrijving van de actie"):
    for el in elements:
        try:
            # ... hier de bewerking per element ...
            changed += 1
        except Exception as e:
            errors.append((el.Id, str(e)))

# REPORT
# ==================================================
output.print_md("## Resultaat")
output.print_md("- Aangepast: **{}**".format(changed))
output.print_md("- Fouten: {}".format(len(errors)))
for eid, msg in errors:
    output.print_md("- {} -> {}".format(output.linkify(eid), msg))

4.1 Waarom elk blok er staat

BlokFunctie
Header__title__ wordt de knoptekst, __doc__ de tooltip. De eerste regel (utf-8) is verplicht zodra er een é of ë in je teksten staat.
ImportsVast blok: Revit API via clr, en revit, forms, script uit pyRevit. Geen Dynamo-referenties (RevitServices) — die horen hier niet.
Variablesdoc, uidoc en output altijd bovenaan, zodat elk script dezelfde ingangen heeft.
ConfigAlle grenswaarden en namen als benoemde constante. Aanpassen kan dan zonder in de logica te graven.
MainVerzamelen → controleren → wijzigen. Wijzigen gebeurt altijd binnen with revit.Transaction("..."):.
ReportResultaten naar het output-paneel met output.print_md; pop-ups alleen voor echte fouten of bevestigingen.
05

De vijf gouden regels

Het doel achter alle conventies is één ding: een script mag Revit nooit laten vastlopen bij een collega. Deze vijf regels borgen dat:

  1. Wijzigen alléén via de context managerwith revit.Transaction("Nederlandse omschrijving"):. Gaat er iets mis, dan rolt Revit automatisch terug in plaats van in een open transactie te blijven hangen.
  2. Per element try/except Exception as e: in elke loop met een risicovolle actie. Eén kapot element mag nooit de hele batch afbreken; verzamel fouten en rapporteer ze.
  3. Cancel-check na elke keuzelijst. Klikt iemand op Annuleren, dan geeft forms.SelectFromList.show(...) None terug — controleer daarop en stop netjes met script.exit().
  4. Rapportage via output.print_md, niet via een pop-up per actie. Eén overzicht aan het einde, met output.linkify(element_id) zodat je naar elementen kunt doorklikken.
  5. Benoemde constanten in het CONFIG-blok — geen magische getallen of familienamen verstopt in de logica.
Zo herken je goed werk

Draait een script twee keer achter elkaar zonder dubbele resultaten, meldt het netjes wat het heeft overgeslagen, en overleeft het een klik op Annuleren — dan voldoet het aan de huisstijl.

06

Oefeningen

Drie opdrachten, oplopend in moeilijkheid. Werk in een eigen oefen-extensie (hoofdstuk 03) en test op een kopie van een project — nooit op het echte model.

Oefening 1 — Je eerste eigen knop

Maak in je oefen-extensie de map HalloTekenkamer.pushbutton met een script.py die het volledige header-blok uit hoofdstuk 04 heeft en één melding toont:

de kern van het scriptpython
from pyrevit import forms
forms.alert("Hallo tekenkamer! Dit is mijn eerste knop.")

Doe een Reload en controleer: staat de knop in de ribbon, en toont de tooltip jouw __doc__?

Oefening 2 — In welk model werk ik?

Maak een tweede knop die de naam van het geopende model toont:

alleen-lezen: hier kan niets kapotpython
from pyrevit import revit, forms

doc = revit.doc
forms.alert("Je werkt nu in: {}".format(doc.Title))

Bonus: vervang doc.Title eens door doc.PathName en bekijk het verschil.

Oefening 3 — Kanalen tellen in de actieve view

Bouw een knop die telt hoeveel ducts er in de actieve view zichtbaar zijn en het resultaat in het output-paneel zet:

collector + rapportage — nog steeds alleen-lezenpython
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory
from pyrevit import revit, script

doc    = revit.doc
output = script.get_output()

ducts = FilteredElementCollector(doc, doc.ActiveView.Id)\
        .OfCategory(BuiltInCategory.OST_DuctCurves)\
        .WhereElementIsNotElementType().ToElements()

output.print_md("## Telling actieve view")
output.print_md("- Ducts gevonden: **{}**".format(len(ducts)))

Bonus: tel óók de duct fittings (OST_DuctFitting) en zet beide tellingen in het rapport. Dit is precies het lees-en-rapporteer-patroon waarop de meeste toolbar-knoppen zijn gebouwd.

07

Problemen oplossen

7.1 De knop verschijnt niet

7.2 Rode foutmelding (traceback)

Lees een traceback altijd van onder naar boven: de onderste regel zegt wat er misging, de regels erboven waar. De drie IronPython 2.7-klassiekers:

SymptoomOorzaak & oplossing
SyntaxError op een regel met f"..."F-strings bestaan niet in IronPython 2.7 — herschrijf naar "...{}".format(x).
Een deling geeft geruisloos een te laag geheel getalTwee gehele getallen delen rondt af naar beneden: 1850 / 1000 → 1. Maak er één een kommagetal van: / 1000.0.
Rare tekens of een fout bij é/ë in teksten# -*- coding: utf-8 -*- moet de allereerste regel van het script zijn.

7.3 "Er gebeurt niets"

Controleer het output-paneel (verschijnt achter het Revit-venster) — de meeste knoppen rapporteren daar in plaats van met een pop-up. Vindt een script niets om te doen, dan meldt het dat daar ook.

Gouden testregel

Test elke nieuwe of aangepaste knop eerst op een kopie van een echt project — niet alleen op een leeg testmodel, en nooit rechtstreeks op productiewerk.