Home
» PC-tips
»
Versnel Calc-macro's door gegevens in batches te lezen en te schrijven.
Versnel Calc-macro's door gegevens in batches te lezen en te schrijven.
De meest betrouwbare eerste manier om een trage Calc-macro te versnellen, is door herhaalde cel-voor-cel lees- en schrijfbewerkingen te vervangen door één bereikleesbewerking, een lus in het geheugen en één bereikschrijfbewerking. Dit vermindert het aantal aanroepen tussen Basic en Calc; het garandeert echter geen vaste snelheidswinst, omdat formules, opmaak, bestandsgrootte en macrologica ook een grote invloed kunnen hebben op de uitvoeringsduur. Het onderstaande voorbeeld wijzigt een statuskolom en laat zien hoe zowel de snelheid als de correctheid gemeten kunnen worden. De API-details zijn gecontroleerd aan de hand van de LibreOffice 26.8-documentatie op 9 oktober 2026.
Wat moet er verbeterd worden, en hoe ga je dat meten?
Voer de huidige macro uit op een kopie van het werkblad en noteer de verstreken tijd. Gebruik een nieuwe kopie met dezelfde begingegevens voor de oude en herziene macro's, of herstel de invoer tussen de uitvoeringen; anders kan de tweede uitvoering minder werk verrichten. Houd het aantal rijen, de berekeningsinstellingen en de uitvoervoorwaarden hetzelfde. Herhaal elke uitvoering en vergelijk de gemiddelde tijd in plaats van te vertrouwen op één uitzonderlijk snelle uitvoering. Controleer of het resultaat overeenkomt met uw verwachte regel. Een macro die sneller klaar is, maar de verkeerde rijen wijzigt, is geen verbetering.
De functie in LibreOffice Basic Timergeeft het aantal seconden sinds middernacht weer; wijs deze waarde toe aan Longvariabelen om de seconden in numerieke vorm te verkrijgen. Voor een korte run noteert u een begin- en eindwaarde en trekt u deze van elkaar af. Als de eindwaarde lager is, is de run voorbij middernacht, dus tel 86.400 seconden bij het verschil op. De timer geeft hele seconden weer; gebruik de ScriptForgeTimer-service voor precisie tot op de milliseconde. Zie de documentatie van de LibreOffice Basic Timer en de documentatie van de ScriptForge Timer-service . Houd het openen, opslaan en handmatig controleren van werkmappen buiten het gemeten interval, tenzij dit onderdeel is van de daadwerkelijke taak.
Begin bij elke timingrun met hetzelfde aaneengesloten gegevensbereik en dezelfde werkbladvoorwaarden.
Waarom worden grote Calc-macro's trager?
Een lus die getCellByPosition()herhaaldelijk individuele celeigenschappen opvraagt, leest en schrijft, zorgt ervoor dat Calc voor elke bewerking de Basic-naar-Calc-interface moet aanroepen. Bij veel rijen en kolommen kunnen die aanroepen flink oplopen, zelfs als de transformatie zelf eenvoudig is. Een lus over een array in het geheugen bezoekt nog steeds elke rij, maar vermijdt een aparte API-aanroep voor elke celwaarde.
Verwijder eerst bewerkingen die geen invloed hebben op het resultaat: vermijd het selecteren of activeren van cellen binnen de lus, herbereken of formatteer een cel niet herhaaldelijk wanneer één laatste bereikbewerking volstaat, en verwerk geen hele kolommen als slechts een afgebakend gegevensblok nodig is. Deze wijzigingen helpen om het werkelijke knelpunt te isoleren voordat u meer besturingselementen toevoegt.
Hoe verwerk je een bereik als een array?
Gebruik een rechthoekig bereik dat alleen de waarden bevat die uw macro wil wijzigen. In het voorbeeld wordt uitgegaan van een werkblad met de naam Data, een kopregel in rij 1 en statuswaarden in kolom C. Wijzig de naam van het werkblad en het bereik zodat deze overeenkomen met uw werkmap. De API getDataArray()retourneert het bereik als rijen met waarden; setDataArray()schrijft een array van dezelfde grootte terug naar dat bereik.
Lees het benodigde rechthoekige bereik eenmaal uit voordat de geheugenlus begint.
Sub UpdateStatuses
Dim oSheet As Object
Dim oRange As Object
Dim aData As Variant
Dim i As Long
oSheet = ThisComponent.Sheets.getByName("Data")
oRange = oSheet.getCellRangeByName("A2:C10001")
aData = oRange.getDataArray()
For i = LBound(aData) To UBound(aData)
If aData(i)(2) = "pending" Then
aData(i)(2) = "review"
End If
Next i
oRange.setDataArray(aData)
End Sub
De rij-array is nulgebaseerd: aData(i)(2)het adresseert de derde kolom in elke rij. Hier is dat kolom C, omdat het geselecteerde bereik begint bij A. De buitenste reeks van de array vertegenwoordigt rijen en elke binnenste reeks vertegenwoordigt kolommen. Het bereik dat wordt doorgegeven, setDataArray()moet dezelfde afmetingen hebben als de array; een verschil leidt tot een foutmelding. Zie de API-referentie van LibreOffice XCellRangeData en de array-documentatie van LibreOffice ScriptForge .
Pas de regel in het geheugen toe en schrijf vervolgens de voltooide array in één keer naar Calc.
Voorkom dat formulecellen worden meegenomen in een update die alleen waarden bevat.
getDataArray()Retourneert celwaarden als getallen of tekenreeksen, niet als de oorspronkelijke formuletekst. Als u een bereik met formules leest en die matrix terugschrijft met setDataArray(), kunnen die formules worden vervangen door hun huidige resultaten. Beperk de waardematrixmethode tot invoer-/uitvoercellen die waarden moeten bevatten. Wanneer een macro formules moet behouden of wijzigen, gebruikt u de formulematrixmethoden getFormulaArray()en setFormulaArray(), of werkt u alleen met het bereik zonder formules. De API-referentie van XCellRangeFormula beschrijft deze aparte interface.
Wanneer moet je de reken- of weergave-instellingen wijzigen?
Test deze opties pas nadat u de matrixversie hebt gemeten. Als het herberekenen van formules een groot deel van de uitvoeringstijd in beslag neemt, kunt u isAutomaticCalculationEnabled()de automatische berekening tijdelijk uitschakelen met enableAutomaticCalculation(False), vervolgens de oorspronkelijke instelling herstellen en de gewijzigde cellen opnieuw berekenen wanneer dat nodig is. Plaats het herstel in een opschoonpad, zodat een fout de werkmap niet in de handmatige berekeningsmodus achterlaat. Schakel de berekening niet uit als de macro tussen de stappen nieuwe formuleresultaten nodig heeft. LibreOffice beschrijft calculate()het herberekenen van gewijzigde cellen calculateAll()als een volledige herberekening die zelf kostbaar kan zijn. Zie de API-referentie van XCalculatable .
lockControllers()Kan bepaalde meldingen voor schermupdates opschorten terwijl een macro veel cellen wijzigt. Koppel elke vergrendeling aan unlockControllers(), ook wanneer de macro via een foutafhandeling wordt beëindigd. Dit vermindert de hoeveelheid werk die nodig is voor schermupdates; het schakelt de formuleberekening niet uit en maakt van de logica per cel geen bulkbewerking. Gebruik het voor een gemeten knelpunt bij het verversen van het scherm, niet als vervanging voor bereikarrays. Zie de XModel API-referentie .
Hoe controleer je de wijziging en hoe weet je wanneer je van methode moet wisselen?
Voer de herziene macro uit op een kopie van het werkblad en registreer de uitvoeringstijd onder dezelfde omstandigheden als de basisversie. Vergelijk de beïnvloede rijen, de niet-beïnvloede rijen, de formules en de belangrijkste totalen. Sla het werkblad op, sluit het en open het opnieuw als het productieproces opslaan vereist; dit kan problemen aan het licht brengen die bij een snelle visuele controle over het hoofd worden gezien. Een stabiele verbetering zou zichtbaar moeten zijn bij herhaalde uitvoeringen, zolang de uitvoercontroles blijven slagen.
Bevestig de omgerekende waarden en noteer de gemeten tijden zonder vooraf een versnelling aan te nemen.
Als de macro nog steeds het grootste deel van zijn tijd besteedt aan complexe formules, opmaak, bestandsinvoer/uitvoer of sorteren, profileer die fase dan apart; bereikmatrixen verminderen alleen herhaalde celtoegang. Voor zeer grote werkbladen kan een volledige matrix in het geheugen ook aanzienlijk geheugen in beslag nemen. Verwerk een paar kolommen tegelijk of verdeel de rijen in afgemeten blokken als de geheugendruk toeneemt, en controleer daarbij of elk blok begint en eindigt op de beoogde rijen. Als de gegevens zich al in een database bevinden en de taak bestaat uit het filteren, groeperen of bijwerken van records, is het wellicht beter om die taak in een databasequery uit te voeren dan elk record in Calc te laden.