VBA Access: public function laten verwijzen naar een subform i.p.v. een form

Status
Niet open voor verdere reacties.

AvantiConLaCapra

Gebruiker
Lid geworden
11 sep 2016
Berichten
44
Hallo iedereen,

Ik heb het volgende probleem:
Ik heb een module gemaakt met een x-aantal public functions die waarden instellen.
Eentje daarvan heeft de waarde van het formulier waarop ik werk.
Dit gaat allemaal prima maar nu is het noodzakelijk dat dit formulier als subformulier wordt toegepast.
Hierbij werkt de functie die verwijst naar het formulier niet meer.

De functie is erg eenvoudig:

Code:
Public Function FRM() As Object
Set FRM = Screen.ActiveForm
End Function

Hij wordt opgeroepen door andere functies die bijvoorbeeld veldbreedte van een veld op het subformulier instellen.

Hoe bouw ik deze functie om zodat hij ook werkt op een subformulier?
 
Ik zou nooit met screen.aciveform werken (zul je mij dus ook nooit zien doen) maar het bewuste formulier meegeven als parameter in de functie.
Code:
Public Function JouwFunctie( frm as Form)
 
Als die functies niets anders doen dan waarden instellen/aanmaken die je dan zogezegd overal kan gebruiken is het dan niet makkelijker deze waarden te laten aanmaken via de TempVars?
 
Dank voor jullie reacties!

Ik heb vrij veel zijdelings met VBA te maken gehad maar heb nog nooit zelf iets opgezet, tot nu :cool:
Erg leuk om te doen maar ook veel om te leren.

Jouw opmerking is terecht octafish, activescreen is niet ideaal (vrij zinnig aangezien het scherm niet 100% actief is).
Ik roep andere subroutines op die gebruik maken van de functie FRM, zou ik dan jouw oplossing kunnen gebruiken om de functie FRM aan te roepen en vervolgens de subroutines? Ga ik proberen!

Johan, je zult ongetwijfeld gelijk hebben, ik heb ook teveel functies waardoor ik een stack overflow krijg. Ik zat al te denken om dat anders op te lossen maar wist niet hoe... De help gaf aan om ze vanuit 1 subroutine aan te roepen maar dan zijn ze weer niet publiekelijk toegankelijk, iets wat wel noodzakelijk is omdat er meerdere routines gebruik van maken.
Heb je een voorbeeld voor me hoe ik een dergelijke tempvar kan maken?
 
Ik roep andere subroutines op die gebruik maken van de functie FRM, zou ik dan jouw oplossing kunnen gebruiken om de functie FRM aan te roepen en vervolgens de subroutines?
...
Heb je een voorbeeld voor me hoe ik een dergelijke tempvar kan maken?

Ad 1:
Ik gebruik bijvoorbeeld een functie om alle controls op een formulier in te stellen.
Code:
Function BewaarWaarden(frm As Form)
Dim ctl As Control, lst As Access.ListBox
Dim X As Integer, iLst As Integer
Dim itm As Variant, tmp As Variant
Dim sKeuze As String

        With ctl
            Select Case .ControlType
                Case acTextBox
                    If Not .Value = "" Then
                        X = X + 1
                        If X = 1 Then ReDim arrWaarden(X) Else: ReDim Preserve arrWaarden(X)
                        arrWaarden(X) = .Tag & "|" & .Value & "|" & .Name
                    End If
                Case acListBox
                    '-------------------------------------------------------------------------------------------
                    'Een listbox kan meerdere items bevatten die geselecteerd worden.
                    'Die moeten allemaal apart worden uitgelezen.
                    '-------------------------------------------------------------------------------------------
                    ''Set lst = frm(.Name).ListBox
                    tmp = .Name
                    Set lst = frm(tmp)
                    sKeuze = ""
                    If lst.ItemsSelected.Count >= 1 Then
                        X = X + 1
                        If X = 1 Then ReDim arrWaarden(X) Else: ReDim Preserve arrWaarden(X)
                        For Each itm In lst.ItemsSelected
                            If sKeuze & "" <> "" Then sKeuze = sKeuze & "\"
                            sKeuze = sKeuze & lst.ItemData(itm)
                        Next itm
                        arrWaarden(X) = .Tag & "|" & sKeuze & "|" & .Name
                    End If
                Case acComboBox
                    If Not .Value = "" Then
                        X = X + 1
                        If X = 1 Then ReDim arrWaarden(X) Else: ReDim Preserve arrWaarden(X)
                        arrWaarden(X) = .Tag & "|" & .Value & "|" & .Name
                    End If
                Case acCheckBox
                    If Not .Value = "" Then
                        X = X + 1
                        If X = 1 Then ReDim arrWaarden(X) Else: ReDim Preserve arrWaarden(X)
                        arrWaarden(X) = .Tag & "|" & .Value & "|" & .Name
                    End If
            End Select
        End With
    Next ctl

Die functie roep je dan bijvoorbeeld zo aan:
Code:
Private Sub Form_BeforeUpdate(Cancel As Integer)
    BewaarWaarden Me
End Sub

Dus die functie van jou is echt nergens voor nodig, en alleen maar foutgevoelig.

Ad 2:
Bij het starten van de db maak ik gelijk een paar TempVars aan. Voorbeeldje:
Code:
            TempVars.Add "varMedewerkerID", !medewerkerID.Value
            TempVars.Add "varMedewerkerNaam", !medewerker_naam.Value
            TempVars.Add "varAccessLevel", !rechten.Value
            TempVars.Add "varActief", !Actief.Value
            TempVars.Add "varStatus", "START"
Deze laat ik dan ofwel staan (MewerkerID blijft bijvoorbeeld gedurende de hele sessie onveranderd) of vul ik als er iets moet gebeuren op een formulier. Zo verander ik de status regelmatig om een formulier in een andere modus te openen.
Code:
    TempVars("varStatus").Value = "ZOEKEN"
En op het betreffende formulier gebruik ik dan deze status bij het openen van het formulier:
Code:
    Select Case TempVars("varStatus").Value
        Case "START"
            If TempVars("varActief") = False Then
                MsgBox "Je bent niet gemachtigd om in te loggen; neem contact op met de beheerder.", vbCritical
                Exit Sub
                Application.Quit
            End If
            strZoek = "(persoonID In(SELECT persoon_ID_d FROM tDossiers WHERE ((afsluitdatum_d Is Null) AND (Medewerker_ID_d = " & TempVars("varMedewerkerID") & ")) GROUP BY persoon_ID_d;)) "
            strTabel = strTabel & strZoek
            With Me
                .RecordSource = strTabel
            End With
        Case "OPEN"
        Case "EDIT"
        Case "NIEUW"
    End Select
Etc. Hier worden eerder gedefinieerde en gevulde TemVars gebruikt om selecties te maken, of een formulier te sluiten.
 
Zoals steeds van Michel een uitgebreide uitleg waar ik misschien één ding kan bijvoegen is dat die Tempvars PC gebonden is en dat je dus misschien best bij het afsluiten van de DB ook die tempvars verwijdert.
Je kan ze allemaal ineens verwijderen (TempVars.Removeall ) of specifiek per stuk (bv TempVars.Remove "varMedewerkerID"). Zo vermijdt je dat een andere gebruiker soms dingen ziet bij het heropstartten van de DB op dezelfde PC (een tempvar overleeft nml een programmacrash). De tempvars worden zowieso verwijderd bij het normaal afsluiten van de DB en/of de PC. Meer uitleg omtrent de tempvars vindt je overal op internet bv hier en hier
 
... dat die Tempvars PC gebonden is en dat je dus misschien best bij het afsluiten van de DB ook die tempvars verwijdert.
Volgens mij zitten de Tempvars in de db en niet in de pc. De tempvars worden dus vanzelf verwijderd als je de database afsluit. Geen extra handeling nodig. Maar het mag natuurlijk altijd. De grap is: bij een crash wórdt er natuurlijk nooit netjes afgesloten. Daarom definieer ik de tempvars altijd bij het openen van de db, dan zijn ze ook leeg.
 
Michel, ik lees her en der dat die tempvars in de memory zitten en een gecrashte DB afsluiten via bv Ctrl+Alt+Delete verwijderd die Tempvars waarschijnlijk dus niet.
Speelt eigenlijk allemaal geen rol aangezien we ze normaal (her)definiëren bij het opstartten van een DB.
 
... dat die tempvars in de memory zitten en een gecrashte DB afsluiten via bv Ctrl+Alt+Delete verwijderd die Tempvars waarschijnlijk dus niet.
Dat heb ik dus nog nooit ergens gelezen. Bovendien: als er iets is dat je geheugen leegmaakt, dan is het Ctrl+Alt+Delete :). Niet op een mac; althans: mijn G5 start gewoon weer op waar-ie gebleven was. Maar da's dan ook geen echte pc...
 
"By default, a TempVar object remains in memory until Access is closed." aldus microsoft: https://msdn.microsoft.com/en-us/library/office/ff193475.aspx
Dus tenzij je niets doet vervallen ze als access gesloten wordt.

Voor mij even een resume:

Momenteel heb ik meldingen van stack overflow omdat de functies onderling elkaar ook aanroepen wat het geheugen te zwaar belast. Dit is anders met tempvars?

Ik heb 59 functies en 11 subroutines.
De reden voor mij om die functies te maken is omdat ik niet in alle subroutines de variabelen en diens waarden wil declareren. Dit kan ik dus doen met tempvars voor de functies die alleen maar waarden bevatten begrijp ik.
Daarnaast kan ik een subroutine maken die de tempvars bepaald en instelt bij het openen van het formulier/de db.

Ik heb binnen de 59 functies een aantal die in een later stadium uit een tabel gehaald kunnen worden en dus vervallen, de anderen zijn berekende waarden, deze zullen dus in een subroutine bepaald moeten worden zodra ze bepaald worden/wijzigen.
Een klein aantal bevat vaste waarden.

De kortste klap is nu: een subroutine maken die de berekende tempvars bepaald zodat een groot aantal functies vervallen + de subroutines zo wijzigen dat de benodigde info meekomt bij het oproepen waardoor er nog een aantal vervallen en mijn probleem met FRM is opgelost.

Kom ik even terug op mijn initiële vraag: stel ik geef de formuliernaam mee bij het aanroepen van de subroutines, hoe doe ik dat dan vanaf een subformulier?

edit: even getest: die neemt hij op dezelfde manier mee :cool:
 
Laatst bewerkt:
Ik heb daar dus nooit last van, ongeacht hoe groot of klein de db's zijn, en het aantal modules en /of functies. Ben benieuwd hoe jij het wél voor elkaar krijgt :).
 
Dat is vrij simpel eigenlijk :eek:

De reden om deze gegevens als functies in het geheugen te zetten is omdat ik deze gegevens continue gebruik, dus ook binnen diezelfde functies.
Binnen 1 functie worden misschien wel 4 of 5 anderen aangeroepen etc. etc.
Om 1 waarde te bepalen worden er misschien wel 40 varianten in het geheugen gezet :eek: Doe dat heel veel en snel achter elkaar et voila!
 
Ik bedoelde met de Ctrl+Alt+Delete je taakbeheer openen en dan de gecrashte DB applicatie sluiten, dus niet compleet herstartten van de PC af afmelden of zo.
 
Ik heb nu alles omgebouwd naar tempvars en dat werkt perfect :thumb:
Wel moet ik alle tempvars nu declareren bij elke subroutine natuurlijk maar goed, functionaliteit gaat voor.

Ik kan nu mijn subroutine aanroepen ongeacht ik het vanaf het formulier als hoofd- of subformulier doe.
Sterker nog, ik kan hetzelfde formulier 2x als subformulier op hetzelfde hoofdformulier aanroepen en andere waarden geven met behulp van 1 en dezelfde subroutine :d

En uiteraard geen stack overflow meer aangezien het herhalende rekenwerk nu binnen de routine gebeurt :cool:

Dank voor de hulp!
 
Wel moet ik alle tempvars nu declareren bij elke subroutine natuurlijk maar goed, functionaliteit gaat voor.
Waarom? Je kunt best in één keer op één (start)formulier alle TempVars declareren en met Null vullen bijvoorbeeld. Of andere waarden die op dat moment bekend zijn.
 
Jij maakt dus op 1 formulier(plaats) alle tempvars aan en vult deze later wanneer ze aan bod komen?

Ik heb ze gedeclareerd omdat ik onderling gebruik maak van de tempvars. Dat leverde mij ook het probleem op met stack overflow.

Voorbeeld:

tempvar 1 = tempvar2 + tempvar 3/tempvar16 etc...
Het gaat bij mij vrij veel om rekenwerk, daarom gebruik ik ze ook veel.
Ik had alle berekeningen al klaar, verwijzend naar de public functions.

De benaming van de public functions heb ik behouden en verwezen naar de tempvars.
Public functions kun je gemakkelijk oproepen: 1=2+3/16 maar tempvars moet je oproepen zoals ik hier boven aangaf.
Vandaar dat ik ze eerst gedeclareerd heb. 1= tempvar 1, 2 = tempvar 2 etc.

In een nieuwe situatie zal ik jouw idee eens proberen :thumb:
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan