LibreOffice Basic - Inleiding: verschil tussen versies
Regel 151: | Regel 151: | ||
== API: Export naar TSV-bestand == | == API: Export naar TSV-bestand == | ||
− | |||
− | |||
Dit werkt prima: | Dit werkt prima: | ||
Regel 172: | Regel 170: | ||
''' FilterOptions ''' | ''' FilterOptions ''' | ||
+ | [[file:20161014-2005.png|thumb|Deze instellingen worden (deels?) opgeslagen in de ''FilterOptions''-string]] | ||
* Eerste getal: Scheidingsteken tussen velden (ASCII-code) | * Eerste getal: Scheidingsteken tussen velden (ASCII-code) |
Versie van 14 okt 2016 17:16
Interface
- Net als in Microsoftproducten, heb je macro's en volwaardige code. Deze laatste heet LibreOffice Basic, en is te bereiken via Tools » Macros » Organise macros » LibreOffice Basic
- Ook de shortcut is hetzelfde: ALT-F11
- Programmeercode heet altijd macros. Ook als het in LO-Basic is geschreven
- Je kunt code opslaan in een geopend document, in een standaard-bibliotheek, of in een nieuwe bibliotheek. In dat laatste geval weet ik niet waar dat opgeslagen wordt
- Eigen routines kun je vervolgens aanroepen in functies in Calc
- Handig om de beveiligingsinstellingen te verlagen, als je met code aan de slag gaat: Tools » Options » Security » Macro security
Line wrapping
Line wrapping gaat op dezelfde manier als in VBA, en kent dus z'n beperkingen.
Simpel voorbeeld
function get_number_of_sheets() ' ' ====================================================== ' Line wrapping: <spatie><underscore> ' ====================================================== ' print ThisComponent. _ sheets. _ count end function
Realistischer
' Dit werkt, maar de underscores maken het er niet mooier op ' ThisComponent.sheets(0).copyRange _ ( _ Cell_dest.CellAddress, _ Cell_org.RangeAddress _ ) ' Dit ook: Weer: De underscores helpen weinig ' ThisComponent.sheets(0).copyRange _ ( _ _ Cell_dest.CellAddress, _ Cell_org.RangeAddress _ ) ' Misschien is dit de beste optie, als ik de input-argumenten graag onder elkaar wil afbeelden: ' ThisComponent.sheets(0).copyRange( _ Cell_dest.CellAddress, _ Cell_org.RangeAddress _ )
Commentaar-regels
De apostrophe (') zorgt voor commentaarregels
Functie-aanroepen
Functies kunnen andere functies aanroepen. Voorbeeld:
function call_another_function() call get_number_of_rows() call get_number_of_rows() end function
Immediate Windows & interactie
- Er is geen Immediate Windows zoals in VBA
- Wel kun je functies direct uitvoeren (F5) of via Alt-F11
- Output gaat naar een dialoogvenster, met het commando
print
.
API: Copy & paste cell ranges - copyRange
De copyRange
-method lijkt de meest voor de hand liggende manier te zijn om een range van cellen te kopiëren - Werkt super!
Voorbeeld: 1 cel kopiëren
Cell_org = ThisComponent.sheets(0).getCellByPosition(0,0) Cell_dest = ThisComponent.sheets(0).getCellByPosition(0,1) ThisComponent.sheets(0).copyRange(Cell_dest.CellAddress,Cell_org.RangeAddress)
Wat dit voorbeeld aangeeft tav. de syntaxis van copyRange
copyRange( destination cell address , source cell range address ) copyRange( <cel-object>.CellAddress , <cel-object>.RangeAddress ) copyRange( ThisComponent.sheets(0).<cel-object>.CellAddress , ThisComponent.sheets(0).<cel-object>.RangeAddress )
Wat dit voorbeeld verder aangeeft
Cell_org
enCell_dest
zijn cel-objectencopyRange
heeft van het cell_org-object de .RangeAddress-eigenschap nodigcopyRange
heeft van het cell_dest-object de .CellAddress-eigenschap nodig
Voorbeeld 2: Range kopiëren
Spreekt voor zich:
function copy_and_paste_copyrange_3() ' ' =============================================================================================================== ' copyRange + Range - Dit is 'm! ' =============================================================================================================== cell_org=ThisComponent.sheets(0).getCellRangeByPosition(0,0,0,2) cell_dest=ThisComponent.sheets(0).getCellByPosition(0,3) ThisComponent.sheets(0).copyRange _ ( _ cell_dest.CellAddress, _ cell_org.RangeAddress _ ) end function
API: Copy & paste cell ranges - getDataArray & setDataArray
Kopiëren en plakken van cell ranges kan op verschillende manieren, waaronder met getDataArray en setDataArray:
- getDataArray en setDatArray zijn allebei methodes van een sheet- of cell-range-object
- Ze schijnen hier thuis te horen:
:: com :: sun :: star :: sheet :: - interface XCellRangeData
- getDataArray vult een array met de aangegeven waardes, die worden opgeslagen als double of als string.
Voorbeeld
source_array=ThisComponent.Sheets(0).getCellRangeByName("A1:C1").getDataArray() ThisComponent.Sheets(0).getCellRangeByName("A3:C3").setDataArray(source_array)
getDataArray is hier een methode van sheets.getCellRangeByName:
ThisComponent.Sheets(0).getCellRangeByName("A1:C1")
Dit object bevat behalve de waardes van de cellen, tevens zaken zoals cel-opmaak. Vandaar de getDataArra-methode.
API: Export naar TSV-bestand
Dit werkt prima:
function export_csv() Dim Propval(1) as New com.sun.star.beans.PropertyValue Propval(0).Name = "FilterName" Propval(0).Value = "Text - txt - csv (StarCalc)" Propval(1).Name = "FilterOptions" Propval(1).Value ="9,34,0,1,1" ' Eerste & tweede veld zijn ASCII-codes FileName = "/var/export/calc.tsv" 'Change to whatever file name you want FileURL = convertToURL(FileName) ThisComponent.StoreAsURL(FileURL, Propval()) end function
FilterOptions
- Eerste getal: Scheidingsteken tussen velden (ASCII-code)
- Tweede getal: Omsluitingsteken voor tekstvelden (ASCII-code). Op het moment dat tab wordt gebruikt als scheidingsteken, lijkt dit veld niet meer te worden gebruikt
- Derde getal: ?
- Vierde getal: ?
- Vijfde getal: ?
ASCII-codes voor FilterOptions
<tab> - 9 " - 34 ; - 59
Casus (okt. 2016)
Ik wil een rekenblad met zo'n 30 tabbladen importeren in MySQL. Daarbij wil ik die tabbladen samenvoegen, waarbij de naam van het tabblad als extra kolom wordt opgevoerd. Het liefst wordt dat geaggregeerde tabblad volautomatisch geëxporteerd in een passen formaat (TSV, etc.).
Gezochte functionaliteiten:
- Voeg een nieuw tabblad toe
- Voeg een nieuwe kolom toe aan een tabblad
Voeg een nieuw tabblad toe
function insert_sheet() ' ====================================================== ' Insert sheet 'Aggregate' (if not exists) ' ====================================================== dim doc as object dim sheet as object doc = ThisComponent if ThisComponent.sheets.hasByName("Aggregate") then ' Do nothing: Sheet "Aggregate" bestaat al else sheet = doc.createInstance("com.sun.star.sheet.Spreadsheet") doc.sheets.insertByName("Aggregate",sheet) end if
Voeg een kolom toe
function insert_column() ' ====================================================== ' Insert column on current sheet ' ====================================================== ' dim doc as object dim sheet as object dim new_column as object doc = Thiscomponent sheet = doc.Sheets(0) ' Select first sheet (counting starts at 0) sheet.Columns.insertByIndex(0,1) ' At position 0, insert 1 column end function
Get number of sheets
function get_number_of_sheets() ' ====================================================== ' Get the number of sheets in the current file ' ====================================================== ' ' In dit geval niet gewerkt met tussenliggende variableen ' Op zich handig, zo'n abstractielaag, maar hier overkill ' print ThisComponent.sheets.count end function
Insert column on each sheet
function insert_column_on_each_sheet() ' ' ====================================================== ' Insert column on each sheet ' ====================================================== ' for i=0 to ThisComponent.sheets.count-1 Thiscomponent.sheets(i).columns.insertbyindex(0,1) next end function
Get number of rows
function get_number_of_rows() ' ' ====================================================== ' Get number of rows ' ====================================================== ' ' * Dat gaat alleen indirect, mbv. een cursor & gotEndOfUsedArea ' * Base=0. Dus het getal is 1 cijfer te laag ' dim o_cursor as object o_cursor = ThisComponent.Sheets(0).createCursor() o_cursor.gotoEndOfUsedArea(false) print o_cursor.getRangeAddress().EndRow end function
Get sheet name
function get_sheet_name() ' ====================================================== ' Get sheet name ' ====================================================== ' get_sheet_name = thiscomponent.getcurrentcontroller.activesheet.GetName end function
Insert sheet name on each row
function insert_sheet_name_on_each_row() ' ====================================================== ' Insert sheet name on each row in new column ' ====================================================== dim o_cursor as object dim s_sheetname as string dim i_rows as integer ' Get number of rows » i_rows ' =================================== ' o_cursor = ThisComponent.Sheets(0).createCursor() o_cursor.gotoEndOfUsedArea(false) i_rows = o_cursor.getRangeAddress().EndRow+1 ' Sheet name » s_sheetname ' =================================== ' s_sheetname = ThisComponent.sheets(0).Getname ' Insert column ' ============= ' Thiscomponent.sheets(0).columns.insertbyindex(0,1) ' Insert sheet name on each row ' ============================ for i = 0 to i_rows-1 ThisComponent.sheets(0).getCellByPosition(0,i).String=s_sheetname next ' Debug ' ===== ' ' print s_sheetname & " " & i_rows end function
Copy & paste cell ranges
Zie aparte hoofdstuk voor details:
function copy_and_paste_copyrange_3() ' ' =============================================================================================================== ' copyRange + Range - Dit is 'm! ' =============================================================================================================== cell_org=ThisComponent.sheets(0).getCellRangeByPosition(0,0,0,2) cell_dest=ThisComponent.sheets(0).getCellByPosition(0,3) ThisComponent.sheets(0).copyRange _ ( _ cell_dest.CellAddress, _ cell_org.RangeAddress _ ) end function
Bronnen
Algemeen
- http://www.debugpoint.com/libreoffice-basic-macro-tutorial-index/ - Hoopvol
- https://wiki.documentfoundation.org/Development/How_to_debug - Geen Immediate Windows zoals in VBA
Code
- LibreOffice 3.4 Basic Programmer's Guide, p. 106 [1]
- http://openoffice3.web.fc2.com/OOoBasic_Calc.html#OOoCCA01a - Diverse voorbeelden. Ook goed voor je Japans
- http://www.openoffice.org/api/docs/common/ref/com/sun/star/sheet/XCellRangeMovement.html#copyRange - XCellRangeMovement API-calls
- https://www.prahladyeri.com/blog/2016/02/ten-libreoffice-macro-recipes.html
Copy & paste cell ranges
- https://www.openoffice.org/api/docs/common/ref/com/sun/star/sheet/XCellRangeData.html - getDataArray & setDataArray
- https://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Data_Array
- https://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Cell_Ranges
- http://www.openoffice.org/api/docs/common/ref/com/sun/star/sheet/SheetCellRange.html
- https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=33756 - copyRange, voorbeeld-code
- https://forum.openoffice.org/en/forum/viewtopic.php?f=25&t=16413