B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
B3-cursus Practicumopdracht 3
Ontwikkelen met MS Access Doelstelling bij deze practicumopdracht: 1) verdere kennismaking met ‘gebruikers’-aspecten van MS Access (zoals ‘Filters’) 2) verdere kennismaking met ‘ontwikkelaars’-aspecten van MS Access (tabelstructuur en Forms)
1. Meer over het vastleggen van een gewenste tabelstructuur We herhalen hier de figuur uit practicumopdracht 2, waarin via een dialoogvenster je de mogelijkheid wordt geboden om de gewenste structuur van een gegevenstabel te definiëren. Datzelfde dialoogvenster komt ook te voorschijn als je de structuur van een tabel wilt aanpassen en daarvoor in het databasevenster, met de betreffende gegevenstabel geselecteerd, klikt op de ‘Design’-knop. We richten ons in deze opdracht vooral op een aantal van de mogelijkheden die linksonder in die figuur via de ‘General’-tab worden geboden. We zien daar staan (voor een Text-veld!!): • Field Size • Format • Input Mask • Caption • Default Value • Validation Rule • Validation Text • Required • Allow Zero Length • Indexed Bij velden van andere datatypes (dan Text) kan deze trits instel-mogelijkheden er iets anders uit zien. De eigenschappen ‘Validation Rule’ en ‘Validation Text’ horen bijelkaar, net zoals ‘Required’ en “Allow Zero Length’. Als we via een zelfgemaakte foutmelding (lees: ‘Validation Text’) willen melden dat een veld niet ingevuld is, moeten we dat bij via de ‘Validation Rule’ controleren en niet pas door ‘Required’ op ‘Aan’ te zetten. Dat kan bij ‘Validation Rule’ gebeuren via ‘ <>”” ’ of via ‘Is Not Null’. Uit de MS Access-Help halen we: Format eigenschap: Met de eigenschap Notatie (Format) kunt u de notatie aanpassen waarmee getallen, datums, tijden en tekst op het scherm en op papier worden weergegeven. Als u bijvoorbeeld een tekstvak met de naam Prijs hebt gemaakt, stelt u de eigenschap Notatie (Format) van het tekstvak in op Valuta en de eigenschap Aantal decimalen (DecimalPlaces) op 2 of Automatisch. Als u vervolgens 4321,678 in het besturingselement invoert, wordt dit getal weergegeven als fl 4.321,68. Opmerking: De eigenschap Notatie (Format) beïnvloedt alleen de weergave van gegevens, niet de wijze waarop de gegevens worden opgeslagen.
Het is zelfs mogelijk om via speciale VBA-code gedurende het ‘runnen’ van het programma deze Format-eigenschap aan te passen. InputMask eigenschap Met de eigenschap Invoermasker (InputMask) kunt u de invoer van gegevens vereenvoudigen en kunt u bepalen welke waarden gebruikers in een besturingselement tekstvak kunnen invoeren. U kunt bijvoorbeeld een invoermasker maken voor een veld Telefoon, waardoor u precies ziet hoe u een
1
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
telefoonnummer moet invoeren: (___)-___ ____. Het is vaak eenvoudiger om deze eigenschap in te stellen met behulp van de wizard Invoermasker. In Visual Basic stelt u deze eigenschap in met behulp van een reeksexpressie. In het volgende voorbeeld wordt een invoermasker opgegeven voor een tekstvak voor telefoonnummers: Forms!Klanten!Telefoon.InputMask = "(###)-### ####"
DefaultValue eigenschap In de eigenschap Standaardwaarde (DefaultValue) geeft u een tekst of een expressie op, die automatisch in een veld wordt ingevoerd bij het maken van een nieuwe record. Als u bijvoorbeeld de eigenschap Standaardwaarde (DefaultValue) van een besturingselement tekstvak instelt op = Now ( ) , geeft het besturingselement de huidige tijd weer.
ValidationRule, ValidationText eigenschappen In Microsoft Access worden waarden automatisch gevalideerd op basis van het gegevenstype van het veld. Zo is bijvoorbeeld het invoeren van tekst in een numeriek veld niet toegestaan. Met de eigenschap Validatieregel (ValidationRule) kunt u bepaalde vereisten opgeven waaraan ingevoerde gegevens in een, record, veld of besturingselement moeten voldoen. Met de eigenschap Validatietekst (ValidationText) kunt u een bericht opgeven dat op het beeldscherm verschijnt wanneer gegevens worden ingevoerd die niet aan de instelling voor Validatieregel (ValidationRule) voldoen. Opmerking De eigenschappen Validatieregel (ValidationRule) en Validatietekst (ValidationText) gelden niet voor de besturingselementen selectievakje, keuzerondje of wisselknop als deze in een groepsvak zijn opgenomen. De eigenschappen gelden wel voor het groepsvak zelf. Als u wel de eigenschap Validatieregel (ValidationRule) instelt maar niet de eigenschap Validatietekst (ValidationText), wordt een standaard foutbericht weergegeven als de validatieregel wordt overtreden. Als u de eigenschap Validatietekst (ValidationText) instelt, wordt een door u ingevoerde tekst weergegeven als foutbericht. Wanneer bijvoorbeeld een record voor een nieuwe medewerker wordt gemaakt, kunt u een validatieregel instellen die vereist dat de datum van indiensttreding van de medewerker ligt tussen de oprichtingsdatum van het bedrijf en de huidige datum. Als de ingevoerde datum buiten dit bereik valt, kunt u de validatietekst 'Datum in dienst onjuist' weergeven. Voor besturingselementen kunt u de eigenschap Validatieregel (ValidationRule) op elke geldige expressie instellen. Voor validatieregels voor velden en records mag de expressie geen door de gebruiker gedefinieerde functies, statistische of domeinfuncties, de functies HuidigeGebr (CurrentUser) en Evalueren (Eval) of verwijzingen naar formulieren, query's of tabellen bevatten. Bovendien mogen veldvalidatieregels geen verwijzingen naar andere velden bevatten. De expressies voor records mogen verwijzingen bevatten naar velden in de tabel. U kunt de eigenschappen Validatieregel (ValidationRule) en Validatietekst (ValidationText) instellen in: • De sectie Veldeigenschappen in de tabelontwerpweergave (voor een veldvalidatieregel). • Het eigenschappenvenster van een tabel door in de tabelontwerpweergave Eigenschappen te kiezen in het menu Beeld menu (voor een recordvalidatieregel). • Het eigenschappenvenster van een besturingselement op een formulier. • Een macro of Visual Basic. In Visual Basic stelt u deze eigenschappen in met een reeksexpressie. Voor tabelvelden en records kunt u deze eigenschappen ook instellen in Visual Basic met de eigenschap voor gegevenstoegang ValidationRule. Control, field, and record validation rules are applied as follows: • Validation rules you set for fields and controls are applied when you edit the data and the focus leaves the field or control. • Validation rules for records are applied when you move to another record. • If you create validation rules for both a field and a control bound to the field, both validation rules are applied when you edit data and the focus leaves the control. The following table contains expression examples for the ValidationRule and ValidationText properties: ValidationRule property ValidationText property <> 0 Entry must be a nonzero value. > 1000 Or Is Null Entry must be blank or greater than 1000. Like "A????" Entry must be 5 characters and begin with the letter "A". >= #1/1/96# And <#1/1/97# Entry must be a date in 1996. If you create a validation rule for a field, Microsoft Access doesn't normally allow a Null value to be stored in the field. If you want to allow a Null value, add "Is Null" to the validation rule, as in "<> 8 Or Is Null" and make sure the Required property is set to No.
Required property (en de ‘Allow Zero Length’ property) Met de eigenschap Vereist (Required) kunt u opgeven of in een veld een waarde moet worden ingevoerd. Als deze eigenschap is ingesteld op Ja, moet u bij het invoeren van gegevens in een record een waarde invoeren in het veld of in een besturingselement dat afhankelijk is van het veld. Dit mag geen Null-
2
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
waarde zijn. U kunt bijvoorbeeld het invoeren van een waarde in het besturingselement Achternaam in elke record vereist stellen. Wanneer u Null-waarden in een veld wilt kunnen opnemen, moet u de eigenschap Vereist (Required) instellen op Nee en moet een eventuele Validatieregel (ValidationRule) expliciet de instructie 'validatieregel Or Is Null' bevatten.
Voor het verschil met de ‘Allow Zero Length’ eigenschap verwijzen we graag naar de Help. Let op: als je het per se invullen van een waarde met een zelfgemaakte foutboodschap wilt afvangen, dan moet je ‘Required’ op ‘No’ zetten en bij de Validation Rule iets maken als b.v. <>”” of : ‘Is Not Null’. Als je ‘Required’ op ‘Yes’ hebt staan, zul je [voorlopig] altijd een voor gewone gebruikers onleesbare foutmelding krijgen. Indexed Property Met de eigenschap Geïndexeerd (Indexed) kunt u een index van een enkel veld instellen. Een index versnelt de uitvoering van query's en sorteer- en groepeerbewerkingen op de geïndexeerde velden. Als u bijvoorbeeld in het veld Achternaam namen van bepaalde werknemers zoekt, kunt u voor dit veld een index maken. Als de primaire sleutel voor een tabel een enkel veld is, wordt de eigenschap Geïndexeerd (Indexed) voor dat veld automatisch ingesteld op Ja (Geen duplicaten). Gebruik het venster Indexen voor het maken van meervoudige indexen. N.B. Hiervoor staat weliswaar uitdrukkelijk dat het aanbrengen van indexen het zoeken en groeperen van waarden in dat veld zal versnellen, niet vermeld is hier echter dat door het aanbrengen van indexen in het algemeen het wijzigen van gegevens (toevoegen, veranderen, verwijderen) vaak trager zal worden. In de praktijk zul je een compromis moeten bereiken tussen aan de ene kant het versnellen van zoeken/groeperen en van de andere kant het niet teveel vertragen van het systeem bij het doorvoeren van wijzigingen.
N.B. Indien we wijzigingen wilt aanbrengen in de structuur van een (bestaande en) reeds gevulde gegevenstabel, dan zal MS Access je bij het aangeven van bepaalde gewenste wijzigingen erop attent maken, dat het doorvoeren ervan vanwege conflicten met bestaande gegevenswaarden misschien wel gegevensverlies kan met zich mee kan brengen. Vraag je dan uiteraard af of je je door die waarschuwing al dan niet moet laten afbrengen van je plannen om de tabelstructuur aan te passen. In het voorafgaande deel ging het over eigenschappen van afzonderlijke velden. Soms komt het voor, dat we eigenschappen van gehele records willen instellen; dit kan [indien we de tabel in de Designmodus geopend hebben] via View/Properties van die tabel.
1.1
Practicumopdracht 3.a
(verbetering tabelstructuur)
Pas de structuur van je ‘Leden’-tabel als volgt aan: • Laat als ‘Caption’ bij het Naam-veld steeds de tekst ‘Achternaam’ verschijnen en bij ‘Plaats’ steeds ‘Plaatsnaam’. • Er moeten waarden worden ingevuld bij Achternaam, voornaam en plaatsnaam en als dat niet dreigt te gebeuren, dient een zelf gedefinieerde foutmelding te verschijnen, waarmee de gebruiker erop attent wordt gemaakt dat een bepaalde [met naam genoemde] waarde moet worden ingevuld. • Zorg ervoor dat een gebruiker alleen correcte postcode-waarden (dus: 4 cijfers + 2 hoofdletters) of ‘niks’ in dat veld kan invoeren en laat zonodig een duidelijke instructie verschijnen als dat niet gebeurt. Zoek via de Help na hoe je de ‘Input Mask’-Wizard daarvoor moet gebruiken. • Omdat we vaker op plaatsnaam zullen zoeken is een index op dit veld gewenst. Breng die al aan.
2.
Het stap-voor-stap opbouwen van een Form
We gaan hier stap voor stap een Form opbouwen dat er uiteindelijk zoals hiernaast getoond uit zal gaan zien. We willen in een (tekst)invoerveld een voornaam kunnen intikken, vervolgens in een ander tekstveld een achternaam en vervolgens via een klik op de push button ‘Koppel naamdelen’ de ingetikte waarden, gescheiden door een spatie, in een uitvoerveld tonen. Een ‘Afsluiten’-knop moet het mogelijk maken het formulier te sluiten. Let erop dat dit Form [links onder] géén record-navigation-onderdelen heeft.
3
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
Omdat dit Form nìet gebaseerd is op een gegevenstabel, kiezen we na de klik voor een ‘New Form’ voor de zuivere Design View. Hiernaast is zowel het verschijnende lege Form als de bijbehorende Toolbox getoond. Voor het door ons gewenste Form hebben we 3 tekstvelden nodig. Een tekstveld-object is op het Form te plaatsen door eerst bijna rechtsboven in de toolbox op het ‘ab|’-icoontje te klikken en daarna op de voor het tekstveld gewenste plek in het Form. (Het icoontje ‘Aa’ linksboven staat voor een ‘tekstlabel’.) Als we voor het op het Form geplaatste tekstveld nu het scherm voor het tonen/instellen van de ‘Eigenschappen’ (Properties) opvragen, dan zien we met de ‘Other’-tab geactiveerd het volgende. Default is aan dit eerste tekstveld-object de ‘variabele’-naam Text0 gegeven; uiteraard veranderen we dat in een zinvollere aanduiding als bijvoorbeeld ‘Voornaam’. Op eenzelfde manier plaatsen we een tekstveld ‘Achternaam’ en een ‘VolledigeNaam’ op de gewenste plaats op het Form. Door in het bijbehorende (er vóór staande) label te dubbelklikken, kunnen we daarvan ook de ‘label-aanduidingstekst’ vervangen. Door [met het gewenste object geselecteerd] op de Format-tab van het Properties-scherm te klikken, kunnen we daar zaken als gewenst lettertype etc. aangeven. Het plaatsen van de ‘Koppel naamdelen’-button gaat op een geheel analoge wijze, door eerst in de toolbox op het push button-icoontje te klikken (op halve hoogte, links). We kunnen géén gebruik maken van de ‘Command Button Wizard’, omdat we niet te maken hebben met een button voor een van de gewenste ‘actie-categoriën’; breek die wizard daarom af met een klik op de Cancel-knop. Vervang vervolgens in het properties-scherm (‘Other’-tab) de variabele-naam van de button door een zinvolle, zoals ‘KoppelButton’. Ook het opschrift van een button (de ‘caption’) is te wijzigen via de Format-tab. Voor de ‘Afsluiten’-push button om het Form te sluiten kunnen we uiteraard wél gebruik maken van die wizard. Plaats als label (groot lettertype e.d.) bovenin het Form een aanwijzing voor de gebruikers waar dat form voor dient. Door even ‘buiten’ het oppervlak van het Form (maar wel binnen de grenzen van het Form-designerwindow) te klikken, kun je ook de eigenschappen van het Form-als-totaal veranderen. Zet via het Format-tabblad de record-navigation-onderdelen op ‘uit’. N.B. Vergeet niet om regelmatig je werk op te slaan (door op het diskette-icoontje te klikken; de eerste keer zul je een [desnoods later te wijzigen] naam voor het Form moeten opgeven. We gaan nu het van ons Form gewenste gedrag implementeren. Allereerst: het gedrag van de ‘KoppelButton’. Indien we op de ‘Event’-tab van het properties-window klikken, dan krijgen we het hiernaast getoonde overzicht te zien, waarbij we zo vrij zijn geweest al één ‘gebeurtenis’-procedure in te vullen, en wel bij de optie ‘On Click’. In het overzicht zien we een opsomming van wat blijkbaar de verschillende gebeurtenissen zijn, waarop het systeem zou kunnen reageren. We hebben voor ons mini-probleempje ervoor gekozen iets te laten gebeuren (het koppelen van voor- en achternaam) als er op die Koppelbutton geklikt wordt. Indien we de cursor plaatsen in het tekstveld achter zo’n opschrift als ‘On Click’, dan zien we dat dat tekstveld veranderd in een combo-box (waarmee we eventueel reeds bestaande procedures zouden kunnen koppelen aan zo’n muisklik. Belangrijker is hier echter, dat helemaal rechts ook een icoontje met drie puntjes (...) is verschenen.
4
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
Als we daar op klikken [als er nog geen ‘gebeurtenis-procedure’ gekozen is] dan wordt ons gevraagd of we de Expression Builder, de Macro Builder of de (VBA) Code Builder willen gebruiken. We kiezen voor die laatste optie (voor het maken van VBA-code) en komen daarna terecht in de klassenmodule-editor, waar de kop- en de eindregel van de ‘Private Sub’-procedure al voor ons gereed staan. Het ‘Private’ vanwege het klassenmodule-karakter; deze gebeurtenisprocedure heeft alleen iets met dit Form te maken. MS Access (beter: het VBA-systeemdeel) heeft voor ons reeds een zinvolle naam gekozen (althans: indien wij daarvoor een zinvolle variabelenaam aan de button hadden gegeven): KoppelButton_Click(). Kortom: uit die naam is af te lezen, dat het om het gewenste gedrag bij het klikken op de sluitbutton gaat. We hoeven vervolgens binnen dit skelet alleen de code-regels toe te voegen over wat er precies moet gebeuren; een toekenning aan het ‘VolledigeNaam’-tekstveld. Onze procedure wordt: Private Sub KoppelButton_Click ( ) If Trim ( Voornaam ) = "" Then ‘ er is geen voornaam ingevuld VolledigeNaam = Achternaam Else VolledigeNaam = Voornaam + " " + Achternaam End If End Sub
Een kind lijkt de was te kunnen doen. N.B. In diezelfde klassenmodule treffen we ook de door MS Access gegenereerde VBA-code voor een klik op de Sluitbutton aan: Private Sub SluitButton_Click ( ) On Error GoTo Err_SluitButton_Click DoCmd.Close Exit_SluitButton_Click: Exit Sub Err_SluitButton_Click: MsgBox Err.Description Resume Exit_SluitButton_Click End Sub Uit weerzin tegen deze afgrijselijk ongestructureerde wijze van codering (met een ‘GoTo label’-constructie, een ‘Exit’ en een ‘Resume’ hakken we het grootste deel van deze code weg en [omdat er verder niets hoeft te gebeuren, zoals het nog even snel opslaan van veranderde gegevens of zo] beperken we deze code tot: Private Sub SluitButton_Click ( ) DoCmd.Close End Sub
2.1
Practicumopdracht 3.b
(form met tekstvelden en push buttons)
Als je in MS Access twee datum-waarden van elkaar aftrekt, krijg je het verschil in aantal dagen. Maak nu zelf een Form, waarbij je twee datumwaarden kunt invoeren en waarbij een druk op een knop het verschil in aantal dagen tussen de begin- en de einddatum uitrekent en toont. Het Form kan er uit zien zoals hiernaast getoond. De twee datumvelden zijn tekstinvoervelden, waarvan het ‘Format’ op Short Date is gesteld.
3.
Filters en hun gebruik
Naast de mogelijkheid van het via SQL-(SELECT-)queries laten opzoeken en tonen van gegevens is in MS Access ook heel sterk de mogelijkheid ontwikkeld van het kunnen toepassen van zogenaamde ‘filters’. We kunnen daarmee (net als met SQL-queries) criteria aangeven, waaraan gezochte waarden moeten voldoen. Uit de MS Access Help halen we (cursivering e.d. is van mijn hand /GP):
5
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
Overeenkomsten en verschillen tussen selectiequery's en filters De basisovereenkomst tussen selectiequery's en filters is dat u met beide een subset van records kunt zoeken en ophalen in een onderliggende tabel of query. De manier waarop u de opgehaalde records wilt gebruiken, bepaalt of u een filter of een query moet gebruiken. In het algemeen gebruikt u een filter als u tijdelijk een subset van records wilt bekijken of bewerken terwijl u in een formulier of gegevensblad werkt. Gebruik een query als u een of meer van de volgende handelingen of bewerkingen wilt verrichten: • De subset van records bekijken zonder eerst een bepaalde tabel of een bepaald formulier te openen. • De tabellen kiezen die de records bevatten waarmee u wilt werken, en later eventueel meer tabellen toevoegen. • Bepalen in welke velden van de subset van records de resultaten worden weergegeven. • Berekeningen verrichten op waarden in velden. Opmerking: Ook als u besluit dat u een query nodig hebt, kunt u gebruik maken van de eenvoudige technieken Formulierfilter, Selectiefilter of Invoerfilter om een filter te maken. Vervolgens kunt u het filter als een query opslaan. Op deze manier hebt u het ontwerpraster van de query helemaal niet nodig, tenzij u aanvullende wijzigingen in de query wilt aanbrengen. En ook in dat geval ziet u, als u de query in de ontwerpweergave opent, hoe het ontwerpraster wordt ingevuld met de gegevens uit het filter. U kunt deze gegevens vervolgens gebruiken als een richtlijn voor aanvullende wijzigingen. In het volgende overzicht worden de overeenkomsten en verschillen tussen query's en filters uiteengezet. Kenmerken Filters Query's Bieden de mogelijkheid meer tabellen toe te voegen als u de records uit die tabellen wilt opnemen in de subset die als resultaat wordt gegeven Bieden de mogelijkheid op te geven welke velden uit de subset van records u wilt weergeven in de resultaten Verschijnen als een afzonderlijk object in het databasevenster Kunnen alleen worden gebruikt in een gesloten tabel, query of formulier Geven resultaten die kunnen worden gebruikt als de gegevensbron voor een formulier of rapport Kunnen de som, het gemiddelde, het aantal en andere soorten totalen berekenen Kunnen records sorteren Bieden de mogelijkheid gegevens te bewerken als het bewerken van gegevens is toegestaan
Nee
Ja
Nee
Ja
Nee Nee Ja
Ja Ja Ja
Nee
Ja
Ja Ja
Ja Ja, afhankelijk van het soort query. U kunt ook gegevens op grotere schaal bijwerken met een bijwerkquery.
Voor wat betreft het verschil tussen de verschillende filters halen we weer uit de Help:
Vergelijking van filtermethoden Doel van het filter
Selectiefilter
Formulierfilter en Invoerfilter
Records zoeken die voldoen aan meerdere criteria.
Ja (maar u moet de criteria stuk voor stuk opgeven)
Ja (en u kunt alle criteria tegelijk opgeven)
Records zoeken die voldoen aan het ene criterium of aan het andere. Het mogelijk maken om expressies in te voeren als criteria. Records sorteren in oplopende of aflopende volgorde.
Nee
Ja
Geavanceerde filter/sorteeropties Ja (en u kunt alle criteria tegelijk opgeven) Ja
Nee
Ja
Ja
Nee (maar nadat u het filter hebt toegepast, kunt u alle gefilterde records sorteren door te klikken op Oplopend sorteren of Aflopend sorteren op de werkbalk)
Nee (maar nadat u het filter hebt toegepast, kunt u alle gefilterde records sorteren door te klikken op Oplopend sorteren of Aflopend sorteren op de werkbalk)
Ja (u kunt sommige velden in oplopende volgorde en andere velden in aflopende volgorde sorteren)
6
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
De bij ‘Oplopend sorteren of Aflopend sorteren op de werkbalk’ behorende icoontjes zijn: Als je o.a. in een Form aan het werken bent, dan zie je dat bovenin de hiernaast getoonde icoontjes tevoorschijn zijn gekomen. Als je de cursor bij zo’n icoontje houdt, verschijnt als ‘hint’ (van links naar rechts) respectievelijk: ‘Selectiefilter’, ‘Formulierfilter’ en ‘Filter toepassen’. Het meest rechtse icoontje (‘Filter toepassen’), gedraagt zich als een ‘aan/uit’-knop waarmee je het gedefinieerde filter wel of niet van toepassing verklaard.
Voorbeeld met ‘Selectiefilter’ We keren terug naar ons Ledenform van de vorige practicumopdracht. Als we met de cursor in het ‘plaatsveld’ gaan staan, in een record waarbij de plaats ‘Nijmegen’ is en dan op het (linkse) icoontje voor ‘Selectiefilter’ klikken, dan verschijnt het scherm zoals hiernaast getoond (met de plaatsnaam ‘geselecteerd’ en helemaal onderaan kun je lezen, dat er nu 6 records uitgefilterd zijn; blijkbaar wonen 6 leden in deze plaats) en kun je zien dat het icoontje voor ‘Filter toepassen’ nu ingedrukt likt. Als je nu op dat icoontje ‘Filter toepassen’ klikt, wordt blijkbaar het filter weer uitgeschakelt, want helemaal onderaan zie je dan, dat er weer 9 records in beschouwing worden genomen. Indien je nu bijvoorbeeld in het niveau-veld gaat staan (met de getoonde waarde 2) en nog een keer op ‘Selectiefilter’ klikt, dan kun je onderaan zien, dat nog slechts 1 record aan de filtervoorwaarden voldoet (blijkbaar is er maar één lid uit Nijmegen met niveau 2). Na klikken op ‘Filter toepassen’ zijn weer alle (9) bestaande records bereikbaar. Als je (al dan niet met filter ‘aan’) in een veld (bijvoorbeeld ‘niveau’) gaat staan en dan op het eerdergenoemde icoontje voor ‘Oplopend sorteren’ klikt, dan zullen de records geordend getoond worden (hier dus naar toenemende niveau-waarde). De enige manier om een eenmaal opgegeven filterconditie uit een trits opgegeven condities te verwijderen is blijkbaar het ‘sluiten’ van het Form en weer opnieuw openen en dan de nog wel gewenste condities weer opnieuw aangeven.
Voorbeeld met ‘Formulierfilter’ We gaan weer naar ons Ledenform van de vorige practicumopdracht. Als we met de cursor in het ‘plaatsveld’ gaan staan, in een record waarbij de plaats ‘Nijmegen’ is en dan op het (middelste) icoontje voor ‘Formulierfilter’ klikken, dan verschijnt het scherm zoals hiernaast getoond (het verdwijnt desgewenst na drukken op de Windows-9?-sluit-‘X’ rechtsboven in het window; je komt dan weer terug in het ‘Ledenform’). Je ziet dat voor het eerder geselecteerde ‘Plaats’-veld nu een combo-box is verschenen, waarmee je een keuze kunt maken uit de verschillende plaatsnamen die in de ledentabel aanwezig zijn. Als je linksonder (waar nu de tabtekst ‘Zoeken naar’ oplicht) op de tab ‘Of’ klikt, kun je een andere mogelijk gewenste waarde opgeven (voor een filtervorm van bijvoorbeeld “Nijmegen” OF “Arnhem”). Je kunt ook voor meer velden een (gelijktijdige) filterconditie opgeven, door in een ander veld te gaan staan en via de verschijnende combo-box een filterwaarde te kiezen. Een gekozen waarde kun je verwijderen door in het betreffende veld te gaan staan en de eerder aangegeven waarde (bijvoorbeeld met de ‘Delete’-toets) te verwijderen. Je activeert het gekozen formulierfilter door in de MS Access-werkbalk op het (van plaats verschoven) icoon ‘Filter toepassen’ te klikken en krijgt daarna uiteraard de gewenste selectie (hier: van alle leden uit Nijmegen) en kunt daar ‘doorheen bladeren’.
Geavanceerde ‘filter/sorteer-opties’ Als je via de MS Access menubalk kiest voor ‘Records/Filter/Geavanceerde filter-/sorteeropties’ of als je eerst kiest voor ‘Formulierfilter’ kiest en daarna (in de nu gewijzigde menubalk) voor ‘Filter/Geavanceerde filter-/sorteeropties’ dan komt een dialoogscherm tevoorschijn dat erg lijkt op
7
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
dat van de Query-Wizard uit de vorige opdracht. Als je daarna op het icoon ‘Filter toepassen’ klikt, kun je in het ledenform rondwaren door de uitgefilterde records.
Wat meer over filters: geprogrammeerd in Visual Basic for Applications We bespreken hier de wijze waarop je op een heel gebruiksonvriendelijke manier een filter zou kunnen maken voor al dan niet toepassen in een Form. We hebben bovenin dit form (alles ‘binnen een omlijnende rechthoek’) een ‘tekstvak’ geplaatst met de (variabele)naam ‘FilterWHERE’, een push button met de (variabele)naam ‘FilterToepassen’ en een ‘selectievakje’ met de (variabele)naam ‘RecordsGefilterd’. Al deze afzonderlijke schermobjecten (dus: rechthoek, tekstvak, push button en selectievakje) zijn er via de Toolbox op geplaatst en kwa eigenschappen aan onze wensen aangepast. Indien we in het tekstvak een geldige filterconditie intikken en op de push button klikken, dan wordt het filter toegepast en het selectievakje aangevinkt. Nogmaals klikken op de push button schakelt het filter uit en maakt het selectievakje ook ‘blanco’. Indien we dit dialoogscherm in de Design-modus bekijken en de eigenschappen van de push button ‘FilterToepassen’ opvragen (zie desnoods opdracht 2 over hoe je dat ook alweer deed . .), dan zien we de hierbij getoonde (kale) invulling bij het tab-blad ‘gebeurtenissen’. Je ziet dat er blijkbaar (alleen) een ‘gebeurtenisprocedure’ aangeroepen wordt op het moment dat je op de betreffende push button klikt (zie het bijschrift ‘Bij klikken’). Als we in de rechterkantlijn op de knop met de drie puntjes (. . .) klikken, dan komen we in de klassenmodule van het betreffende formulier en vinden daar de (door ons zelf ingetikte code): Private Sub FilterToepassen_Click ( ) Me.Filter = Me.FilterWHERE
‘ gebruik als filterconditie wat in ‘FilterWhere’ is ingetikt
If Me.FilterOn Then Me.FilterOn = False Me.RecordsGefilterd = False Else Me.FilterOn = True Me.RecordsGefilterd = True End If
‘ zet het selectievakje ‘uit’
‘ zet het selectievakje ‘aan’
' Door Access was hier eerst via de Command Wizard voor aangemaakt: ' DoCmd.DoMenuItem acFormBar, acRecordsMenu, 2, , acMenuVer70 End Sub
Hoe moeten we die VBA-code lezen? • Het ‘Me’ verwijst steeds naar het object waar deze klassenmodule bij behoort; in dit geval is dat het Ledenform van het type ‘Form’. Als je in die module-editor ‘Me.’ intikt dan verschijnt weer het reeds ietwat bekende type-hulpwindowtje met een overzicht van alle mogelijke aanvullingen voor ‘wat kan met ‘Me’ allemaal? We zien in dat hulp-overzichtje o.a. de mogelijkheden ‘Filter’ en ‘FilterOn’ [met mogelijke waarden: True en False]. • Toen deze gebeurtenisprocedure aangemaakt werd en het VBA-systeem doorkreeg, dat het te maken had met wat er moest gebeuren na een klik op de ‘FilterToepassen’-button, heeft het zelf de naam ‘FilterToepassen_Click ( )’ aan deze gebeurtenisprocedure gegeven. Er staat ‘Private’ voor omdat deze ‘Sub’ alleen bij dit Form behoort en niet van daar buiten aangeroepen wordt.
8
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
• Ga zelf na dat via de If/End If-constructie zowel het filter aan/uit-geschakeld wordt alsook de waarde van het selectievakje steeds gewisseld wordt. • Als je voor het maken van zo’n eigen filter bij het op het formulier zetten van een push button voor het toepassen van een filter, kiest voor de push button command wizard en daarin bij ‘Formoperations’ kiest voor ‘Apply Form Filter’, dan genereert MS Access de volgende zogenaamde ‘macro’-code voor je: DoCmd.DoMenuItem acFormBar, acRecordsMenu, 2, , acMenuVer70 en zet die in een gebeurtenis-procedure voor je (zie de ‘uit’ becommentarieerde code in voorgaande ‘FilterToepassen_Click ( )’-procedure. Daarin wordt verwezen naar opties in de MS Access-menubalk.
3.1
Tussendoor: over validatieregels bij een Form-object
Nu we toch met die klassenmodule van dit Form bezig zijn: we hebben een extra bescherming ingebouwd op wat als waarde in het ‘LidSinds’-veld kan worden ingevoerd. In bijgaande figuur zie je dat via de Properties en daarin via de Gegevens-tab een mogelijkheid bestaat om een validatieregel (+ bijbehorende validatietekst) in te voeren. Daarvoor hebben we in de klassenmodule van dit Ledenform de volgende functie opgenomen: Private Function CheckDate ( Datum As Date ) As Boolean If Datum >= Date Then CheckDate = False ElseIf Year( Datum ) <= 1990 Then CheckDate = False Else CheckDate = True End If End Function
Je ziet dat in de Gegevens-tab de ietwat primitief aandoende formulering ‘CheckDate ( LidSinds ) = Waar’ wordt gebruikt (engelse versie: . . =True). Helaas vereist VBA dit soort pleonasmen! Let erop, dat we de kop van de (Sub-) procedure veranderd hebben, zodat een Function is ontstaan, waarna we dat hiervoor genoemde pleonasme van ‘Waar=Waar’ kunnen toepassen.
3.2
Practicumopdracht 3.c
(aanbrengen Validatieregel in Form)
Pas je resultaat van practicumopdracht 3.b zodanig aan, dat gecontroleerd wordt of de ingevoerde einddatumwaarde wel ná de begindatumwaarde ligt en dat als dit niet zo is er een zelfgemaakte foutmelding komt waarin de gebruik(st)er attent wordt gemaakt op die foutieve waarde.
4.
Meer over het werken met forms en (nieuw:) het erin plaatsen van subforms
We zagen al eerder hoe het maken van een ‘formulier’ (Form) in zijn werk gaat. In het ‘database-window’ kies je daarvoor eerst het tabblad ‘Forms’ (of uiteraard: Formulieren) en drukt op de push button ‘New’. Er komt dan allereerst een dialoogvenster waarin je aangeeft op welke manier je zo’n nieuw formulier wilt aanmaken. Als je kiest voor de meest algemene aanpak: ‘Design view’ dan verschijnt in een venster een leeg formulier, vergezeld van een toolbox-venstertje (zie bijgaande figuur). Met behulp van de
9
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
toolbox-icoontjes kunnen we diverse soorten schermobjecten in het formulier plaatsen. N.B. We maken in deze paragraaf gebruik van een gegevenstabel die gevuld is met gegevens van allerlei muziek-titels. We geven hier de inhoud (+ impliciet de structuur) van die tabel:
Werken met Sub-forms binnen een form Met het tweede icoontje vanaf links beneden in de toolbox kun je een subform aan je ‘hoofd’-form toevoegen. Als je zo’n subform probeert aan te brengen, verschijnt een serie dialoogvensters, met daarin allereerst de vraag of je het subform op een ‘Tabel/Query’ of op een al bestaand formulier wilt baseren. Vervolgens komt de vraag welke (bestaande) tabel of query je wilt gebruiken en welke velden (kolommen) je daarvan wilt laten tonen. Tot slot mag je het ontworpen subform een naam geven, waaronder het zal worden opgeslagen (onder die naam verschijnt het later ook in het forms-overzicht). Als je daarna in het databasevenster de naam van dat subform aanklikt en op de ‘Design’-button klikt, dan is het daarna mogelijk om –door in een ‘leeg’ deel van het ontwerpscherm op de rechter muisknop te klikken- via een opkomend keuzemenuutje de optie ‘Properties’ (of: ‘Eigenschappen’) te activeren. De inhoud van het verschijnende propertiesdialoogvenster is afhankelijk van welk object geselecteerd was toen je op die rechter muisknop klikte. We geven hier de inhoud van wanneer inderdaad het form zèlf geselecteerd was (door dus op een ‘leeg stuk’ te klikken). Je ziet dat –via het Format-tabblad- de ‘Default View’ en het al dan niet verschijnen van scroll bars en record selectors naar keuze ingesteld kan worden. Na aanklikken van het tabblad ‘Data’ is bijvoorbeeld bij ‘Allow Additions’ aan te geven, of je via dat (sub)form wel/niet gegevens aan een tabel wilt kunnen toevoegen (bij ‘wel’ verschijnt dan steeds een laatste ‘leeg record’ in je overzicht). Je ziet boven in dat Data-tabblad van bijgaande figuur, dat blijkbaar een gegevenstabel ‘Opnames’ (of ook mogelijk: een query die onder die naam is opgeslagen) als ‘Record Source’ wordt gebruikt. Wat te doen om ons totale scherm de gewenste functionaliteit te geven? Zoals gezegd moet er dus naast een ‘hoofdform’ (die het gehele window oplevert) ook apart een subform gedefinieerd worden, waarin de gevraagde gegevens kunnen worden getoond. Daarnaast moet er een mogelijkheid zijn om aan te geven van welk muziekgenre we een overzicht willen. Het probleem zit hem nu verder in ‘hoe’ de koppeling moet worden gemaakt tussen de manier (lees: het soort schermobject) waarop we willen aangeven welk genre we willen en dat gewenste overzichtssubform.
10
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
1) Via een invoerregel (text box) We beginnen met het functioneel krijgen van een scherm (zie bijgaande figuur) met een genrekeuze via het intikken van een genre-naam (zoals ‘jazz’, ‘rock’ e.d.) in een tekstregel-box. Na het geven van een <Enter> verschijnt in het subform een overzicht met titels van het ingetikte genre. Hoe hebben we nu de koppeling tussen die tekstregel en het subform gelegd? We bekijken daarvoor in de Design-mode het Propertiesdialoogvenster, waarbij het Data-tabblad geopend is en het subform geselecteerd is (zie figuur). Voor ons interessant zijn daarbij de waarden die ingevuld zijn bij de twee ‘link’-velden. Daarbij moet je weten, dat in het gebruikte voorbeeld ‘Text6’ de naam is van de ‘text box’ (MS Access heeft zèlf deze naam voor dit text box-object gegenereerd, maar je hebt de gelegenheid die naam te veranderen via het Properties/Other-tabblad) en dat in het subform (dat hier ‘toevallig’ de naam ‘Child2’ heeft gekregen; zie titelbalk van het venstertje) het veld waarin de genreinformatie staat, de naam ‘Music Category ID’ heeft (gelijk aan de betreffende kolom in de Opnamesgegevenstabel).
2) Via een ‘list box’ of een ‘combo box-popup’ In het getoonde scherm is eerst een overzicht gevraagd van aanwezige ‘Classical’ titels en is nu het combo box-venster opnieuw opengeklapt voor het opgeven van de nieuwe keuze ‘Rock’. Na aanklikken van zo’n nieuwe keuze zal in het resultaten deel eronder een overzicht van de aanwezige ‘Rock’-titels moeten verschijnen. We bespreken hier eerst: - hoe krijgen we zo’n combo box gevuld? en vervolgens: - hoe leggen we de koppeling met het subform? In de getoonde figuur van het Properties/Data-scherm van deze combo box (gezien de getoonde tekst in de titelbalk heeft die blijkbaar de naam ‘Combo0’ gekregen) is te zien, dat de ‘Row Source’ van het type SQL-query is (en wel: SELECT DISTINCT [Music Category ID] FROM Opnames ). Indien gewenst, kun je in dit scherm ook een default-waarde (b.v. Jazz) opgeven. In de volgende figuur is getoond, dat nu in het Properties/Data-tabblad van het subform (‘Child2’) bij Link Master Fields de objectnaam ‘Combo0’ van de combo box is ingevuld.
N.B. Het verschil in ‘afhandeling’ van de gewenste waarde tussen een combo box, een listbox en een simpele invoerregel (text box) is voor MS Access zelfs zo klein, dat in de Design-mode in het via een klik met de rechtermuisknop opgeroepen popup-menu ook de optie ‘Change To’ bestaat,
11
B3: Systematisch ontwikkelen van eenvoudige informatiesystemen
Practicumopdracht 3
waarbij je desgewenst een vervanging van een combo box door een van de twee andere schermobject-types kunt doorvoeren (en v.v.).
4.1
Practicumopdracht 3.d
Maak een Form onder de naam ‘Overzicht per plaats’ waarbij je via aansturing/keuze met een combobox een overzicht [in een subform] kunt laten zien van alle leden die uit de geselecteerde plaats afkomstig zijn. Zorg ervoor via het correct instellen van allerlei ‘Eigenschappen’ van zowel het Form [en zonodig het subform] als geheel, als van de afzonderlijke form-objecten, dat je form zo goed mogelijk lijkt op het hieronder getoonde:
Lever je in de database opgeslagen uitwerkingen uiterlijk ten tijde van het volgende B3-werkcollege in per email naar jeroen.claassens@p12.nl ‘Compacteer’ (als je ‘Database-venster’ geselecteerd is, via Tools/Database Utilities/Compact Database) je database voordat je hem inlevert !!!
12