Uit de cursus: Basisbeginselen van programmeren: voorbeelden uit de echte wereld

Gebeurtenisgestuurde programmering

- Het gebruik van de pollingmethode om te controleren op de pizzabezorging was niet erg efficiënt. En het was behoorlijk vermoeiend om die trappen op en af te rennen. Gelukkig is er een betere manier om op de pizzaman te wachten. Event-driven programmeren. Ik kan hier gewoon op bed liggen, wachtend op een gebeurtenis. En wanneer die gebeurtenis zich eindelijk voordoet, zal het mijn wachttoestand onderbreken en pas dan zal ik van het bed moeten opstaan om die gebeurtenis met de juiste actie af te handelen. Er zijn veel verschillende soorten gebeurtenissen die ik bereid ben aan te pakken. Een voorbeeld is een timergebeurtenis. Het pizzabedrijf belooft dat ze de pizza in 30 minuten of minder zullen bezorgen. En ik heb besloten om ze een paar minuten speling te geven, dus ik heb een timer ingesteld voor 45 minuten. En als ik mijn pizza tegen die tijd nog niet heb ontvangen, moet ik ze waarschijnlijk bellen om te zien of er een probleem is met de bestelling. (telefoon gaat) Nu de timergebeurtenis mijn wachttoestand heeft onderbroken, moet ik het afhandelen zoals ik zei dat ik zou doen door het pizzabedrijf te bellen. Hallo, ik wacht nog steeds op die pizza. Ah, oké, tot snel. Vast in de file. Nou, nu ik klaar ben met het afhandelen van die timergebeurtenis, kan ik terugkeren naar mijn wachttoestand. Naast het gebruik van timers om gebeurtenissen te activeren, kan ik ook reageren op door gebruikers gegenereerde gebeurtenissen zoals een druk op de knop. (deurbel gaat) Ah, de deurbel! Dat moet de pizza zijn. Nu zal ik dat evenement afhandelen door de pizza te gaan halen. Dus ik ga de trap af, maar deze keer maar één keer. En nu kan ik de pizzaman ontmoeten. (telefoon gaat) Oh, ik hoor mijn telefoon boven rinkelen. Normaal gesproken zou ik mijn telefoon meteen opnemen, maar ik zit midden in het afhandelen van deze deurbelbelgebeurtenis. Als een gebeurtenisgestuurd programma kan ik slechts één gebeurtenis tegelijk verwerken, en ik zal dit doen in de volgorde waarin die gebeurtenissen plaatsvinden. Dat betekent dat het heel belangrijk is dat ik er niet te lang over doe om de deur te beantwoorden, anders mis ik misschien dat telefoontje. Dus, zonder verder oponthoud. Hé, je hebt het gehaald. Hier, houd de verandering. En nu kan ik de telefoon opnemen. Hé Bern, hoe gaat het? Dit is het Python-script genaamd start_12_01_alarms_and_doorbells, wat een korte studie is in het omgaan met levensgebeurtenissen. Ik begin met het importeren van een module genaamd Tkinter, de standaard Python-module voor het maken van grafische gebruikersinterfaces. Ik kies ervoor om Tkinter hier te gebruiken om event-driven programmering te demonstreren, omdat het een eenvoudig framework is om evenementen te maken en af te handelen. Gebruikersinterfaces zijn bijna altijd ontworpen als gebeurtenisgestuurde programma's omdat hun doel is om te reageren op acties van gebruikers. Ik zal niet in detail treden over de functie achter de schermen van de Tkinter-module, want dat is op zichzelf al een enorm onderwerp. In een gebeurtenisgestuurd programma moet ik de code opgeven die wordt uitgevoerd wanneer elk van de verschillende gebeurtenissen zich voordoet. Dit worden gebeurtenishandlers genoemd. Ik heb drie functies in dit script geschreven die fungeren als de handlers voor de drie gebeurtenissen. Mijn wekker gaat af, de deurbel gaat en mijn telefoon rinkelt boven. Als het timeralarm afgaat, bel ik het pizzabedrijf om te kijken waar mijn pizza is. Als de deurbel gaat, moet ik hem openen. En als mijn telefoon overgaat, moet ik de telefoon opnemen. Het onderste deel van dit script gebruikt de Tk constructor-methode van de Tkinter-module om een nieuw GUI-venster te maken, dat ik root heb genoemd, en vervolgens worden er twee knoppen in dat venster gemaakt. De eerste knop, met de tekst Ring Doorbell erop, is zo geconfigureerd dat wanneer de gebruiker op die knop klikt, deze een gebeurtenis genereert die de opdracht uitvoert die ik heb opgegeven. In dit geval zal het klikken op Ring Doorbell de deurbelfunctie uitvoeren. Ik heb hetzelfde gedaan om een tweede knop met het label Oproeptelefoon te maken, die de functie voor het verwerken van telefoongesprekken uitvoert wanneer erop wordt geklikt. Dat zijn dus mijn twee knoppen om door gebruikers gegenereerde gebeurtenissen te activeren. De regel daarna configureert de timergebeurtenis met behulp van de after-methode van Tkinter. Wanneer deze methode wordt aangeroepen, start deze een timer voor 4.000 milliseconden, wat vier seconden is, en nadat die tijd is verstreken, genereert deze een gebeurtenis om de alarmfunctie uit te voeren. De allerlaatste regel van dit script is gewoon iets dat nodig is om de Tkinter-module een kickstart te geven om alles te laten draaien. Dus laten we dit script nu uitvoeren. Dat creëerde het kleine raam met knoppen om aan te bellen of de telefoon te bellen. En nadat vier seconden zijn verstreken, wordt de timergebeurtenis geactiveerd en wordt "Calling the Pizza Company" afgedrukt in het shell-venster. In het scenario eerder, terwijl ik wachtte tot mijn wekker afging, ging ik in een wachttoestand door een dutje te doen. Hetzelfde gebeurt in het programma omdat het ook in een afwachtende toestand gaat. En wanneer de timer afloopt, onderbreekt deze die wachtstatus en activeert het programma om de handler voor die timergebeurtenis uit te voeren. Ik kan de wachtstatus ook handmatig onderbreken door gebeurtenissen te genereren, aan te bellen of de telefoon te bellen. Wanneer ik op een van die knoppen klik, voert de Python de juiste handlerfunctie uit en keert vervolgens terug naar de wachtstatus totdat de volgende gebeurtenis plaatsvindt. Dus als ik aanbel, beantwoord ik zoals verwacht de deur. En als ik op Telefoon bellen klik, neem ik de telefoon op. Merk op dat beide acties resulteerden in een onmiddellijke reactie. Als ik steeds opnieuw aanbel, kan mijn programma de deur net zo snel beantwoorden als ik op de knop kan klikken. Op dezelfde manier, zo snel als ik de telefoon kan bellen, kan ik hem ook beantwoorden. Maar vandaag is het een luie zaterdag en ik reageer niet altijd snel op dingen. Laten we zeggen, als de deurbel gaat, zit ik midden in het kijken naar een tv-programma en wil ik wachten tot het reclameblok om de deur te beantwoorden. Om dat te simuleren, zal ik een vertraging in het programma invoegen door de tijdmodule te importeren. En dan bel ik de slaapfunctie van de tijdmodule om vier seconden te wachten nadat de deurbel gaat voordat ik hem ga openen. Ik sla dat script op en voer het uit. Dus nu, als ik aanbel, duurt het vier seconden nadat de deurbelhandler heeft afgedrukt "Ding Dong!" voor het programma om voorbij de slaapfunctie te komen en "De deur openen" af te drukken. Als de deurbel de enige gebeurtenis is die in het scenario plaatsvindt, ja, dan is het een beetje vervelend voor de persoon beneden dat ze moeten wachten tot ik de deur open. Maar het is niet het einde van de wereld. Maar wat gebeurt er als iemand me vlak nadat de deurbel gaat belt? Nou, dat zal ik nu aantonen door aan te bellen en dan meteen te bellen. Het programma neemt de telefoon pas op nadat ik de deur heb geopend. Laat ik dat nog één keer doen. Ik bel aan en terwijl de deurbelfunctie vastzit, plaats ik een telefoontje. Dat telefoontje wordt pas beantwoord nadat ik helemaal klaar ben met het afhandelen van het deurbelevenement. Dit komt omdat Tkinter slechts één gebeurtenis tegelijk kan verwerken, en dit doet het in de volgorde waarin die gebeurtenissen plaatsvinden. Dus wanneer de deurbelgebeurtenis plaatsvindt, is het programma bezig met het uitvoeren van die deurbelhandler. En wanneer de telefoongesprekgebeurtenis plaatsvindt, wordt deze in een gebeurteniswachtrij geplaatst die moet worden afgehandeld zodra de deurbelgebeurtenis is voltooid. Ik kan zelfs meerdere telefoongebeurtenissen in de wachtrij van de handler plaatsen. Dus als ik bijvoorbeeld aanbel, en dan plaats ik heel snel vijf oproepen, zul je merken dat nadat de deurbelhandler klaar is, Tkinter die vijf oproepen gaat afhandelen. Dit is de reden waarom u uw handlerfuncties moet ontwerpen om in de kortst mogelijke tijd uit te voeren. Als het te lang duurt voordat uw handler wordt uitgevoerd, vertraagt u de verwerking van andere acties en dat kan een trage en onhandige gebruikersinterface creëren.

Inhoud