Tagarchief: Select

Nijntje Schuif 2.0

Deze keer een vreemde Excel-toepassing; het bekende schuifspelletje: NijnSchuifschuif vakjes op en neer net zolang totdat het oorspronkelijke plaatje tevoorschijn komt.

Net zo vreemd als de toepassing is ook de aanleiding: op een feestje, een paar weken geleden, kwam ik na lange tijd een vriend van een zoon van mij tegen en zoals het dan gaat begonnen we herinneringen op te halen.
We kregen het ook over onze gezamenlijke programmeer-activiteiten: meer dan 15 jaar terug hadden we als LKG-software (Ludo, Koen, Gijs) een website waar spelletjes konden worden gedownload. Deze hadden allemaal als thema het bekende Nijntje.
Eén van de spelletjes was het verschuiven van vierkantjes op het scherm, zodanig dat er een mooi plaatje ontstond (uiteraard met het Nijntje-figuur; vanuit royalty-problemen mogen we die helaas niet meer gebruiken, maar de naam Nijntje Schuif laten we nog voortleven!).

Het leek me wel een uitdaging om dit in Excel na te bouwen.
Nou, een uitdaging was het! Qua principe had ik een prototype snel aan de praat, maar om dit leuk met plaatjes te doen, dat viel nog niet mee.

Deze keer eerst een opzet waarbij het principe en de programmeersystematiek van het schuifspel duidelijk wordt; een volgende keer een mooiere uitvoering.

Nijntje Schuif 2.0

Nijntje SchuifDe basis voor deze eerste versie van de moderne uitvoering van Nijntje Schuif vormen de 16 cellen C4:F7.
Dit blokje cellen heeft de naam cNijn gekregen, zodat we daar binnen VBA makkelijk naar kunnen verwijzen.

Verder heb ik ook de cellen I7 en I8 een naam gegeven: cReset respectievelijk cNwRonde. Deze cellen gebruiken we om de cijfers direct in de juiste volgorde te zetten (een Reset dus) en om een nieuw spelletje te beginnen (de cijfers worden door elkaar gehutseld).
Om een VBA-routine (een macro) te starten wordt meestal een button gebruikt; deze keer gebruik ik daarvoor cellen. Wanneer op de cellen I7 of I8 geklikt wordt (of met de cursor deze cellen wordt geselecteerd) dan start de betreffende routine op.
Ditzelfde idee (reageren op het veranderen van de selectie in een werkblad) gebruiken we ook om cijfers in het vierkant te verplaatsen. Klik op een genummerde cel en het programma zal controleren of deze cel verwisseld kan worden met de lege.

De mogelijkheid om met behulp van VBA te reageren op een selectiewijziging kan uiteraard voor diverse doeleinden gebruikt worden.

 VBA-reactie bij wijziging van selectie

Nijn SchuifBelangrijk is dat een dergelijke routine (Sub Worksheet_SelectionChange) aan het betreffende werkblad wordt toegevoegd (in dit geval het tabblad Nijntje).

In het voorbeeld hierboven zal een Reset worden uitgevoerd, wanneer de cel die geselecteerd wordt (de Target) overeenkomt met de cel cReset.
Misschien wat vreemd geconstrueerd (als de overlap tussen Target en cReset niet leeg is), maar ik zie geen andere oplossing.

Op dezelfde manier wordt gecontroleerd of er een nieuwe speelronde moet worden opgestart (via de cel cNwRonde). In dat geval wordt een andere routine in de module NijnSchuif uitgevoerd, namelijk NieuweRonde.

‘Verplaatsen’ van een vierkantje

Op dezelfde manier testen we of één van de 16 vierkantjes van cNijn wordt geselecteerd:

Nijn SchuifAls dat zo is, dan leggen we de positie vast in intRij en intKolom en controleren dan eerst in de array/matrix Nijntje of de betreffende cel leeg is; zo ja dan moet die cel even rood gekleurd worden en verder niets.

Hopelijk is de uitleg in het voorbeeldbestand genoeg om de overige controles te begrijpen.

Variabelen declareren

In diverse routines worden variabelen gebruikt om tussenwaarden op te slaan, die voor de werking van de routine nodig zijn. Het is een goede gewoonte om deze vooraan in de routine te declareren met behulp van het statement Dim. Deze variabelen zijn dan alleen geldig in de betreffende routine.

Nijn Schuif

Voor de goede werking van ons NijntjeSchuif-programma is het echter ook nodig, dat sommige variabelen door alle routines kunnen worden gebruikt (bijvoorbeeld in welke rij staat de lege cel, intLegeCelRij).
Deze variabelen worden niet door Dim gedeclareerd, maar door Public ergens ‘buiten’ de routines; in dit geval in de module Algemeen.

Opstart-routine

Om ons spel te kunnen gebruiken is het van belang, dat diverse variabelen een waarde hebben. De routine Reset neemt dit allemaal voor zijn rekening.
Nijn SchuifOm zeker te weten, dat het spel meteen gespeeld kan worden (nadat een Nieuwe ronde is gekozen), zorgen we dat de reset-routine direct wordt uitgevoerd wanneer we de werkmap openen.
Dit gebeurt door in de subroutine Workbook_Open de reset-opdracht op te nemen.

LET OP: deze subroutine moet u altijd plaatsen in het speciale Excel-object ThisWorkbook.

De routine Workbook_Open is heel handig. U kunt er bijvoorbeeld voor zorgen, dat een bepaald tabblad altijd actief wordt bij het openen (Sheets(“Nijntje”).Select) of dat de eerste cel wordt geselecteerd (Range(“A1”).Select) of een combinatie.

Veel plezier met het spelen van Nijntje Schuif 2.0!

Zoals gezegd: volgende keer een fraaiere uitvoering; dus versie 2.1 komt er aan.


G-Info en de functie G_Info()

In mijn vorige artikel heb ik het gehad over de functies CEL() en INFO().
LET OP
: in Excel en Access wordt een functie altijd gevolgd door 2 ronde haken. Bij de meeste functies worden tussen die haakjes argumenten meegegeven.

De naam van die tweede functie triggerde me om een eigen functie G-Info() te ontwikkelen. Maar wat zou die functie moeten doen?

Deze week kwam ik op een idee: wij moesten al nadenken wanneer we volgend voorjaar een korte vakantie zouden plannen; ergens met Hemelvaart of Pinksteren. Maar op welke data vallen die volgend jaar?

Ik wist nog wel, dat deze feestdagen afhankelijk zijn van Pasen, maar wanneer is het nu precies eerste Paasdag?

Pasen

Even “googlen” en al snel was ik een stap verder. Wikipedia:

Het concilie van Nicea bepaalde in 325 dat Pasen moet worden gevierd op de zondag na de eerste volle maan in de lente.

We hoeven dus alleen maar te weten wanneer de lente begint, wanneer het dan weer volle maan wordt en wat dan de eerstvolgende zondag is en we zijn klaar!!

PasenNog maar even verder op Google rondgeneusd en toen bleken er al diverse voorbeelden beschikbaar voor het bepalen van de datum van eerste Paasdag.

Dat is dus minder makkelijk dan ik gedacht had!
Met dank aan de bedenkers van deze routine gaan we dit gebruiken als bouwsteen voor onze nieuwe functie G-Info().

In het Voorbeeldbestand kunt u deze functie aan het werk zien:

Pasenwanneer in cel C2 een jaartal wordt ingetikt zal in cel D2 worden weergegeven, wanneer Pasen in dat jaar valt.

In cel D2 staat de formule =BepaalPasen(Jaar). Wanneer deze functie wordt ingetikt, zal in eerste instantie in D2 een getal komen. Door deze cel een datum-opmaak mee te geven zien we, dat Pasen in 2014 op 20 april is geweest. Ik heb de cel een aangepaste opmaak meegegeven: niet alleen de datum komt in cel D2, deze wordt vooraf gegaan door de tekst “Pasen valt op”.

LET OP: het Voorbeeldbestand bevat een viertal zelf-gedefinieerde namen, zodat de gebruikte formules veel beter leesbaar zijn. Cel C2 bijvoorbeeld heeft de naam Jaar gekregen.
Voor uitleg over het definiëren van namen, zie het artikel Namen ipv celverwijzingen.

G_Info()

De functie G_Info() vormt een uitbreiding op de functie BepaalPasen. Als parameter/argument wordt niet allen het jaar meegegeven, maar ook van welke feestdag de datum bepaald moet worden. Als derde parameter dient nog meegegeven te worden of de functie een datum moet retourneren (een getal dus) of een tekst.

FeestdagenAls voorbeeld: in C7 staat de formule =G_Info(Jaar;$B7;C$6).
Deze levert als resultaat de datum voor Pasen (cel B7) in het jaar 2014 en wel als echte datum (niet als tekst; cel C6)). Het resultaat is een getal, die een datumopmaak mee heeft gekregen.

PS1 let op de $-tekens in de formule; deze zijn zodanig gekozen, dat bij het kopiëren van de formule (naar rechts en naar beneden) de juiste verwijzingen blijven bestaan.
PS2 ik had de formule graag G-Info genoemd, maar het -streepje is in een functienaam niet toegestaan.

De formule in cel D7 geeft ook de Paasdatum weer, maar nu is het resultaat een tekst.

Naast de Paasdatum levert G_Info() ook de data voor Pinksteren, Carnaval, Hemelvaart, Kerstmis en Nieuwjaar (die laatste 2 liggen nogal voor de hand!). Zoals we hierna zullen zien, zijn uitbreidingen makkelijk door te voeren. Een verjaardag of huwelijksdag vergeten is er dus niet meer bij!

VBA

Eigen functies (in het Engels: User Definied Function, UDF) worden op dezelfde plaats gedefinieerd als waar macro’s worden geregistreerd: in de VBA-editor. Wanneer u daar nog nooit mee hebt gewerkt, bekijk dan het betreffende artikel.

Een korte uitleg van het programma:

PasenVBA1

Allereerst definiëren we de naam van de functie: G_Info.
NB zoals al eerder aangegeven is een – (streepje) niet toegestaan.
Daar achter, tussen haakjes, geven we aan welke parameters/argumenten/waarden aan de functie worden meegegeven: het Jaar, waarvoor de feestdagen bepaald moeten worden (moet een Integer=geheel getal zijn), voor welke Feestdag moet er informatie opgeleverd worden (een String=tekst) en een parameter TekstUitvoer (van het type Boolean; kan alleen de waarden WAAR of ONWAAR bevatten).
De groene tekst (achter het ‘-teken) is commentaar en wordt door het programma niet gebruikt.
In het vervolg van het programma willen we tusseninformatie ‘onthouden’ daarom definiëren we via Dim een variabele x.
PasenVBA2Het programma moet nu afhankelijk van de inhoud van de parameter Feestdag de datum van Pasen of van Pinksteren of van Carnaval etcetera genereren.
Binnen VBA is daar een handige constructie voor:
Select Case ….
     Case Voorwaarde1
Vervolg1
      Case Voorwaarde2
Vervolg2
……
End Select
Wanneer in onze functie aan de parameter Feestdag de waarde Pasen wordt meegegeven, moet het programma de Paasdatum gaan bepalen. Afhankelijk van de inhoud van TekstUitvoer (WAAR of ONWAAR) levert het programma een tekst of een datum/getal op. Dit resultaat wordt in de hulpvariabele x bewaard.
PasenVBA3De Select-optie wordt afgesloten met een Case Else: als er aan de parameter Feestdag een andere tekst wordt meegegeven dan waar in ons programma rekening mee is gehouden, zal dit programmagedeelte worden uitgevoerd.

Na afsluiting van de Select-constructie (dus na End Select) moeten we nog zorgen, dat de de functie in Excel het resultaat van het programma weergeeft. Aangezien we het resultaat in de variabele x hebben vastgelegd sluiten we de functie af met G_Info=x.

Het mag nu niet moeilijk meer zijn om de functie uit te breiden met voor u belangrijke feestdagen als verjaardag, huwelijksdag enzovoorts.

PS de twee in het Voorbeeldbestand gebruikte functies (BepaalPasen en G_Info) zijn zonder aanpassingen ook bruikbaar in Access. Kopieer de functies naar de VBA-omgeving (Module) van Access en u kunt ze direct in een query inzetten.

Kalender

In het voorbeeld is ook een jaaroverzicht opgenomen, waarin direct de diverse feestdagen worden geaccentueerd:
Feestdagen2In dag 1 van januari staat de formule =Datum(Jaar;Maand;Dag) en deze formule is naar rechts en naar beneden gekopieerd. Deze Excel-functie genereert afhankelijk van het jaar, maand- en dagnummer de betreffende datum (in Excel-formaat, dus een getal; zie ook het betreffende artikel over Datums).
Jaar is de naam van cel C2, Maand de naam van het bereik met de cijfers 1 t/m 12 voor de maandomschrijvingen en Dag is het bereik met de cijfers 1 t/m 31.
Alle betreffende cellen hebben bij cel-eigenschappen het datumformaat “ddd” meegekregen: dus alleen de weekdag wordt afgekort getoond.

De blanco cellen op het einde van diverse maanden, de kleuren voor de weekenden en de kleuren voor de feestdagen worden m.b.v.  Voorwaardelijke opmaak geregeld (via de menu-optie Start in het blok Stijlen).
Feestdagen3