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 :
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 :
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.
Gebruik van Property procedures in een Class module
Men heeft drie types van Property Procedures :
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
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:
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
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
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
hallo