• Privacywetgeving
    Het is bij Helpmij.nl niet toegestaan om persoonsgegevens in een voorbeeld te plaatsen. Alle voorbeelden die persoonsgegevens bevatten zullen zonder opgaaf van reden verwijderd worden. In de vraag zal specifiek vermeld moeten worden dat het om fictieve namen gaat.

Fout 424 tijdens uitvoering: Object vereist

Status
Niet open voor verdere reacties.

LJA

Gebruiker
Lid geworden
23 mrt 2017
Berichten
18
Mijn probleem:
In VBA krijg ik de melding: Kan de onderbrekingsmodus momenteel niet activeren
en vervolgens de foutmelding: Fout 424 tijdens uitvoering: Object vereist

Mogelijk antwoord:
Vermijd 'Select' en 'Activate' in VBA. Dat geldt ook voor overbodige variabelen (bijv. die niet variëren)
Dit heb ik gevonden in de post : http://www.helpmij.nl/forum/showthread.php/696865-Excel-VBA-foutmelding-424-Object-vereist
Ik begrijp alleen niet, hoe ik mijn VBA-code dusdanig kan aanpassen. Ik ben nog lerende. ; )

Mijn vraag:
Ik heb een Macro in 4 stappen werkend. Nu ben ik die stappen gaan samenvoegen.
Bij stap 3 ('Draaitabel maken) naar 4 krijg ik de genoemde foutmelding. (Stap 3 lijkt wel afgemaakt te worden, omdat de weeknummers met 2 getallen worden uitgevoerd (laatste stap).)
Wanneer ik stap 4 daarna los uitvoer, werkt het weer wel.
Omdat ik nog lerend ben in VBA, zie ik niet goed, hoe ik het probleem daadwerkelijk kan oplossen.
Ik hoop dat iemand mij in de goede richting wil helpen.

Mijn VBA-code:
-------------------------------------------------------------------------------
Code:
Sub MT_CopyDataFromMultipleWorkbooksIntoMaster()

' DEEL Macro1 CopyDataFromMultipleWorkbooksIntoMaster Macro

Dim FolderPath As String, Filepath As String, Filename As String

'LOCATIE : TEST : H:\Mijn Documenten\Excel\Voorbeelden\Test\Planningen\
'LOCATIE : TEST : I:\STO\Projecten\_Planning\PLANNINGEN\
FolderPath = "H:\Mijn Documenten\Excel\Voorbeelden\Test\Planningen\"

Filepath = FolderPath & "*.xls*"

Filename = Dir(Filepath)

Dim lastrow As Long, lastcolumn As Long

Do While Filename <> ""
'Meldingen uit
Application.DisplayAlerts = False
'Werkmap openen
Workbooks.Open (FolderPath & Filename), UpdateLinks:=3, Notify:=False
'Alle Kolommen zichtbaar maken
 ActiveSheet.Cells.EntireColumn.Hidden = False
'Laatste Rij vinden
 lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
'Kolommen met ProjectNummer en ProjectNaam
 Columns("A:A").Select
 Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
 Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
 Range("A1").FormulaR1C1 = "=R1C4"
 Range("B1").FormulaR1C1 = "=R2C4"
 Range("A1:B1").AutoFill Destination:=Range(Cells(1, 1), Cells(lastrow, 2)), Type:=xlFillDefault
'Laatste Kolom vinden
 lastcolumn = ActiveSheet.Cells(4, Columns.Count).End(xlToLeft).Column
'Range(“A6:**”) kopieren en werkmap sluiten
 Range(Cells(6, 1), Cells(lastrow, lastcolumn)).Copy
 ActiveWorkbook.Close

erow = Blad1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column

ActiveSheet.Paste Destination:=Worksheets("Blad1").Range(Cells(erow, 1), Cells(erow, lastcolumn))

Filename = Dir

Loop

' DEEL Macro2 Aanpassen_Tabel
    'Naamgeving kolommen en Nummering weeknummers (t/m 52)
    Range("A1").FormulaR1C1 = "ProjectNummer"
    Range("B1").FormulaR1C1 = "ProjectNaam"
    Range("C1").FormulaR1C1 = "Werk"
    Range("D1").FormulaR1C1 = "Team"
    Range("E1").FormulaR1C1 = "Persoon"
    Range("F1").FormulaR1C1 = "X"
    Range("G1").FormulaR1C1 = "Duur"
    Range("H1").FormulaR1C1 = "Begin"
    Range("I1").FormulaR1C1 = "Einde"
    Range("J1").FormulaR1C1 = "Versie"
    Range("K1").FormulaR1C1 = "Opmerking"
    Range("L1").FormulaR1C1 = "SamenVoeg"
    'Eerste twee weken nummeren en doorkopieren
    Range("M1").FormulaR1C1 = "01"
    Range("N1").FormulaR1C1 = "02"
    Range("M1:N1").AutoFill Destination:=Range(Cells(1, 13), Cells(1, 64)), Type:=xlFillDefault
     
    'Laatste Rij en Laatste Kolom vinden en definieren
    erow = Blad1.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0).Row
    lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
     
    'Weeknummers in twee cijfers
    Range(Cells(1, 13), Cells(1, lastcolumn)).NumberFormat = "00"
    Rows("1:1").Font.Bold = True
    
    'Kolom L (SamenVoeg) vullen met gegevens 11 voorgaande kolommen
    Range("L2").FormulaR1C1 = "=RC[-11]&""|""&RC[-10]&""|""&RC[-9]&""|""&RC[-8]&""|""&RC[-7]&""|""&RC[-6]&""|""&RC[-5]&""|""&RC[-4]&""|""&RC[-3]&""|""&RC[-2]&""|""&RC[-1]"
    Range("L2").AutoFill Destination:=Range(Cells(2, 12), Cells(erow - 1, 12))
    
    'OPMAAK
    'Kolommen fit
    Range(Columns(1), Columns(lastcolumn)).EntireColumn.AutoFit
    'Lijnen rond alle cellen
    ActiveCell.CurrentRegion.Borders.LineStyle = xlContinuous
    
' DEEL Macro3 DraaiTabel_Maken Macro
    'Laatste Rij en Laatste Kolom vinden en definieren
    erow = Blad1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
    lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
  
    'Range selecteren en benoemen
    Range(Cells(1, 12), Cells(erow - 1, lastcolumn)).Select
    ActiveSheet.ListObjects.Add(xlSrcRange, Selection, , xlNo).Name _
    = "myRange"
    
    'Draaitabel maken
    ActiveWorkbook.PivotCaches.Create(SourceType:=xlConsolidation, SourceData:= _
        "myRange", Version:=xlPivotTableVersion14). _
        CreatePivotTable TableDestination:="", TableName:="Draaitabel1", _
        DefaultVersion:=xlPivotTableVersion14
    ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(1, 1)
    ActiveSheet.Cells(1, 1).Select
    ActiveSheet.PivotTables("Draaitabel1").DataPivotField.PivotItems( _
        "Aantal van Waarde").Position = 1
    With ActiveSheet.PivotTables("Draaitabel1").PivotFields("Aantal van Waarde")
        .Caption = "Som van Waarde"
        .Function = xlSum
        ActiveSheet.PivotTables("Draaitabel1").PivotFields("Kolom").NumberFormat = "00"
    End With
    
    'Hulpblad verwijderen
    'Sheets("Data (2)").Delete
    
    'Blad naam geven
    'ActiveSheet.Name = "DraaiTabel"
    
' DEEL Macro4 DraaiTabel_Aanpassen Macro
    'Laatste Rij en Laatste Kolom vinden en definieren
    erow = Blad2.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
    lastcolumn = ActiveSheet.Cells(2, Columns.Count).End(xlToLeft).Column
  
    'Andere tabel openen
    Range(Cells(erow - 1, lastcolumn), Cells(erow - 1, lastcolumn)).ShowDetail = True
    
    'Meldingen opheffen
    Application.DisplayAlerts = False
    
    'Tekst kolom A uitsplitsen
    Columns("B:B").Select
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Columns("A:A").Select
    Selection.TextToColumns Destination:=Range(Cells(1, 1), Cells(erow - 1, 1)), _
        DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter _
        :=False, Tab:=False, Semicolon:=False, Comma:=False, Space:=False, _
        Other:=True, OtherChar:="|", FieldInfo:=Array(Array(1, 1), Array(2, 1), Array _
        (3, 1), Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1), Array(8, 1), Array _
        (9, 1), Array(10, 1), Array(11, 1)), TrailingMinusNumbers:=True
    
    'Naamgeving kolommen en Weeknummers in twee cijfers
    Range("A1").FormulaR1C1 = "ProjectNummer"
    Range("B1").FormulaR1C1 = "ProjectNaam"
    Range("C1").FormulaR1C1 = "Werk"
    Range("D1").FormulaR1C1 = "Team"
    Range("E1").FormulaR1C1 = "Persoon"
    Range("F1").FormulaR1C1 = "X"
    Range("G1").FormulaR1C1 = "Duur"
    Range("H1").FormulaR1C1 = "Begin"
    Range("I1").FormulaR1C1 = "Einde"
    Range("J1").FormulaR1C1 = "Versie"
    Range("K1").FormulaR1C1 = "Opmerking"
    Range("L1").FormulaR1C1 = "Week"
    Range("M1").FormulaR1C1 = "Uren"
    Columns("L:L").NumberFormat = "00"

    'Tabel uit elkaar laten vallen om selectie in volgende VBA-regel te deleten
    ActiveSheet.ListObjects("Tabel2").Unlist
    'Rijen met lege cel in kolom Uren deleten
    Range("M:M").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
     
     'OPMAAK
    'Kolommen fit
    Range(Columns(1), Columns(lastcolumn)).EntireColumn.AutoFit
    'Lijnen rond alle cellen
    ActiveCell.CurrentRegion.Borders.LineStyle = xlContinuous
 
    'Blad naam geven
    ActiveSheet.Name = "Tabel"
    
    'Einde
    Application.DisplayAlerts = True
    Range("A1").Select
    
End Sub
-------------------------------------------------------------------------------

(Ik besef me, dat ik mijn VBA-code nog verder is op te schonen. Bepaalde tussenstapjes kunnen verwijderd worden, omdat die in het geheel niets meer toevoegen.
Ik wil later nog proberen op te schonen. Tips zijn welkom! ; )

Bestanden
Ik heb mijn excel-bestand met de macro's bijgevoegd: Master - wo-05-04-2017.xlsm
Tevens heb ik de twee planningen bijgevoegd, die normaal gesproken in de map "H:\Mijn Documenten\Excel\Voorbeelden\Test\Planningen" staan.

Ik hoop dat iemand mij verder wil helpen.
Bij voorbaat dank ik u hartelijk.

Met vriendelijke groeten,
LJ
 

Bijlagen

  • Master - wo-05-04-2017.xlsm
    26,4 KB · Weergaven: 81
  • 1001-planning.xlsx
    10,5 KB · Weergaven: 71
  • 1501-planning.xlsx
    10,6 KB · Weergaven: 70
In je code staat Blad2.Range.... maar er is geen object dat Blad2 heet.
 
#jkpieterse:
In "DEEL Macro4" wordt inderdaad het "Blad2" benoemd, omdat Blad2 in "DEEL Macro3" wordt aangemaakt en in "DEEL Macro4" gebruikt wordt.
Dit is dus volgens mij niet de fout.
Zoals vermeld kan ik (met F8 stapsgewijs) de complete VBA-code tot het gedeelte "Draaitabel maken" in "DEEL Macro3" doorlopen. Dan krijg ik de genoemde meldingen.
Wanneer ik vervolgens "DEEL Macro4" apart uitvoer, werkt dit wel.
Het gaat fout bij de overgang van "DEEL Macro3" naar "DEEL Macro4".
 
Blad2.Range impliceert het gebruik van de zogenaamde "CodeName" van een werkblad, dit is de tweede naam die je naast de "echte" naam van de tab in de projectverkenner ziet staan. Deze CodeName wordt gegenereerd door Excel en kan in de VBA Editor worden gewijzigd (en verandert dan NIET op de tab). ALs je de naam op de tab wil gebruiken is de juiste syntax Worksheets("Blad2").Range.
 
#jkpieterse:
In de tussentijd heb ik de VBA-code als geheel werkend gekregen door de volgende 2 zaken te doen:
- Een extra werkblad aan te maken met de "Codenaam" (EN "echte naam") : Blad2
- In het gedeelte "Draaitabel maken" van "DEEL Macro3" heb ik de volgende regel aangepast:
ActiveSheet.PivotTableWizard TableDestination:=ActiveSheet.Cells(1, 1)
naar
ActiveSheet.PivotTableWizard TableDestination:=Blad2.Cells(1, 1)

Nu wordt er bij het eerste gedeelte van DEEL Macro3 een draaitabel aangemaakt op een nieuw werkblad "Blad3".
Op de achtergrond is op "Blad2" een dezelfde draaitabel aangemaakt. Hier wordt vervolgens zonder foutmeldingen verder meegewerkt.
Na "DEEL Macro4" (en het einde van de gehele VBA-code) heb ik op "Blad4" de tabel, die ik wilde genereren.
(Ik zou vervolgens Blad1, Blad2 en Blad3 kunnen verwijderen.)

Kortom: ik heb de gehele VBA-code werkend, maar nog niet op een mooie, begrijpelijke manier.
Ik zou graag begrijpen, waarom de eerder genoemde foutmelding ontstaat EN hoe dit op een mooie, begrijpelijke manier op te lossen is. ; )
Hopelijk kunt u (of een ander) dit voor mij verduidelijken, zodat ik weer wat wijzer wordt.
Bij voorbaat hartelijk dank voor de tijd en energie!
Bekijk bijlage Master - wo-05-04-2017 - WERKEND GEHEEL.xlsm
 
Zonder (onzin-) gegevens in het bestand of een csv met wat data is dit erg lastig te doen.
 
#jkpieterse:
Hartelijk dank voor uw laatste reactie. Helaas begrijp ik deze niet. Kunt u deze verduidelijken?
Bedoelt u (onzin-) gegevens in het excel-bestand of in de VBA-code?
De gegevens voor de gewenste eindtabel (op Blad4) in het excel-bestand met de VBA-code worden uit bij de eerste post met vraag geplaatste planningen (1001-planning.xls en 1501-planning.xls) gehaald.

Nog een kleine aanvulling op het laatste geplaatste excel-bestand met de in geheel werkende VBA-code:
De VBA-code kun je maar één keer uitvoeren, omdat excel bij het aanmaken van werkbladen en tabellen met "de echte naam" doornummert.
(Ik begrijp bijvoorbeeld, dat als er al eens tot en met Blad4 is aangemaakt, de "echte naam" van het volgende werkblad automatisch Blad5 wordt. Ook al heb je de eerder aangemaakte bladen verwijderd.)
De verwijzingen in mijn VBA-code kloppen daardoor alleen bij de eerste keer uitvoeren van de VBA-code.
Wil je de VBA-code opnieuw laten lopen, dan dien je het excel-bestand te sluiten ZONDER op te slaan (of door het onder een andere naam op te slaan) en het originele bestand opnieuw te openen.
Ik begrijp dat bepaalde naamgevingen en omschrijvingen in mijn VBA-code mooier en beter kunnen.
Zoals gezegd ben ik lerende en sta ik open voor tips. ; )
 
Als je bij alle verwijzingen naar werkbladen de vorm van Worksheets("Naam") gebruikt, dan kan dat met die bladnamen niet fout gaan. Moet je wel als je een werkblad invoegt natuurlijk zorgen dat dat blad de juiste naam krijgt zodat je er evt vererop in je code naar verwijzen kunt.
 
(De bladbenoemingen en -verwijzigingen ga ik proberen "op te poetsen".)

Mijn vraag is echter eigenlijk nog steeds niet beantwoord.
Waarom kreeg ik bij de overgang "DEEL Macro3" naar "DEEL Macro4" (zie de bij de eerste post geplaatste VBA-code EN bestanden) de genoemde meldingen
en hoe is dit op een nettere manier op te lossen.
 
Vermijd 'Select' en 'Activate' in VBA

i.p.v
Code:
Workbooks.Open (FolderPath & Filename), UpdateLinks:=3, Notify:=False
 ActiveSheet.Cells.EntireColumn.Hidden = False
 lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
gebruik:

Code:
  with getobject(FolderPath & Filename)
    .sheets(1).Columns.Hidden = False
    with .sheets(1).Cells(Rows.Count, 1).End(xlUp).offset(1)
 
    end with
  end with

i.p.v.
Code:
    Range("A1").FormulaR1C1 = "ProjectNummer"
    Range("B1").FormulaR1C1 = "ProjectNaam"
    Range("C1").FormulaR1C1 = "Werk"
    Range("D1").FormulaR1C1 = "Team"
    Range("E1").FormulaR1C1 = "Persoon"
    Range("F1").FormulaR1C1 = "X"
    Range("G1").FormulaR1C1 = "Duur"
    Range("H1").FormulaR1C1 = "Begin"
    Range("I1").FormulaR1C1 = "Einde"
    Range("J1").FormulaR1C1 = "Versie"
    Range("K1").FormulaR1C1 = "Opmerking"
    Range("L1").FormulaR1C1 = "SamenVoeg"
    'Eerste twee weken nummeren en doorkopieren
    Range("M1").FormulaR1C1 = "01"
    Range("N1").FormulaR1C1 = "02"
gebruik:

Code:
  range("A1:N1")=split("ProjectNummer ProjectNaam Werk Team Persoon X Duur Begin Einde Versie Opmerking SamenVoeg 01 02")

En zo kunnen we nog wel een hele tijd doorgaan.
 
#snb:
Hartelijk dank voor de concrete voorbeelden ter verbetering. Hier ga ik mee aan de slag!

Ik heb al eens geprobeerd het volgende stuk VBA-code aan te passen, op basis van een eerder voorbeeld van u in een andere post).
In het volgende stukje VBA-code staat namelijk verschillende keren "ActiveSheet." en dan gevolgd door iets. Aan het einde staat een "with".
Ik dacht dit te kunnen vervangen door één "with", waarbij ik de TableDestination één keer concreet benoem. Helaas krijg ik dit niet werkend.
Hoe kan ik dit stukje VBA-code (uit DEEL Macro3) het beste "oppoetsen".

Code:
    'Range selecteren en benoemen
    Range(Cells(1, 12), Cells(erow - 1, lastcolumn)).Select
    ActiveSheet.ListObjects.Add(xlSrcRange, Selection, , xlNo).Name _
    = "myRange"
    
    'Draaitabel maken
    ActiveWorkbook.PivotCaches.Create(SourceType:=xlConsolidation, SourceData:= _
        "myRange", Version:=xlPivotTableVersion14). _
        CreatePivotTable TableDestination:="", TableName:="Draaitabel1", _
        DefaultVersion:=xlPivotTableVersion14
    ActiveSheet.PivotTableWizard TableDestination:=Blad2.Cells(1, 1)
    ActiveSheet.Cells(1, 1).Select
    ActiveSheet.PivotTables("Draaitabel1").DataPivotField.PivotItems( _
        "Aantal van Waarde").Position = 1
    With ActiveSheet.PivotTables("Draaitabel1").PivotFields("Aantal van Waarde")
        .Caption = "Som van Waarde"
        .Function = xlSum
        ActiveSheet.PivotTables("Draaitabel1").PivotFields("Kolom").NumberFormat = "00"
    End With

Ik heb het volgende geprobeerd, maar dit werkt nog niet.
(Ik heb bij de start van de VBA-code in het bestand de volgende lege sheets "Blad1" en "Blad2" (=codenaam en "echte naam").
De gegevens worden uit de aparte planning-bestanden gehaald.)
Code:
    'Range selecteren en benoemen
    With .Sheets(Blad1).Range(Cells(1, 12), Cells(erow - 1, lastcolumn)). _
    ListObjects.Add(xlSrcRange, Selection, , xlNo).Name = "myRange"
    End With
    
    'Draaitabel maken
    ActiveWorkbook.PivotCaches.Create(SourceType:=xlConsolidation, SourceData:= _
        "myRange", Version:=xlPivotTableVersion14). _
        CreatePivotTable TableDestination:=Sheets(Blad2).Cells(1, 1), TableName:="Draaitabel1", _
        DefaultVersion:=xlPivotTableVersion14
    With .Sheets(Blad2)
        .PivotTables("Draaitabel1").DataPivotField.PivotItems("Aantal van Waarde").Position = 1
        .PivotTables("Draaitabel1").PivotFields ("Aantal van Waarde")
        .Caption = "Som van Waarde"
        .Function = xlSum
        .PivotTables("Draaitabel1").PivotFields("Kolom").NumberFormat = "00"
    End With

Bij voorbaat dank voor uw hulp.
 
Je zult toch eerst moeten studeren op wat With... End with precies is.
Daar bestaan boeken over.
 
Hieruit concludeer ik, dat ik toch wel een lastig te beantwoorden vraag stel...
 
Nee hoor, maar het antwoord moet wel begrepen kunnen worden. Als ik je een antwoord in het Italiaans geef, zul je eerst Italiaans moeten bestuderen om mijn antwoord te begrijpen. Dat geldt voor VBA (is ook gewoon een taal) ook. Het geven van een antwoord kan voor de beantwoorder simpeler zijn dan het begrijpen van het antwoord door de vragensteller. De vraag is dus niet moeilijk, het begrip van het antwoord eventueel wel.

Ik beschouw een forum niet als een online-cursus, maar als een plaats waar je vragen kunt stellen over een specifieke kwestie/opgave; de kennis van basisbegrippen veronderstel ik aanwezig bij de vragensteller, conform het adagium: gebruik geen VBA-code die je niet begrijpt.
 
Laatst bewerkt:
Stel u gaat een weekje op vakantie naar Italië. Doet u dan vooraf een complete cursus Italiaans, zodat u vloeiend Italiaans spreekt?
Of zoekt u de basis beginselen op, zodat u zich al aardig kan redden "met handen en voeten" (en een beetje begrip en waardering van de Italianen, omdat u het in ieder geval probeert)?

Wellicht kunt u de vertaling van dat ene, wat moeilijkere zinnetje net niet vinden? Voelt u zich dan toch verplicht om die complete cursus Italiaans te volgen?
Of vraagt u bijvoorbeeld de Italiaan op de hoek vriendelijk om wat hulp, omdat hij de taal beter spreekt dan u?

Wellicht ervaart hij het als een kleine moeite om u met deze vraag vooruit te helpen en bent u er voldoende mee geholpen...
Of zou hij u vragen toch maar eerst een complete cursus Italiaans te volgen, voordat u hem deze ene vraag stelt?!
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan