mandag den 10. oktober 2016

Subrutiner og funktioner

Indtil nu har vi altid startet vores kode med Sub Main og afsluttet med End Sub. Det betyder at vi har lagt al vores kode i en enkelt subrutine.

Subrutiner er små eller store 'stumper' af kode, og en subrutine afvikles linje for linje. En subrutine kan kalde en anden subrutine (eller en funktion).

Lad os kigge på vores makroer som indlæser en CSV-fil. Begge makroer indeholder disse linjer:

my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count

If NOT my_sheets.hasbyName("Statistik") Then
    my_sheets.insertNewByName("Statistik", antal)
End If


Pointen her er, at hvis der ikke allerede findes et ark der hedder "Statistik", så skal vi oprette det. Denne lille opgave skal vi udføre i mindst to forskellige situationer, så det vil være smart hvis vi kan genbruge. Og det kan vi med en ny subrutine:

Sub checksheet(name as String)
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count

If NOT my_sheets.hasbyName(name) Then
    my_sheets.insertNewByName(name, antal)
End If
End sub


Læg mærke til at jeg ikke nævner navnet "Statistik" i subrutinen, men derimod tilføjer en parentes efter subrutinens navn. Det indikerer at subrutinen tager imod en parameter. Vi kan kalde subrutinen således:

Sub Main
filename= "file:///home/leif/Skrivebord/Calc/Statistik.csv"
my_doc = ThisComponent
checksheet("Statistik")        'Her kalder vi subrutinen checksheet

the_sheet = my_sheets.getByName("Statistik")
the_sheet.TabColor= RGB(255, 3, 101)
...osv

End sub


Bemærk at de grundlæggende variable my_doc og my_sheets deklareres i både Sub Main og i Function Checksheet. Årsagen er at disse variable er deklareret som lokale variable, og derfor ikke kendes uden for den enkelte subrutine eller funktion. Vi kan godt definere globale variable, men disse variable er ret store og vil fylde op i hukommelsen. Derfor vil det være mest effektivt at deklarere dem i de subrutiner, hvor vi skal bruge dem, men det er altid en afvejning.

Læg mærke til at vi fortsat anvender en subrutine. Vi vil dog gerne genbruge endnu mere af koden, f.eks. at den skal sætte en farve på fanen og returnere my_sheet som resultat. En subrutine kan ikke returnere et resultat, men det kan en funktion:

Function checksheet(name as String, r As integer, g As integer, b As integer)
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count

If NOT my_sheets.hasbyName(name) Then
    my_sheets.insertNewByName(name, antal)
End If

checksheet=my_sheets.getByName(name)
checksheet.TabColor= RGB(r, g, b)
End Function


Funktionen kaldes således:

Sub Main
filename= "file:///home/leif/Skrivebord/Calc/Statistik.csv"
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count
the_sheet=checksheet("Statistik", 255, 3, 101)
...



Den samlede makro ser nu sådan ud:
Sub Main
filename= "file:///home/leif/Skrivebord/Calc/Statistik.csv"
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count
the_sheet=checksheet("Statistik", 255, 3, 101)

n = FreeFile
r=0
Open filename For Input As #n
Do While NOT EOF(n)

    For c = 0 to 1
        Input #n, s
        my_cell = the_sheet.getCellByPosition(c,r)
        If r=0 then
        my_cell.String=s
        Else
        If c=0 Then
        t= split(s, "-", 3)
        s=DateSerial(t(2), t(1), t(0))
        End if
        my_cell.Value=s   
        End if
    Next c
    r=r+1

Loop
Close #n
End Sub

Function checksheet(name as String, r As integer, g As integer, b As integer)
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count

If NOT my_sheets.hasbyName(name) Then
    my_sheets.insertNewByName(name, antal)
End If

checksheet=my_sheets.getByName(name)
checksheet.TabColor= RGB(r, g, b)
End Function