MS Access. - Class Module.

Van Objecten en Class modules

Het begrip object is niet weg te denken in VBA en bij programmeer talen in het algemeen. Wat in eerste instantie abstract klinkt kan voor een Access gebruiker duidelijker worden wanneer men bedenkt dat Formulieren, Controle-elementen zoals knoppen, combo’s..enz, als objecten kunnen beschouwd worden. Men kan een object programmeren, manipuleren en er controle op uitoefenen.

Objecten hebben eigenschappen (Propertys) en methoden (Methods).

Een eigenschap kan gezien worden als bijvoeglijk naamwoord, het zegt iets over de karakteristieken van een object. Nemen wij een tekstvak controle-element, het kan zichtbaar (visible) zijn, het kan een bepaalde achtergrond (background color) kleur hebben, de letters kunnen een belaalde kleur (forecolor) hebben.De meeste eigenschappen van een object kunnen ingesteld en gelezen worden, bepaalde kunnen enkel gelezen worden.

Een methode is een actie die op een object kan uitgevoerd worden, een methode kan gezien worden als een werkwoord. Op een tekstvak kan de focus geplaatst worden (setfocus), een formulier kan geactualiseerd worden met de requery of refresh methode.

VBA en MS Access bieden de mogelijkheid dat een Access ontwikkelaar zelf objecten creëert, en er eigenschappen en methodes aan toewijst. Deze werkwijze biedt verschillende voordelen :

  • Complexe functionaliteit wordt in het object ingekapseld en kan aangesproken worden via de eigenschappen en methodes van het object wat voor gebruikers veel gemakkelijker is.
  • In de object browser van de VBA-editor is het object met zijn eigenschappen en methode s gevisualiseerd.
  • Intellisense is beschikbaar, wanneer men in de VBA editor verwijst naar een variabele van het object.
  • Van een object kunnen terzelfdertijd meerdere instanties gecreëerd en gebruikt worden.
  • Een object kan in meerdere toepassingen gebruikt worden en zodoende structuur brengen in uw programmacode.

In VBA worden objecten gecreëerd via de VBA-editor in een "Class module". Men spreekt dan ook van "Classes". Het is handig indien men bij de naamgeving van een Class duidelijk verwijst naar de aard ervan. Als prefix voor de naam gebruik ik cls. Stel dat men een Class wil maken over het beheer van een club dan noem ik die clsClub. Men kan aan de naam ook een suffix toevoegen, bijvoorbeeld de initialen van de ontwikkelaar.

Een Class module beschikt steeds over een Initialize, wanneer een instantie van een Claas gecreëerd wordt, en een Terminate gebeurtenis (Event) wanneer de dinstantie van de class teniet gedaan wordt door de Class gelijk te stellen aan Nothing.

Instellen van Eigenschappen of Properties kan op twee manieren :

  1. Door het gebruik van Publieke Variabelen in een Class module.
  2. Door het gebruik van Property procedures in een Class module.

Begin

Gebruik van Publieke Variabelen in een Class module

De Class module krijgt de naam clsClub
Twee publieke variabelen worden gedeclareerd.

Public Lid as string
Public LidType as string

In een gewone module kan men dan de Class clsClub aanspreken :

            Dim mijnClub as New clsClub
            ' eigenschap instellen doet men als volgt :
            mijnClub.Lid = “André”
            mijnClub.LidType = “Gewoon lid”
            'eigenschap opvragen : 
            strLid = mijnClub.lid
            

De eigenschap is steeds bewerkbaar, kan dus gelezen worden en men kan ernaar schrijven. Het creëeren van eigenschappen via publieke variabelen is dus vrij eenvoudig. Nadeel is dat externe processen de waarde kunnen wijzigen en dat men controle verliest, bijvoorbeeld in het beperken van mogelijke waarden of het nemen van acties bij het wijzigen van de waarde.
Dit euvel kan vermeden worden door gebruik te maken van Property Procedures.

Begin

Gebruik van Property procedures in een Class module

Men heeft drie types van Property Procedures :

  1. Property Get : om de waarde van de property of eigenschap op te vragen.
  2. Property Let : om de waarde van de property of eigenschap in te stellen.
  3. Property Set : om de waarde in te stellen wanneer men met objecten te doen heeft.

De eerste stap bestaat er steeds in met de declareren van een Private variabele ( en dus verdoken ) op module niveau. Vervolgens maakt men gebruik van boven vermelde procedures. Deze kunnen zowel Private als Public gedeclareerd worden. Een andere merkwaardigheid bestaat erin dat de procedures (dus zowel Get en Let/Set) dezelfde naam mogen hebben

Passen wij de Class module clsClub aan :

' Maak twee private variabelen aan in de declaratie sectie
Private mstrLid as String
Private mstrLidType as String

' Met de Property Get procedure biedt men de mogelijkheid om de eigenschap of property op te vragen. Wil men dit niet, gebruik dan de Property Get procedure niet. De Procedure geeft de waarde van de verdoken, private, variabele.
Public Property Get Lid () As String
'neem de waarde van de gedoken variabele mstrLid

Lid = mstrLid
End Property

Public Property Get LidType As String
LidType = mstrLidType
End Property

'Met de Property Let procedure wordt de waarde ingesteld, wil men dit onmogelijk maken, gebruik dan deze procedure niet.
Public Property Let Lid (strNaamLid as string)
' ken de waarde toe aan de gedoken variabele
mstrLid = strNaamLid
End Property

Pubblic Property Let LidType(strLidType as String)
 mstrLidType = strLidType
End Property

In een gewone module kan men dan de Class clsClub aanspreken :

            Dim mijnClub as New clsClub
            ' eigenschap instellen doet men als volgt :
            mijnClub.Lid = “André”
            mijnClub.LidType = “Gewoon lid”
            'eigenschap opvragen : 
            strLid = mijnClub.lid
            

Met de Property Set procedure kan men een referentie leggen naar een object. Beschouwen wij de Class module clsFormulier

            Private mobjFormulier As Form
            
            Public Property Get Formulier() As Variant
            ' Neem het object verdoken in de private variabele mobjFormulier en ken het toe aan de Property waarde 
             Set Formulier  = mobjFormulier
            End Property
            
            Public Property Set Formulier(FormulierObject)
            'bewaar het object in FormulierObject en bewaar het in de private, verdoken, variabele mobjFormulier
             Set mobjFormulier = FormulierObject
            End Property
            

Begin

Instellen van de Methodes van een object.

Een methode die kan gezien worden als een actie die op een object kan uitgevoerd worden, kan ingesteld worden door het creëeren van een publieke Sub of Functie in een Class-module.
Hier enkele voorbeelden van Class Modules.

Zijn er records in een DAO.recordset.

Alvorens aan het werk te gaan met een DAO.Recordset dient men in principe steeds te controleren als de recordset records bevat, men kan dit natuurlijk in de plaatselijke code testen, of gebruikmaken van deze class, wat handiger is.

Code in de Class clsTelRec

Option Compare Database
            Option Explicit
            
            Private varTabel As Variant
            Private varAantal As Variant
            Private db As DAO.Database
            Private rst As DAO.Recordset
            
            Public Property Get Tabel() As Variant
                Tabel = varTabel
            End Property
            
            Public Property Let Tabel(ByVal vNewValue As Variant)
                varTabel = vNewValue
            End Property
            
            Public Property Get Aantal() As Variant
                Set rst = db.OpenRecordset(varTabel, dbOpenSnapshot, dbReadOnly)
                If Not rst.EOF And Not rst.BOF Then
                    rst.MoveLast
                    varAantal = rst.RecordCount
                Else
                    varAantal = 0
                End If
                Aantal = varAantal
            End Property
            
            Private Sub Class_Initialize()
                Set db = CurrentDb
            End Sub
            
            Private Sub Class_Terminate()
                On Error Resume Next
                rst.Close
                Set rst = Nothing
                db.Close
                Set db = Nothing
            End Sub
            

Gebruik van de clsTelRec.

Dim varAantal As clsTelRec
            Set varAantal = New clsTelRec
            
            varAantal.Tabel = "tblTest"
            If varAantal.Aantal > 0 Then
                open de recordset en doe iets
            End If
            

Let op het begruik van Class_Initialize() hier wordt de variabele db toegewezen aan de actuele database, waar met Class_Terminate() zowel database en recordset variabelen worden geledigd.

Methodes Classes zijn er records 2.

Een methode die kan gezien worden als een actie die op een object kan uitgevoerd worden, kan ingesteld worden door het creëeren van een publieke Sub of Functie in een Class-module.
Hier enkele voorbeelden van Class Modules.

Zijn er records in een DAO.recordset gebaseerd op een SQL clausule met parameter.

Alvorens aan het werk te gaan met een DAO.Recordset dient men in principe steeds te controleren als de recordset records bevat, men kan dit natuurlijk in de plaatselijke code testen, of gebruikmaken van deze class, wat handiger is.Hier is de recordset gebaseerd op een SQL-clausule

Option Compare Database
            Option Explicit

            Private varTabel As Variant
            Private varVeldNaam As Variant
            Private varVeldWaarde As Variant
            Private varAantal As Variant
            Private strVeldWaarde As String
            Private lngVeldWaarde As String
            Private strSQL As String
            Private db As DAO.Database
            Private rst As DAO.Recordset

            Public Property Get Tabel() As Variant
                Tabel = varTabel
            End Property

            Public Property Let Tabel(ByVal varNaamTabel As Variant)
                varTabel = varNaamTabel
            End Property

            Public Property Get VeldNaam() As Variant
                VeldNaam = varVeldNaam
            End Property

            Public Property Let VeldNaam(ByVal varNaamVeld As Variant)
                varVeldNaam = varNaamVeld
            End Property

            Public Property Get VeldWaarde() As Variant
                VeldWaarde = varVeldWaarde
            End Property

            Public Property Let VeldWaarde(ByVal varWaardeVeld As Variant)
                varVeldWaarde = varWaardeVeld
                    If IsNumeric(varVeldWaarde) Then
                        lngVeldWaarde = CLng(varVeldWaarde)
                        strSQL = "SELECT * FROM " & varTabel & " WHERE " & varVeldNaam & " = " & lngVeldWaarde
                    Else
                        strVeldWaarde = CStr(varVeldWaarde)
                        strSQL = "SELECT * FROM " & varTabel & " WHERE " & varVeldNaam & " = """ & strVeldWaarde & """"
                    End If
            End Property

            Public Property Get Aantal() As Variant

            Set rst = db.OpenRecordset(strSQL, dbOpenSnapshot, dbReadOnly)
                If Not rst.EOF And Not rst.BOF Then
                    rst.MoveLast
                    varAantal = rst.RecordCount
                Else
                    varAantal = 0
                End If
                Aantal = varAantal
            End Property

            'Public Property Let Aantal(ByVal vNewValue As Variant)
            '    varAantal = vNewValue
            'End Property
            Private Sub Class_Initialize()
                Set db = CurrentDb
            End Sub

Namen van Foto-bestanden in groep wijzigen.

Een methode die kan gezien worden als een actie die op een object kan uitgevoerd worden, kan ingesteld worden door het creëeren van een publieke Sub of Functie in een Class-module.
Hier enkele voorbeelden van Class Modules.

Fotobestanden die van een digitaal fototoestel of een flashcard afgeladen worden hebben een naam in de vorm van img_0018.jpg. Wanneer men de bestanden van de flashcard wist, zijn er toestellen die de naamgeving vanaf 0001 herstarten, vb img_0001.jpg, img_0002.jpg enz. Zodoende kan men identieke namen hebben voor verschillende foto's.
Omwille daarvan is het aangewezen de oorspronkelijk naam te wijzigen. In de regel moeten er nogal wat bestanden een andere naam krijgen. De nieuwe naam kan bijvooorbeeld naar een datum, gebeurtenis, reis enz verwijzen, maar met liefst ook een oplopend volgnummer op het einde van de naam (maar vóór de extensie natuurlijk).
De class clsHernoem verwezenlijkt dit.
Door gebruik te maken van het FileDialog object van Office, impliceert de clsHernoem dat er een referentie gelegd wordt de Office Object Library.
Zodoende kan de gebruiker met het vertrouwde Office mappen- en bestanden-dialoog kader, de fotobestanden kiezen waarvan de naam moet gewijzigd worden.

Option Compare Database
                Option Explicit
                
                Private mstrNieuweNaam As String
                Private mstrFotoNaam As String
                Private mstrPad As String
                Private mstrTypeFoto As String
                
                Public Property Let TypeFoto(strTypeFoto As String)
                        mstrTypeFoto = strTypeFoto
                End Property
                
                Public Property Let NieuweNaam(ByVal strNieuweNaam As String)
                    mstrNieuweNaam = strNieuweNaam
                End Property
                
                Private Function GeefFotoNm(mstrPad)
                'enkel de naam van de foto zonder pad
                Dim intLen As Integer
                intLen = Len(mstrPad)
                Dim intDum As Integer
                    For intDum = Len(mstrPad) To 1 Step -1
                        If Mid(mstrPad, intDum, 1) = "\" Then
                           GeefFotoNm = Mid(mstrPad, intDum + 1)
                            Exit For
                        End If
                    Next intDum
                End Function
                
                Private Function fGeefPad(mstrPad As String) As String
                'enkel het volledig pad zonder de fotonaam
                Dim intLen As Integer
                intLen = Len(mstrPad)
                Dim intDum As Integer
                    For intDum = Len(mstrPad) To 1 Step -1
                        If Mid(mstrPad, intDum, 1) = "\" Then
                            fGeefPad = Left(mstrPad, intDum)
                            Exit For
                        End If
                    Next intDum
                End Function
                
                Private Function fGenerStringTeller(intTel As Integer) As String
                ' om een oplopend nummer te maken en te voegen achter de naam van de foto
                Dim strTeller As String
                strTeller = CStr(intTel)
                Select Case Len(strTeller)
                    Case 1
                        fGenerStringTeller = "00" & strTeller
                    Case 2
                        fGenerStringTeller = "0" & strTeller
                    Case 3
                        fGenerStringTeller = strTeller
                End Select
                End Function
                
                Public Sub Hernoem()
                Dim varPadFoto As Variant
                Dim dlgDialoog As Office.FileDialog
                Dim intTel As Integer
                intTel = 1
                
                Set dlgDialoog = Application.FileDialog(msoFileDialogFilePicker)
                    With dlgDialoog
                        .Title = "Kies fotos waarvan de naam moet gewijzigd worden"
                        .AllowMultiSelect = True
                        .Filters.Clear
                        .Filters.Add "jpg's", "*.jpg"
                        .Filters.Add "bitmaps", "*.bmp"
                        .Filters.Add "gif's", "*.gif"
                        If .Show = True Then
                
                         'Loop doorheen iedere geselecteerd bestand.
                         For Each varPadFoto In .SelectedItems
                            mstrPad = fGeefPad(CStr(varPadFoto))
                            Exit For
                         Next
                
                         For Each varPadFoto In .SelectedItems
                            Name CStr(varPadFoto) As mstrPad & mstrNieuweNaam & fGenerStringTeller(intTel) & mstrTypeFoto
                            intTel = intTel + 1
                         Next
                         MsgBox intTel - 1 & " foto's kregen nieuwe naam: " & mstrNieuweNaam, vbOKOnly, "Foto's hernoemen"
                      Else
                         MsgBox "U koos ervoor om niet te hernoemen."
                      End If
                
                    End With
                Set dlgDialoog = Nothing
                End Sub
                

Via een formulier frmBestHernoem maken wij gebruik van de clsHernoem.Het formulier heeft drie controle-elmenten:

  1. Een tekstvak, txtNieuweNaam, hier wordt de nieuwe naam ingegeven, zonder volgnummer (de class doet dit) en zonder extensie.
  2. Een combo, cboTypeFoto, hier moet de extensie voor de foto gekozen worden, is standaard JPG.
  3. Een drukknop, cmdHernoemen, die de code hieronder activeert.

Option Compare Database
                Option Explicit
                
                Private Sub cmdHernoemen_Click()
                    Dim objHernoem As clsHernoem
                    Set objHernoem = New clsHernoem
                    If Not Len(Me.txtNieuweNaam) < 2 Then
                    objHernoem.NieuweNaam = Me.txtNieuweNaam
                    objHernoem.TypeFoto = Me.cboTypeFoto
                    Else
                    Exit Sub
                    End If
                
                    If MsgBox("Namen wijzigen !! ?" & vbCrLf & "Bewerking kan niet ongedaan gemaakt worden.", vbCritical + vbYesNo, "Opgepast") Then
                    objHernoem.Hernoem
                    End If
                
                End Sub
                
                Private Sub Form_Open(Cancel As Integer)
                Me.cboTypeFoto = ".jpg"
                End Sub
                
Begin

Events creëren in Class modules.

Objecten in Access hebben Events. Bijvoorbeeld een formulier heeft een 33-tal Events, On Open, On Close, On Load, On Activate...enz. Een knop of command button een 12-tal Events, On Click, On Enter, On Exit. Al deze events kunnen via code een actie op gang brengen.

Voor objecten en meer bepaald voor Class-modules, die men als gebruiker zelf creëert kan men zelf Events of gebeurtenissen definiëren. Daartoe moet men gebruik maken van het Event sleutelwoord (Keyword), in de declaratie sectie van een Class-module en moet men de gebeurtenis een zelf gekozen naam geven.

Om een gebeurtenis Boodschap te creëren moet men volgende code in de declaratie sectie van de Class-module voorzien:
Public Event Boodschap()

Wil men de Event Boodschap() opwekken dan moet men dit via het Raise sleutelwoord in een methode van het object.

Hier een voorbeeld van één formulier frmNedBericht die kan gebruikt worden als variant op MsgBox Functie.
Bemerk dat de code achter één formulier steeds in een Class-module ingebed is.

            Option Compare Database
            Option Explicit
            Instellen van de Voltooid gebeurtenis
            Public Event Voltooid(intWat As Integer)
            
            Private intGekozenKnop As Integer
            Private varBoodschap As Variant
            Private varOpschrift As Variant
            
            Public Property Get Boodschap() As Variant
                Boodschap = varBoodschap
            End Property
            
            Public Property Let Boodschap(ByVal vNewValue As Variant)
                varBoodschap = vNewValue
                Me.txtTest = varBoodschap
                Me.txtTest.Enabled = (Len(varBoodschap) <> 0)
            End Property
            
            Public Property Get Opschrift() As Variant
                Opschrift = varOpschrift
            End Property
            
            Public Property Let Opschrift(ByVal vNewValue As Variant)
                varOpschrift = vNewValue
                Me.Caption = varOpschrift
            
            End Property
            
            Private Sub cmdJa_Click()
                intGekozenKnop = 6
                    Call Form_Timer
            End Sub
            
            Private Sub cmdNee_Click()
                intGekozenKnop = 7
                    Call Form_Timer
            End Sub
            
            Private Sub cmdSluiten_Click()
                intGekozenKnop = 2
                    Call Form_Timer
            End Sub
            
            Private Sub Form_Timer()
                DoCmd.Close acForm, Me.Name
            End Sub
            
            Private Sub Form_Unload(Cancel As Integer)
            'Opwekken van de Voltooid gebeurtenis
            RaiseEvent Voltooid(intGekozenKnop)
            End Sub
            
            Public Property Get Gekozen() As Variant
                Gekozen = intGekozenKnop
            End Property
            
            Private Sub Class_Initialize()
            Me.TimerInterval = 2000
            End Sub
            

Om gebruik te maken van een zelf gecreëerde Event moet men een object variabele van de Class declareren in de declaratie sectie van de module men moet daarbij gebruik maken van het WithEvents sleutelwoord. Opgepast WithEvents kan enkel gebruikt worden in Class modules (in Formulieren dus wel)iet in gewone standaard modules.
Hier een voorbeeld van de Form_NedBericht

            Option Compare Database
            Option Explicit
            
            Private WithEvents mijnbericht As Form_frmNedBericht
            Public intRespons As Integer
            
            Private Sub cmdTest_Click()
            
            Set mijnbericht = New Form_frmNedBericht
            mijnbericht.Opschrift = "Testen van Nederlandstalige boodschap"
            mijnbericht.Boodschap = "Wil u doorgaan kies dan voor ja, zoniet kies dan Nee"
            
            mijnbericht.Visible = True
            mijnbericht.Modal = True
            
            End Sub
            
            Private Sub mijnbericht_Voltooid(intWat As Integer)
            intRespons = mijnbericht.Gekozen
            If intRespons = 6 Then
                Me.lblBoodschat.Caption = "De gebruiker heeft Ja gekozen"
            'hier kan andere code en een Functie of Sub aangespreoken worden
            End If
            
            If intRespons = 7 Then
                Me.lblBoodschat.Caption = "De gebruiker heeft Nee gekozen"
            End If
            End Sub
            

Begin

Een Chronometer.

Voorzie volgende code in een Class module en noem de module clChrono

Option Compare Database
            Option Explicit
            Private m_lngStart As Long
            Private Declare Function timeGetTime Lib "winmm.dll" () As Long
            
            Public Sub StartTimer()
                m_lngStart = timeGetTime
            End Sub
            
            Public Function EndTimer() As Long
                'geeft verlopen milliseconden op
                EndTimer = (timeGetTime - m_lngStart)
            End Function

            

Wav bestanden afspelen in Access.

Voorzie volgende code in een Class module en noem de module clMuziek

Option Compare Database
            Option Explicit
            
            Private Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long
            
            Public Sub Afspelen(strWav As String)
            'strWav = volledig pad
            Const cSND_SYNC = &H0
            Const cSND_ASYNC = &H1
            Const cSND_NODEFAULT = &H2
            Const cSND_LOOP = &H8
            Const SND_NOSTOP = &H10
            ' Afspelen
                sndPlaySound strWav, cSND_ASYNC            
            End Sub
            
Begin

hallo