|
[ Home ] [ zurück ] [ Seitenende ] [ Teil 1 ] [ Teil 3 ] |
|
|
micro:bit-Programmieren, Teil 2 1. Einleitung
Bekanntlich verfügen alle Menschen über fünf
Sensoren, pardon Sinne. So kann der Mensch mit seinen Augen sehen, mit den Ohren
hören, mit der Zunge schmecken, mit der Nase riechen und mit den
Fingerspitzen der Hände fühlen. Im Allgemeinen funktionieren unsere Sensoren
recht zuverlässig, kann man sich auf diese verlassen. Manchmal schwinden uns
aber auch die Sinne, wenn wir bei Feierlichkeiten zu viel Alkohol getrunken
haben. Dann fangen die Buchstaben,
englisch „characters“, an zu tanzen, lassen sich Zeichenketten, englisch „strings“ nicht mehr richtig
erkennen, zuordnen und interpretieren: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man aber weder betrunken ist, noch unter
Halluzinationen leidet, dann erkennt man sofort, dass es sich bei dem Textstring „!dlroW olleH“ im Programm
„microbit_teil_02_prog_01.hex“
mit dem Sourcecode „microbit_teil_02_prog_01.js
einfach nur um die rückwärts von rechts nach links geschriebene Zeichenfolge „Hello World!“, d.h. auf deutsch
„Hallo Welt!“ handelt. Linkshändern, d.h.
Menschen deren beiden Gehirnhälften anders herum „verdrahtet“ sind und die
deshalb bevorzugt mit der linken Hand schreiben, müsste man eigentlich auch
die Gelegenheit geben, von rechts nach links, d.h. spiegelbildlich zu
schreiben, damit diese mit der Hand nicht die frische Tinte verschmieren. Schriftsetzer bei der Zeitung oder beim
Buchdruck, deren Beruf aber wegen der Computerdrucksetzung inzwischen
ausgestorben ist, musste die Druckplatten noch stets in Spiegelschrift
anfertigen, hatten also mit dem Rückwärtsschreiben und -lesen überhaupt kein
Problem. Dem Computer, d.h. unserem „micro:bit“-Rechner macht es übrigens nichts aus, Textstrings
spiegelbildlich von rechts nach links zu lesen und sie in der richtigen
Reihenfolge wieder auf dem Display, d.h. der „5 x 5 LED-Matrix“ anzuzeigen. Allerdings macht der Computer
immer nur das, was man ihm beigebracht bzw. programmiert hat. Und die Laufschrift
auf dem „Display“ geht natürlich nach wie vor von rechts nach links. 2. Vom Block-Programmieren zu JavaScript
Wie bereits im Kapitel „micro:bit-Programmieren, Teil 1“ gezeigt und
erklärt wurde, verfügt das Block-Programmieren leider nur über einen abgespeckten „basic“-Befehlsvorrat, sodass sich mit
diesem verschiedene Dinge wider Erwarten nicht mit den Blocksymbolen programmieren lassen. Dies ist besonders ärgerlich und
kontraproduktiv, wenn man im „basic“-Befehlsvorrat nach einem bestimmten
Befehl sucht, diesen nicht findet, da nicht implementiert und deshalb eher
früher als später auf JavaScript ausweichen
muss. - 2.1 Spiegelverkehrten Textstring rückwärts
auslesen
Wenn man also den spiegelbildlichen Textstring „!dlroW
olleH“ auf der Display richtig lesbar von links nach
rechts anzeigen will, dann muss man diesen rückwärts, d.h. von hinten
nach vorn auslesen. Dazu muss man die Länge, engl. „length“, des Textstrings ermitteln. Und zwar mit
dem „JavaScritp“-Statement „txtstr.length“ bei dem an die
eigentliche Textvariable txtstr einen Punkt gefolgt von der Angabe „length“ anfügt: (Zum Vergrößern bitte
auf das Bild klicken!) Bei der Längenangabe eines Textstrings,
d.h. dem Inhalt der Textvariablen
txtstr werden auch engl. „spaces“, d.h. ein oder
mehrere Leerschritte in Form von Leerzeichen
„ “ mitgezählt! Wie man oben im Screenshot sieht, werden die Variablen n
und txtstr erst deklariert
und anschließend initialisiert. [
Video 1 ] Dabei legt man beim Deklarieren fest, von
welchem Typ die jeweilige Variable sein soll. Demzufolge ist die Zählvariable n vom Typ
int8, engl. „integer“,
d.h. ganzzahlig positiv (oder negativ). (Zum Vergrößern bitte
auf das Bild klicken!) Wie wir jetzt wissen, handelt es sich bei der
Datenangabe Typ ‚int8’ im Programm „microbit_teil_02_prog_02.hex“
und dem Sourcecode „microbit_teil_02_prog_02.js“
um eine Alias-Angabe
für den Typ ‚int’ im Sinne von
‚integer’, d.h. ganzzahlig positiv oder negativ. Leider wird die Typangabe ‚int’ vom „micro:bit“-Rechner bzw. der Microsoft „MakeCode“-Programmierumgebung wider Erwarten nicht
unterstützt, sodass man stattdessen die Typangabe
‚int8’ verwenden muss. - Der „Windows“-eigene Taschenrechner lässt sich übrigens
auf „Programmierer“ umschalten, sodass
sich mit diesem ganz bequem dezimale Zahlen in binäre, oktale oder hexadezimale (und umgekehrt) umrechnen
lassen: (Zum Vergrößern bitte
auf das Bild klicken!) Was jetzt noch fehlt, ist die rückwärts
zählende Schleife zwecks Anzeige der einzelnen
Buchstaben des spiegelbildlichen
Textstring „!dlroW olleH“: (Zum Vergrößern bitte
auf das Bild klicken!) Bei der im Quelltext stehenden „while“-Schleife fällt auf, dass die Textvariable txtstr in Form eines
sogenannten „Substrings“ der Länge von nur einem Zeichen an der Position n
wiedergegeben wird. Dabei verändert sich die Position n eines darzustellenden
Zeichens aus dem Textstring von Position 12
(ganz rechts) auf Position 1 (ganz links), sodass der spiegelbildliche
Textstring in Form der einzelnen
Buchstaben quasi von rechts nach
links angezeigt werden. Im Prinzip aber werden die einzelnen
Buchstaben so dargestellt wie bei der Laufschrift selbst; sie werden dabei aber nur rückwärts aus
dem Textstring ausgelesen! Mit dem Programm
„microbit_teil_02_prog_02.hex“
und dem Sourcecode „microbit_teil_02_prog_02.js“
können Sie das Ganze selbst ausprobieren! - Wenn man die flüchtige Laufschrift „einfangen“
und das Ergebnis sichern möchte, dann muss man das Programm noch entsprechend
erweitern und den angezeigten Inhalt in Form der einzeln angezeigten
Buchstaben in einem separaten Textstring wie folgt aufaddieren und
abspeichern: (Zum Vergrößern bitte
auf das Bild klicken!) Das Programm
„microbit_teil_02_prog_03.hex“
und den Sourcecode „microbit_teil_02_prog_03.js
kann man sich im Browser anzeigen
lassen oder mittels rechter Maustaste
herunterladen. - 2.2 Von der „while“-
zur „for“-Schleife
Neben den „while“-Schleifen gibt es auch noch die
„for“-Schleifen, die allgemein
beliebter sind und sich leichter programmieren und verstehen lassen, weil man
mit diesen innerhalb der Schleife meistens nur von null an bis zu einem
bestimmten Endwert hoch zählt. Im vorliegenden Fall geht es bei der „for“-Schleife aber nur darum, dass die
Schleife entsprechend der Stringlänge der Variablen txtstr = „!dlroW olleH“ insgesamt bis zu 12 mal
durchlaufen wird, wobei es keine Rolle spielt, ob dabei die Schleife
hoch- oder runtergezählt wird. Beim zwölfmaligen Schleifendurchlauf braucht
man dann aber eine weitere Variable, um mit dieser die Position eines einzelnen Zeichens innerhalb des Textstrings anzulaufen und abzufragen. Dabei
handelt es sich um die (Positions-)
Variable m mit der der Textstring txtstr rückwärts durchlaufen wird: (Zum Vergrößern bitte
auf das Bild klicken!) Das Programm
„microbit_teil_02_prog_04.hex“
und den Sourcecode „microbit_teil_02_prog_04.js
kann man sich im Browser anzeigen
lassen oder mittels rechter Maustaste
herunterladen. - Wenn man mit einer „for“-Schleife rückwärts
zählen will, dann muss man diese von Grund auf besser verstehen. Wie man bei der „for“-Schleife im obenstehenden
Programm sieht, stehen in der runden Klammer
( … ) insgesamt drei
Terme, als da sind: (n = 0; n <= txtstr.length; n++), die jeweils durch
ein Semikolon voneinander getrennt
sind: 1. Term n = 0 2. Term n <= txtstr.length 3. Term n++ So, jetzt dürfte es nicht mehr so schwer
fallen, die drei Terme so zu programmieren, dass sich mit diesen ein
entsprechender Schleifenkopf zu einer „for“-Schleife mit der sich
herunterzählen lässt, zu gestalten: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Sourcecode
sieht, braucht man jetzt zum zwölfmaligen Schleifendurchlauf keine
weitere (Hilfs-) Variable m mehr, um mit dieser die Position eines einzelnen Zeichens innerhalb des Textstrings anzulaufen und abzufragen, da wir
jetzt mit der „for“-Schleife rückwärts
zählen! Selbstverständlich lässt sich das Ganze mit
dem Programm „microbit_teil_02_prog_05.hex“
auch ausprobieren und der Sourcecode „microbit_teil_02_prog_05.js
wie gewohnt im Browser anzeigen
oder mittels rechter Maustaste
herunterladen. - So, jetzt haben wir ganz nebenbei auch noch
gelernt, was eine „while“- von einer „for“-Schleife unterscheidet und wie
man mit einer „for“-Schleife auch rückwärts zählen
kann. [ Video 2 ] 2.3 Umschaltbare Textstring-Anzeige
Wie im obenstehenden Programm zu sehen ist,
haben wir es mit zwei Stringvariablen
txtstr und new_txtstr zu tun. Dabei enthält die Stringvariable txtstr den spiegelverkehrten Textstring „!dlroW olleH“ und die Stringvariable new_txtstr den umgewandelten Textstring „Hello World!“. Diesbezüglich bietet es sich an, dass man die Textanzeige mit der „5 x 5 LED-Matrix“ umschaltbar
macht, sodass beim Tastendruck auf den Taster A der spiegelverkehrte Textstring
„!dlroW
olleH“ als Laufschrift angezeigt wird und beim
Tastendruck auf den Taster B der umgewandelte Textstring „Hello World!“: (Zum Vergrößern bitte
auf das Bild klicken!) Damit sich die beiden Taster A und B
jederzeit betätigen lassen, werden diese mit dem Statement basic.forever(() => { … }) quasi als „Endlos“-Schleife eingebunden. Der Sourcecode „microbit_teil_02_prog_06.js
lässt wie üblich direkt im Browser
anzeigen oder als Programm „microbit_teil_02_prog_06.hex“
im „micro:bit“-Rechner ausführen. 2.4 Zusammenfassung zweier Textstrings zu
einem Array
Das englische Wort „array“ lässt sich wörtlich mit „Feld, Ansammlung
oder Aufstellung“ übersetzen. Dabei kann man sich durch aus ein Spargelfeld
vorstellen, das sich aus mehreren Spargelreihen zusammen setzt. Da sich unser
dezimales Zahlensystem vom hindu-arabischen
Zahlensystem ableitet und es in diesem bereits die Zahl null gab, bekommt
die erste Spargelreihe in unserem Array die Null als Index, um sie von
anderen Spargelreihen nebst fortlaufendem Index unterscheiden zu können. Im nachfolgenden Programm microbit_teil_02_prog_07.hex
mit dem Quellkode microbit_teil_02_prog_07.js
wird die ursprünglich benutzte Stringvariable
txtstr mit dem
spiegelverkehrten Textstring „!dlroW olleH“ umbenannt in die Stringvariable txtstr_1 und die zunächst
leere Stringvariable new_txtstr wird zur Stringvariablen txtstr_2. Des Weiteren wird ein Array namens „str_array: string[]“ wie folgt deklariert:
·
var str_array: string[] ·
str_array =[txtstr_1, txtstr_2] Dabei ist das Array bzw. die var str_array: string[] zunächst unbestimmt,
kann das Array praktisch beliebig
viele Elemente aufnehmen, auch
nachträglich: (Zum Vergrößern bitte auf
das Bild klicken!) Im Programm
microbit_teil_02_prog_08.hex
mit dem Quellkode microbit_teil_02_prog_08.js
wird dann das Array namens „str_array: string[]“ beim Konvertieren
des spiegelbildlichen Textstrings mit txtstr_1 = "!dlroW olleH" in der „for“-Schleife auch entsprechend
benutzt: (Zum Vergrößern bitte
auf das Bild klicken!) [ Video 3 ] Beim Programm
microbit_teil_02_prog_09.hex
mit dem Quellkode microbit_teil_02_prog_09.js
stellt sich die Frage, weshalb beim Drücken des Tasters A nun plötzlich nicht mehr der Text „!dlroW olleH“, sondern vielmehr „Hallo Welt!“ im Display, d.h. auf der „5 x 5
LED-Matrix“ angezeigt wird: (Zum Vergrößern bitte
auf das Bild klicken!) Der Grund dafür, dass beim Betätigen des Tasters A jetzt plötzlich der Schriftzug „Hallo Welt!“ angezeigt wird und nicht mehr „!dlroW
olleH“, ist der, dass es sich bei dem Programmblock „basic.forever(()
=> { … })“
um einen sogenannten Konstruktor innerhalb des Hauptprogramms handelt. [ Video 4a ] Im vorliegenden Fall handelt es sich sogar um
einen besonderen Konstruktor
namens „forever“, da dieser den in der
geschweiften Klammer { … } enthaltenen Programmkode fortwährend im Hintergrund (des
Hauptprogramms) ausführt, sodass sich die Taster A und B jederzeit betätigen lassen.
Man könnte auch sagen, dass es sich bei dem „forever“-Konstruktor um eine Ereignis gesteuerte Programmierung handelt bei der das
Programm stets im Hintergrund lauert und darauf
wartet, dass etwas passiert, um dann sofort darauf zu reagieren. Das Ereignis selbst wäre dann aber nur der Tastendruck auf
den Taster A oder B. Da ein Konstruktor ein in sich geschlossenes (Teil-) Programm
ist, lassen sich in ihm auch eigene, d.h. lokale Variable deklarieren und initialisieren, die nach außen zu den
anderen Programmteilen hin abgeschirmt und nicht ohne Weiteres von außen
zugänglich sind! 2.5 Strukturiertes Programmieren mit
Funktionen
Programmiertechnisch lässt sich eine Funktion als ein besseres, flexibleres Unterprogramm bezeichnen. Dabei handelt es sich aus
der Sicht des Hauptprogramms um
eine „Black Box“
in die man etwas hinein gibt, den Input anhand von Regeln ähnlich einer
Rezeptur intern verarbeitet, gestaltet, organisiert und strukturiert, sodass
sich am Ausgang ein Output einstellt, dessen Ausgangsprodukt einen höheren
Mehrwert als das Eingangsprodukt hat. Dabei kann das Ausgangsprodukt auch
neue Eigenschaften und Funktionen enthalten, die es zuvor so noch nicht gab.
Entscheidend bei einer Funktion ist, dass man aus Sicht des Hauptprogramms gar nicht weiß und
auch gar nicht wissen will, was in der Funktion
als Black Box vor sich geht.
Hauptsache es kommt aus der Black Box etwas Wertvolleres heraus, als man in diese zuvor
hineingegeben hatte. Außerdem soll die Funktion
das Hauptprogramm nicht stören und in Ruhe lassen, soll das Geschehen in der
Funktion als Black Box abgeschirmt sein und dabei das Hauptprogramm
entlasten. Wenn dabei aber trotzdem Fehler passieren, dann bitte schön nur in
der Funktion ohne das
Hauptprogramm dadurch zu beeinflussen oder sogar zum Absturz zu bringen. Der Hauptvorteil einer Funktion ist aber der, dass man bestimmte und immer wieder
vorkommende Vorgänge, Schemata und Routinen in der Funktion zusammenfasst, d.h. aus dem Hauptprogramm auslagert, wobei
sich die Funktion von überall her und
beliebig oft aufrufen lässt. Wie man im Programm microbit_teil_02_prog_10.hex
mit dem Quellkode microbit_teil_02_prog_10.js
sieht, muss eine Funktion nicht nur
programmiert werden, sondern auch explizit aufgerufen werden, da sie sich nicht von allein, z.B. nach
dem Programmstart eines Programms startet: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Sourcecode
sieht, werden im Kopf der Funktion „function starteProgramm() { … }“ (siehe roter Kasten) keine
Variablen oder Variableninhalte an diese übergeben. Demzufolge ist runde Klammer () leer. Würde man der Funktion „function starteProgramm() { … }“ (siehe roter Kasten) entsprechende (Variablen-)
Inhalte mit auf den Weg geben wollen, dann müsste dies bereits mit dem Funktionsaufruf „starteProgramm()“
veranlasst werden. Da die runde
Klammer ()
beim Funktionsaufruf aber leer
ist, werden keine Inhalte an die Funktion übergeben! Im Programm
microbit_teil_02_prog_11.hex
mit dem Quellkode microbit_teil_02_prog_11.js
erfolgt jetzt aber der Funktionsaufruf mittels der Übergabe einer Textmitteilung, eines Textstrings statt: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man oben im Programm sieht, wird die Variable str_einlesen im Kopf der Funktion
„function
starteProgramm(str_einlesen: string) deklariert, aber nicht
initialisiert, da dies
bereits mit dem Funktionsaufruf starteProgramm(„Dies ist eine Funktion!“) erfolgt! Dieser Umstand ist nicht nur logisch, sondern
auch nachvollziehbar: Würde man nämlich die Variable str_einlesen im Kopf
der Funktion „function starteProgramm(var str_einlesen: string) mittels „var“
deklarieren,
dann bekäme die Variable str_einlesen beim Deklarieren bereits den Wert null, d.h. leer mit auf den Weg, sodass sich der Textstring „Dies ist eine Funktion!“ nicht mehr
übergeben ließe und zu einer Fehlermeldung führen würde! [ Video
4b ] Wie man im Programm microbit_teil_02_prog_12.hex
mit dem Quellkode microbit_teil_02_prog_12.js
sieht, lässt sich beim Funktionsaufruf
auch der spiegelbildliche Textstring „!dlroW olleH“ der Variablen
txtstr_1 an die Funktion „function starteProgramm(str_einlesen: string) wie folgt übergeben: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im Programm microbit_teil_02_prog_13.hex
mit dem Quellkode microbit_teil_02_prog_13.js
sieht, lässt sich der Funktionsaufruf
starteProgramm(txtstr_1) auch von außerhalb des Hauptprogramms, nämlich z.B. im „forever“-Konstruktor vornehmen: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Quellkode sieht, wird
mit dem Funktionsaufruf starteProgramm(txtstr_1) der Variableninhalt
„Hallo Welt!“ der lokalen Variablen txtstr_1
des „forever“-Konstruktors an die Funktion übergeben! Außerdem wird die Funktion starteProgramm(txtstr_1) erst dann aufgerufen, wenn der Anwender den Taster A betätigt! - Wie man im Programm microbit_teil_02_prog_14.hex
mit dem Quellkode microbit_teil_02_prog_14.js
sieht, lässt sich beim Funktionsaufruf
der Funktion „function starteProgramm(str_einlesen: string) nicht nur ein Textstring oder der Wert einer Variablen
übergeben, sondern lassen sich am Ende der Funktion mit dem Statement
return (str_ausgeben) auch ein Textstring oder der Wert einer Variablen an den aufrufenden „forever“-Konstruktor wieder zurück geben. Da das Zurückgeben von Daten und Dateninhalten
mittels der Variablen str_ausgeben im Statement return (str_ausgeben)
erfolgt, also von der Funktion „function starteProgramm(str_einlesen: string) veranlasst wird, muss und kann das Deklarieren der (Rückgabe-) Variablen str_ausgeben nur innerhalb
der Funktion erfolgen. Dabei gilt
es quasi zwischen Ursache und Wirkung zu unterscheiden, da sich der Dateninhalt der Variablen str_ausgeben nur mit dem Statement return (str_ausgeben) zurückgeben lässt und zwar auch nur dann,
wenn die Variablen str_ausgeben zuvor
innerhalb der Funktion deklariert und
initialisiert wurde: (Zum Vergrößern bitte
auf das Bild klicken!) Besonders interessant ist dabei nun, dass sich
der aufrufende „forever“-Konstruktor gar nicht für
die Datenrückgabe der Funktion mittels des Statement return (str_ausgeben)
interessiert bzw. auch gar nichts davon weiß bzw. wissen kann, da es für die Aufnahme des Datenrückflusses überhaupt keine Variable gibt, sodass die Datenrückgabe ins Leere geht! Wenn sich aber der aufrufende „forever“-Konstruktor gar nicht für
die Datenrückgabe der Funktion mittels des Statement return (str_ausgeben)
interessiert, dann könnte man diese ja auch weglassen! Diesbezüglich stellt aber gleich die Frage,
wozu der Rücksprung mittels des „return“-Statements überhaupt gut sein
soll! Ganz einfach, damit die aufrufende und ausführende Funktion „function starteProgramm(str_einlesen: string) wieder veranlassen wird und mit dem Programmablauf dort weitergemacht
wird, von wo man zuletzt aus verzweigt ist, nämlich im „forever“-Konstruktor! Ob es nach dem Rücksprung aus der Funktion
„function
starteProgramm(str_einlesen: string) dann tatsächlich noch zur Datenübergabe kommt oder nicht, ist also aus der
Sicht der Funktion uninteressant,
da diese ohnehin keinen direkten Einfluss darauf hat! Aber es bleibt spannend, müssen wir noch etwas
Detektivarbeit leisten und uns Gedanken machen, wie man den veranlassten Rücksprung aus der Funktion „function starteProgramm(str_einlesen: string) tatsächlich überprüfen kann. Also
bleibt uns nichts anderes übrig, als im aufrufenden „forever“-Konstruktor noch die Variable txtstr_1
für die Datenübernahme zu programmieren
(siehe Programm microbit_teil_02_prog_15.hex
mit dem Quellkode microbit_teil_02_prog_15.js):
(Zum Vergrößern bitte
auf das Bild klicken!) Mit dem obenstehenden Programm und der Variablen txtstr_1
haben wir zwar die Voraussetzung für die Datenübernahme beim Rücksprung
aus der Funktion „function starteProgramm(str_einlesen: string) geschaffen, aber ob das auch in der
gewünschten Weise wirklich funktioniert wissen wir bis jetzt trotzdem noch
nicht! Erst wenn wir uns im Programm microbit_teil_02_prog_16.hex
mit dem Quellkode microbit_teil_02_prog_16.js)
mittels des Funktionsaufrufs
starteProgramm(txtstr_1) tatsächlich den Variableninhalt der lokalen Variablen txtstr_1 anzeigen lassen,
haben wir die Gewissheit, dass der Rücksprung aus der Funktion „function starteProgramm(str_einlesen: string) nebst Datenübergabe an die lokale Variable
txtstr_1 tatsächlich in
der gewünschten Art und Weise funktionieren: (Zum Vergrößern bitte
auf das Bild klicken!) Jetzt wissen wir endlich wie leistungsfähig
aber auch komplex Funktionen sein
können, und dass sich diese auch per Tastendruck
auf den Taster A aufrufen und
ausführen lassen. Ferner wissen wir, dass es nicht nur globale
Variablen, die meistens im Hauptprogramm deklariert und/oder
initialisiert werden, gibt, sondern auch lokale Variablen, die in Konstruktoren oder Funktionen eingesetzt werden und vom Hauptprogramm aus nicht
erreichbar und nutzbar sind, .da sie quasi abschirmt sind. Abschließend gibt es aber noch etwas
Interessantes festzuhalten. Wahrscheinlich ist Ihnen bereits kurz nach dem
Programmstart aufgefallen, dass dieses angeblich schon wieder beendet wurde
(siehe Statement basic.showString("Programmende!")).
Wie kann das sein? Schließlich lassen sich
trotz der Meldung „Programmende!“ noch immer die Taster A und B
betätigen und die im „forever“-Konstruktor programmierten
Reaktionen darauf anzeigen! Ganz einfach! Nach dem Programmstart werden alle
Statements linear, d.h. der Reihe nach, aufgerufen und abgearbeitet. So auch
der „forever“-Konstruktor, der ja still und
leise im Hintergrund vor sich hin werkelt
und ständig die beiden Taster A und B abfragt, ob diese eventuell gedrückt wurden. Demzufolge nach wurde zwar das Hauptprogramm komplett abgearbeitet
und quasi auch beendet, obwohl es sich per Tastendruck auf einen der beiden Taster A oder B wieder zum Leben
erwecken lässt. Totgeglaubte leben halt doch
länger! [ Video 5 ] 2.6 Von der Funktion zur Methode mit
Funktionsobjekt
Wie man in JavaScript eine Funktion programmiert wissen wir. Dass sich eine Funktion nicht automatisch zusammen mit Hauptprogramm startet, sondern explizit
durch den Aufruf des Funktionnamens aufgerufen
werden muss, wissen wir auch. Aber erinnern wir uns trotzdem noch mal daran,
was eine Funktion ist, was eine Funktion ausmacht und wozu man sie verwendet. Das Charakteristische einer Funktion ist, dass man dieser beim Aufrufen derselben
einen, mehrere oder auch verschiedene Werte, Ausdrücke, Zeichenstrings oder
boolesche Werte im Sinne von „true“ (= richtig)
oder „false“ (= falsch) z.B. in Form von Variablen
mit auf den Weg gibt, d.h. einliest. In der Funktion wird dann festgelegt,
was mit den eingelesenen Variableninhalten passieren soll, wie
diese verarbeitet, verknüpft und ausgewertet werden sollen. Anschließend
lässt sich dann das Ergebnis als Reaktion auf die Verarbeitung
und Auswertung wieder an das aufrufende Programm zurückgeben.
Demzufolge kann man eine Funktion mit einer „Black Box“
vergleichen, in die man etwas hinein gibt und als Ergebnis etwas ähnliches
oder gänzlich anderes heraus bekommt. Kurz gesagt, sorgt eine Funktion dafür, dass etwas in der gewünschten,
beabsichtigten Weise, nach bestimmten, programmierten Anweisungen einfach nur
funktioniert. Koppelt man eine Funktion
an eine Variable, dann spricht man von
einer Methode! >> Methoden (englisch method oder member function) sind in der objektorientierten Programmierung Unterprogramme (in der Form von Funktionen oder Prozeduren), die das Verhalten von Objekten beschreiben und
implementieren. Über die Methoden des Objekts können Objekte untereinander
in Verbindung treten.
<< (Quelle: Wikipedia) Eine Methode
legt also die Vorgehensweise, das wie, womit und
wodurch fest und beeinflusst dabei das Verhalten des betreffenden Objekts!
Bevor wir unsere Funktion „function starteProgramm(str_einlesen: string) in eine Methode
umwandeln, betreiben wir noch etwas Programmkosmetik, hübschen wir uns auf,
indem wir noch etwas Schminke auftragen und den Lippenstift nachziehen. Dabei
dient die Programmkosmetik der besseren Lesbarkeit des Quellkodes, um
Missverständnissen vorzubeugen. Wie wir ja inzwischen wissen, wird neben dem
eigentlichen Hauptprogramm „microbit_teil_02_prog_17“ auch noch der Konstruktor „basic.forever(() => { … })“ als Hintergrundprogramm gestartet, das auch dann
noch arbeitet, wenn das Hauptprogramm
längst abgearbeitet und quasi beendet wurde. Aber wie wir ferner wissen, lässt sich das Hauptprogramm bzw. lassen sich Teile
davon wieder zum Leben erwecken, wenn man den Taster A betätigt und mittels Tastendruck die Funktion „function starteProgramm(str_einlesen: string) startet, die ja ein Teil des Hauptprogramms
ist. Deshalb ist das Ende des Quellkodes nicht das Ende des Programms oder das Programmende, da ja noch der Konstruktor „basic.forever(() => { … })“ still und leise im Hintergrund vor sich hin werkelt bis der Strom
ausfällt! Deshalb lautet jetzt das Ende des Quellkodes im Programm
microbit_teil_02_prog_17.hex
mit dem Quellkode microbit_teil_02_prog_17.js
wie folgt: basic.clearScreen() basic.showString("Ende Quellkode!") Außerdem benennen wir die Funktion „function starteProgramm(str_einlesen: string) jetzt um in Funktion „function starteFunktion(str_einlesen: string), da ja in Wirklichkeit kein neues
Programm gestartet wird, sondern nur eine Funktion des Hauptprogramms, engl. abgekürzt „main“.
- In der Programmierpraxis bzw. beim
Programmieren eines Programms wird es früher oder später vorkommen, dass man
z.B. mittels einer Funktion gleich
zu Beginn, d.h. direkt nach dem Programmstart des Hauptprogramms
ein paar Variablen deklarieren und
initialisieren, ein Array mit Dateninhalten
füllen oder mittels Programmkode den Status
eines Teilprogramms oder einer anderen Funktion usw. abrufen möchte. Zu diesem Zweck müssen wir erreichen bzw.
veranlassen, dass der Programmkode der Funktion gleich beim Programmstart still und leise quasi
im Hintergrund ausgeführt wird,
sodass der Anwender davon überhaupt nichts mitbekommt. Wie wir ja bereits wissen, werden im Hauptprogramm deklarierte und initialisierte,
globale Variablen gleich beim Programmstart eingerichtet, sodass sie ab sofort zur
Verfügung stehen und nutzen lassen. Wenn wir also erreichen wollen, dass sich die Funktion „starteFunktion()“ später beim Programmstart des
Hauptprogramms
mit startet, dann müssen wir der Funktion
im Hauptprogramm eine sogenannte Objektvariable „funktion_var“ zuweisen, die dann
später beim Programmstart deklariert und
initialisiert wird und dadurch dafür sorgt, dass die Funktion „starteFunktion()“ zusammen mit dem Start des Hauptprogramms ausgeführt
wird: (Zum Vergrößern bitte
auf das Bild klicken!) Bei dem obenstehenden Statement „funktion_var()“ (siehe roter Kasten) handelt es sich um den Funktionsaufruf der Funktion „starteFunktion()“, sodass diese direkt
beim Programmstart gestartet und
ausgeführt wird! Wenn alles so funktioniert, wie wir es uns
vorstellen, dann müsste nach dem Programmstart sofort als erstes
die Anzeige „Funktion wurde gestartet!“ im Display angezeigt
werden und als zweites „Ende
Quellkode“.
Mit dem Programm microbit_teil_02_prog_18.hex
mit dem Quellkode microbit_teil_02_prog_18.js
lässt sich das Ganze ausprobieren! Bei der globalen Variablen „funktion_var“ handelt es sich um eine Objektvariable, die entsprechend der Deklaration zur Funktion „starteFunktion()“ gehört. Demzufolge kann man auch von einer Funktions-Objektvariablen reden. Die Funktions-Objektvariable „funktion_var“ wird aber erst dann durch die Funktion „starteFunktion()“ initialisiert,
wenn diese durch das Statement „funktion_var()“ gestartet wird. Wie man im Programm microbit_teil_02_prog_19.hex
mit dem Quellkode microbit_teil_02_prog_19.js
sieht, kann man dem Funktionsaufruf „funktion_var("Funktion wird gestartet!“)“ auch einen Textstring mit auf den Weg geben, der von der Funktion „starteFunktion(str_einlesen: string)“ eingelesen wird: (Zum Vergrößern bitte
auf das Bild klicken!) Im obenstehenden Quellkode ist noch
interessant, dass man sich den Variableninhalt der Variablen str_einlesen ins Boot holen, d.h.
in die lokale Variable str_ausgeben holen und dort weiter
verarbeiten kann, falls das mal notwendig sein sollte. Wie wir inzwischen wissen, wird die Funktions-Objektvariable „funktion_var“ zunächst nur deklariert (siehe großer
roter Kasten oben im Bild) und erst später mittels der Funktion „starteFunktion()“ initialisiert, wenn man die Funktion mittels des Methodenaufrufs funktion_var(“Funktion wird gestartet!“) aufruft! Dabei gilt es zu beachten, dass es sich bei
der Funktion „starteFunktion(str_einlesen: string)“ immer noch um eine Funktion handelt, auch wenn man diese der Objektvariablen „funktion_var“ zuweist. Aber genau durch diese Zuweisung
wird die bestehende Funktion zur Methode nebst Methodenaufruf
funktion_var(“Funktion wird gestartet!“) erweitert. Da es sich bei der Objektvariablen „funktion_var“ jetzt aber um eine Objektvariable der Methode
„starteFunktion(str_einlesen: string)“ handelt, benennen wir diese nachfolgend um in
Objektvariable „methode_starteFunktion“. Jetzt wo es sich bei der erweiterten Funktion um eine Methode handelt, die sich mittels Methodenaufruf „methode_starteFunktion“ aufrufen und starten lässt, können wir
z.B. auch im Hauptprogramm eine
neue, globale Objektvariable „starteMethode“ vom Methodentyp „methode_starteFunktion“ einführen und entsprechend
benutzen. Wie man im nachfolgenden Programm microbit_teil_02_prog_20.hex
mit dem Quellkode microbit_teil_02_prog_20.js
sieht, trifft dies auch auf die lokale Objektvariable „txt_str1“ im Konstrukt „basic.forever(() => { … }“ zu: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man oben im Quellkode sieht, lassen sich
sowohl im Hauptprogramm als auch
in Konstrukten jederzeit globale
und/oder lokale Objektvariablen zur Methode „methode_starteFunktion()“ erstellen und
entsprechend nutzen. [ Video 6 ] Aber wie man im Programm microbit_teil_02_prog_21.hex
mit dem Quellkode microbit_teil_02_prog_21.js
sieht, lässt sich der Methodenaufruf „methode_starteFunktion()“ auch direkt aufrufen,
sodass globale und/oder lokale Objektvariablen nicht mehr erforderlich sind: (Zum Vergrößern bitte
auf das Bild klicken!) [ Video 7 ] Da es im obenstehenden Quellkode noch immer mehrere
Displayanzeigen mit dem Statement „basic.showString(…)“ gibt, lassen sich
diese im Programm microbit_teil_02_prog_22.hex
mit dem Quellkode microbit_teil_02_prog_22.js
wie folgt zu nur noch einer, wenn auch multifunktionalen Displayanzeige in der Methode „methode_starteFunktion = function starteFunktion(str_einlesen: string)“ wie folgt
zusammenfassen: (Zum Vergrößern bitte
auf das Bild klicken!) Damit wir ein noch besseres Verständnis von
einer Funktion und einer Methode und deren Unterscheidungsmerkmale bekommen,
nehmen wir beide gemeinsam in unser Programm
microbit_teil_02_prog_23.hex
mit dem Quellkode microbit_teil_02_prog_23.js
auf: (Zum Vergrößern bitte
auf das Bild klicken!) Damit wir die beiden obenstehenden Programmblöcke ·
function starteFunktion(str_einlesen: string)
{ … } und ·
var objektvar_starteMethode wirklich gut auseinander halten können und
es bei der Programmausführung zu keinen
Fehlern kommt, sollten Sie
unbedingt auf die korrekten Funktions- und Methoden-Namen achten und diese gegebenenfalls abändern. [ Video
8 ] 2.7 Gekapselte Programmmodule in Klassen
Beim Entwickeln und Programmieren ist es
zunächst naheliegend, dass man den Programmkode einfach so der Reihe nach, sozusagen Statement für Statement,
programmiert und sich freut, wenn alles funktioniert. Das geradlinige,
unverzweigte Programmieren ist leicht und bequem führt aber früher oder
später dazu, dass das Programm nicht nur umfangreicher, sondern auch komplexer
und unübersichtlicher wird. Bei nicht objektorientierten, älteren
Programmiersprachen wie z.B. GW-BASIC
für MS-DOS von Microsoft war man dann
schon froh, wenn man einzelne Programmteile aus dem Hauptprogramm in sogenannte Unterprogramme (Statement in
GW-BASIC: „gosub labelname … return“)
auslagern konnte, sodass das Hauptprogramm kompakt und übersichtlich
blieb. Aber bei vielen Unterprogrammen wurde dann die Programmierung der „gosub“-Unterprogramme irgendwann auch unübersichtlich,
sodass es früher oder später nicht ausblieb, dass man einen „return“-Rücksprungbefehl vergaß mit der Folge, dass
einfach mit dem nächsten Unterprogramm fortgefahren wurde und es demzufolge
zu unvorhersehbaren Effekten bei der Programmausführung kam. Bei Turbo Pascal von Borland ließen sich zusammenhängende Programmteile als
sogenannte „include“-Datei auslagern. Bei vielen „include“-Dateien musste man dann aber darauf achten, wie
diese voneinander abhängen oder aufeinander aufbauen. Die derzeitigen Programmiersprachen wie z.B. JavaScript, PHP oder Java sind
alle objektorientiert und verfügen über Funktionen, Methoden (= Funktion mit
Zuordnung zu einer Objektvariablen), Objekten und Klassen. >> Unter einer Klasse (auch Objekttyp genannt)
versteht man in der objektorientierten Programmierung ein
abstraktes Modell bzw. einen Bauplan für eine Reihe von
ähnlichen Objekten. Die Klasse dient als Bauplan für die Abbildung
von realen Objekten in Softwareobjekte und beschreibt Attribute (Eigenschaften) und Methoden (Verhaltensweisen) der
Objekte. Verallgemeinernd könnte man auch sagen, dass eine Klasse dem Datentyp eines
Objekts entspricht. Formal gesehen belegt eine Klasse somit zur
Programm-Ausführungszeit keinen Arbeitsspeicher, sondern immer
nur die Objekte, die von ihr instanziiert wurden.[Anmerkungen
1] (…) Vererbung Klassen
können miteinander in hierarchischen
Beziehungen stehen und zu
komplexen Strukturen werden. Die Gesetzmäßigkeiten, nach denen diese gebildet
werden, beschreibt das grundlegende Konzept der Vererbung.
Hier sind weiterhin die Begriffe Basisklasse und abgeleitete Klasse von Bedeutung, um die Verhältnisse der Klassen
untereinander zu charakterisieren. Dabei beschreibt die Basisklasse
allgemeine Eigenschaften, ist also eine Verallgemeinerung der abgeleiteten Klassen; diese sind somit Spezialisierungen der Basisklasse. Beispiel: Basisklasse Kraftfahrzeug ist
Verallgemeinerung der abgeleiteten Klassen (Spezialisierungen) Auto, LKW,
Motorrad und Traktor. Dabei erben die abgeleiteten Klassen alle
Eigenschaften und Methoden der Basisklasse (d. h., ein Motorrad hat alle
Eigenschaften eines Kraftfahrzeugs, und man kann alles mit ihm machen, das
man mit einem Kraftfahrzeug machen kann). Zusätzlich führt die abgeleitete
Klasse zusätzliche Eigenschaften und Methoden ein, die
bei ihren Objekten möglich sind. (Das Motorrad hat z. B. einen
Gepäckträger, ein Auto nicht, dafür aber einen Kofferraum.) Programmierstil In vielen Programmiersprachen ist es üblich, dass der Name einer Klasse mit
einem Großbuchstaben
beginnt, Variablennamen dagegen
mit einem Kleinbuchstaben.
<< (Quelle: Wikipedia) Durch das Programmieren einer Klasse sind wir schon mitten drin in der objektorientierten Programmierung, obwohl wir noch kein
einziges Objekt programmiert haben. Aber
das soll uns im Moment nicht weiter stören, geht es doch nachfolgend darum,
dass wir zusammengehörende Programmteile in einer Klasse, sozusagen als objektorientiertes Unterprogramm, zusammenfassen. Wie man im Programm microbit_teil_02_prog_24.hex
mit dem Quellkode microbit_teil_02_prog_24.js
sieht, wurde das Programm „microbit_teil_02_prog_23.hex“ (siehe oben) entkernt,
wurden die Funktion starteFunktion(str_einlesen: string) und die Methode
var objektvar_starteMethode
= function starteMethode(str_einlesen: string) sowie deren Aufrufe
im Konstrukt basic.forever(() => { … }) entfernt und die noch
leere Klasse class starteKlasse { … } hinzugefügt: (Zum Vergrößern bitte
auf das Bild klicken!) Wichtig zu wissen ist an dieser Stelle, dass
eine Klasse immer nur dann beim Programmstart des Hauptprogramms oder beim Aufruf von
anderer Stelle aus immer nur dann ausgeführt wird, wenn man diese
mittels einer Objektvariablen und dem neuen Verweis auf die Klasse z.B. wie folgt
aufruft: var objektvar_starteKlasse = new starteKlasse()
Wichtig ist ferner, dass sich innerhalb
der Klasse kein
Programmkode im Sinne von Statements befinden darf! Deshalb dürfen in der Klasse selbst nur Deklarationen und/oder Initialisierungen von Klassen-Variablen stehen. Dies gilt insbesondere auch für Funktionen oder Methoden;
diese dürfen ebenfalls nicht in der Klasse
selbst „gecodet“ werden! Funktionen und Methoden dürfen
nur in einem Konstrukt „contructor() { … }“ programmiert, d.h. „gecodet“
werden! Klasse und Konstrukt gehören also stets zusammen! Wenn man wissen will, ob man eine Klasse nebst Konstrukt fehlerfrei programmiert wurde, dann muss man die Klasse mittels des Statements var objektvar_starteKlasse = new starteKlasse() aufrufen, d.h. ausführen: (Zum Vergrößern bitte
auf das Bild klicken!) Da eine Klasse
keine Funktion oder Methode ist, lassen sich in ihr nur Deklarationen von Klassen-Variablen vornehmen, die sich aber in allen Funktionen,
Methoden usw. innerhalb des Konstruktors „constructor() { … }“ initialisieren und anwenden lassen! Dabei
dient die „this“-Angabe dazu,
festzulegen und aufzuzeigen, dass es sich bei der Variablen this.showStringVar um die Klassenvariable
showStringVar der Klasse startKlasse()
handelt. Man könnte
auch sagen, dass es sich bei der „this“-Angabe um
eine Platzhalter-Variable mit Verweis auf die Klassenvariable
showStringVar handelt. Mit dem Programm
microbit_teil_02_prog_25.hex
und dem Quellkode microbit_teil_02_prog_25.js
lässt sich alles nachvollziehen und ausprobieren. Im Zusammenhang mit der Deklaration der Klassenvariablen showStringVar und dem
Klassenaufruf, d.h. dem Starten der Klasse
starteKlasse() mittels des Statements var objektvar_starteKlasse = new starteKlasse() stellt sich die interessante Frage, ob sich
die Klassenvariable showStringVar auch im Hauptprogramm nutzen und mit Inhalten initialisieren lässt, obwohl man ja
quasi von außen (= Hauptprogramm) nach innen auf die Klassenvariablen showStringVar zugreift. Da die Klasse
starteKlasse() vom Hauptprogramm
aus mittels der Variablen objektvar_starteKlasse gestartet wird, lässt
sich mittels des Statements wie
z.B. txtstr_3 = objektvar_starteKlasse.showStringVar auch auf den Variableninhalt der Klassenvariable
showStringVar zu greifen bzw. lässt
sich dieser mittels des Statements
basic.showString("Ende Quelltext!" + objektvar_starteKlasse.showStringVar) abfragen bzw. im Display wie folgt anzeigen: (Zum Vergrößern bitte
auf das Bild klicken!) Mit dem Programm
microbit_teil_02_prog_26.hex
und dem Quellkode microbit_teil_02_prog_26.js
lässt sich das Ganze nachvollziehen. [
Video 9 ] Wenn man aber der Klassenvariable showStringVar gleich zu Beginn, d.h. zusammen mit dem Start der Klasse
starteKlasse() einen Wert mit auf den Weg geben will, dann
muss man einen anderen Weg einschlagen und diesen gleich beim Initialisieren der Klasse der Klassenvariable
showStringVar wie folgt zuweisen: var objektvar_starteKlasse = new starteKlasse(„Konstrukt!“) Da der Textstring
„Konstrukt!“ direkt an die Klasse „starteKlasse“ übergeben wird,
könnte man meinen, dass der Textstring
auch von dieser entgegengenommen wird. Dem ist aber nicht so, weil
eine Klasse keine Funktion oder Methode
ist mit denen sich Werte einlesen lassen. Wie man aber sieht, lassen sich mit
dem Konstruktor „constructor(str_einlesen:
string) { … }“ sehr wohl Daten in Form von Werten
oder eines Textstrings einlesen: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im Programm microbit_teil_02_prog_27.hex
und dem Quellkode microbit_teil_02_prog_27.js
sieht bzw. sich auch im Display anzeigen lassen kann, wird am Ende des Quelltextes nur der Text „Ende Quelltext!“ ausgeben. Was aber muss man im Konstruktor „constructor(str_einlesen:
string) { … }“ noch programmieren,
damit am Ende des Quelltextes die vollständige
Anzeige „Ende Quelltext! Konstrukt!“ ausgeben wird? Wie man im obenstehenden Screenshot sieht,
wurde beim Programm „microbit_teil_02_prog_27.hex“ zwar der Teststring „Konstrukt!“ im Kopf des Konstruktors „constructor(str_einlesen:
string) { … }“ ordnungsgemäß eingelesen und mittels
des Statements „basic.showString(str_einlesen)“ auch angezeigt, aber noch nicht an die
Klassenvariable showStringVar weitergegeben, sodass
sie sich demzufolge auch nicht im Statement
basic.showString("Ende
Quelltext!" + objektvar_starteKlasse.showStringVar)
anzeigen lässt! Wenn wir also erreichen wollen dass am Ende des Quelltextes die vollständige
Anzeige „Ende Quelltext! Konstrukt!“ ausgeben wird, dann
müssen wir den eingelesenen Variableninhalt
„Konstrukt!“ der Variablen „str_einlesen“ noch wie folgt an die
Klassenvariable „showStringVar“ weiterreichen: (Zum Vergrößern bitte
auf das Bild klicken!) Bei der
Zuweisung des Variableninhalts „Konstrukt!“ von der Variablen
„str_einlesen“ an die Klassenvariable
„this.showStringVar“ gilt es stets zu beachten, dass diese von rechts
nach links erfolgt
(siehe Programm microbit_teil_02_prog_28.hex
mit dem Quellkode microbit_teil_02_prog_28.js).
- Dabei lässt sich die zuvor genannte Zuweisung „this.showStringVar = str_einlesen“ auch direkt ins Statement „basic.showString(this.showStringVar = str_einlesen)“ übernehmen (siehe Programm
microbit_teil_02_prog_29.hex
mit dem Quellkode microbit_teil_02_prog_29.js):
(Zum Vergrößern bitte
auf das Bild klicken!) So, nun sind wir so weit, dass wir das
obenstehende Programm wieder vervollständigen können, indem wir die Funktion „starteFunktion(str_einlesen:
string)“ sowie die permanent im Hintergrund laufende Abfrage des Tasters A „basic.forever(() => { … }“ wieder ins Programm
einbauen: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Screenshot sieht,
wurde die Variable „str_einlesen“ im Kopf des Kontruktors „contructor(str_einlesen: string) { … } auf „lies_parameter_ein“ abgeändert, um
einem eventuellen Konflikt wegen Namensgleichheit aus dem Weg zu gehen. [ Video
10 ] Außerdem wurde der Quellkode für die Displayanzeige basic.clearScreen() basic.showString(this.showStringVar = str_einlesen) entfernt und durch das Statement this.showStringVar = lies_parameter_ein gleich am Anfang des Kontruktors „contructor(lies_parameter_ein: string) { … } ersetzt, um den eingelesenen Parameter „lies_parameter_ein“ mit dem Textstring „Konstruktor!“ an die Klassenvariable „showStringVar“ der Klasse „starteKlasse“ zu übergeben. Der Grund dafür ist der, dass der Textstring „Konstruktor!“ beim Klassenaufruf „var
objektvar_starteKlasse = new
starteKlasse("Konstrukt!")“ jetzt nur
noch ganz am Ende des Programms mittels des Statements basic.showString("Ende
Quelltext!" + objektvar_starteKlasse.showStringVar) angezeigt werden soll (siehe Programm microbit_teil_02_prog_30.hex
mit dem Quellkode microbit_teil_02_prog_30.js).
- Was jetzt noch fehlt, ist der Einbau der Methode „objektvar_starteMethode“ mit dem Statement var objektvar_starteMethode = function starteMethode(str_einlesen:
string) { … } Außerdem müssen wir noch die permanent im
Hintergrund laufende Abfrage des Tasters B „basic.forever(() => { … }“ wieder ins Programm
einbauen: (Zum Vergrößern bitte
auf das Bild klicken!) Mit dem Programm
microbit_teil_02_prog_31.hex
und dem Quellkode microbit_teil_02_prog_31.js
lässt sich das Ganze wie gewohnt ausprobieren und überprüfen. [ Video
11 ] 2.8 Die programmierte Klassengesellschaft
Obwohl wir bezüglich des Programmierens einer Klasse schon eine ganze Menge gelernt
haben und inzwischen z.B. wissen, dass sich in einer Klasse selbst wider Erwarten kein Quellkode, sondern stets
nur innerhalb eines Konstruktors
entwickeln lässt, wissen, dass eine Methode
nichts anderes als eine Funktion ist, die an eine Objektvariable gebunden ist und auch wissen, wie man Funktionen
und Methoden innerhalb eine Klasse menügesteuert aufruft, gibt es
dennoch ein paar Dinge, die es noch zu ergründen gilt. Starten Sie zu diesem Zweck das Programm microbit_teil_02_prog_32.hex
mit dem Quellkode microbit_teil_02_prog_32.js,
und finden Sie heraus, ob, wann und wie die Deklaration new starteKlasse_1("2.) Klasse 1 aufgerufen!") im Hauptprogramm
von diesem beim Starten des
Programms aufgerufen und ausgeführt wird! [ Video 12 ] Klären Sie diesbezüglich auch weshalb der Textstring „2. Klasse 1 - gestartet!“ beim Aufruf der Deklaration new starteKlasse_1("2.) Klasse 1 aufgerufen!") zwar mit übergeben und bei der Anzeige im Konstrukt „constructor(lies_parameter_ein: string)“ auch angezeigt wird, wider Erwarten aber nicht
in der Objektvariablen objektvar_starteKlasse_1.showStringVar abgespeichert wird: basic.showString("Ende Quelltext!" + objektvar_starteKlasse_1.showStringVar,
100) [ Video 13 ] Hier geht’s weiter zur Antwort
auf Frage 1 mit Video. - So, nun wissen wir, wie man eine Klasse deklariert, nämlich mit
dem Statement new starteKlasse_1("1.) Klasse 1 aufgerufen!")
und initialisiert, indem man diese der Objektvariablen var objektvar_starteKlasse_1 mit dem Statement
var objektvar_starteKlasse_1
= new starteKlasse_1("1.)
Klasse 1 aufgerufen!")
zu ordnet! Ferner wissen wir, dass sich das Konstrukt „constructor(lies_parameter_ein: string)“, das zur bereits deklarierten und
initialisierten Objektvariablen der Klasse gehört, jederzeit ein weiteres Mal im Programm durch das Statement new starteKlasse_1() aufrufen und ausführen lässt! - Wir machen uns diese Erkenntnis zu nutze und
programmieren eine weitere Klasse,
indem wir die Klasse „starteKlasse_1()“ einfach kopieren und
diese als Klasse „starteKlasse_2()“ benennen. Dies betrifft dann auch die Funktion „starteFunktion_2()“ und Methode
„objektvar_starteMethode_2“, die zwecks besserer
Unterscheidung ebenfalls umbenannt wurden, während die Namen der lokalen
Variablen der Einfachheit
halber unverändert beibehalten wurden. Jetzt wo es zwei, wenn auch
hauptsächlich nur namentlich unterschiedliche Klassen gibt, können wir uns
auch daran machen und im Hauptprogramm
eine entsprechende Menüauswahl programmieren. Da uns
aber im Prinzip bzw. wegen der einfachen Bedienbarkeit nur die beiden Taster A und B zur Verfügung stehen,
lässt sich mit dem Taster A das Untermenü der Klasse
„starteKlasse_1()“ und mit dem Taster B das Untermenü der Klasse „starteKlasse_2()“ aufrufen: (Zum Vergrößern bitte
auf das Bild klicken!) Da wir es jetzt im Programm microbit_teil_02_prog_33.hex mit
dem Quellkode microbit_teil_02_prog_33.js mit einem Hauptmenü und in den beiden Klassen jeweils mit
einem Untermenü zu tun haben, müssen
wir dafür sorgen, dass man jederzeit aus dem Untermenü zurück ins Hauptmenü springen kann. Zu diesem Zweck wurde der boole’sche Schalter
„menueswitch“ programmiert, sodass
man jederzeit durch Berühren des Sensors
„P0“ das Untermenü verlassen kann. Da der berührungsempfindliche Sensor „P0“
zum Verlassen des Untermenüs im Moment leider nur softwaremäßig,
d.h. im Browser funktioniert, wurde
das Ganze im Programm microbit_teil_02_prog_34.hex mit dem Quellkode microbit_teil_02_prog_34.js noch
für die Hardware, d.h. „micro:bit“-Rechner mittels des Tasters AB programmiert: (Zum Vergrößern bitte
auf das Bild klicken!) Erklären und begründen Sie, weshalb man im Hauptmenü des Hauptprogramms ebenfalls den Menüschalter mit der Variablen „menueswitch = false“ programmieren muss
(siehe roter Kosten im obenstehenden Bild). Hier geht’s weiter zur Antwort
zur Frage 2 mit Videos. - Wie bereits an anderer Stelle erwähnt, ist es
technisch nicht möglich, zwei Tasten wie z.B. die Taster A und B,
gleichzeitig zu drücken, da es zwischen beiden Tastendrücken immer einen winzig kleinen Zeitunterschied gibt und der Rechner
die Tastendrücke stets hintereinander
abfragt, wenn auch sehr schnell, sodass der Anwender nichts merkt. Spätestens beim „gleichzeitigen“ Tastendruck
auf die Tasten <Strg>, <Alt> & <Entf> zum Starten des Windows Taskmanagers
wird deutlich, dass nur ein gelenkiger Affe alle drei Tasten quasi
gleichzeitig drücken kann. Der kundige Windows-Anwender wird natürlich als
erstes die Steuerungstaste <Strg> drücken und
gedrückt halten! Zweitens die Alternativ-Taste <Alt> und
ebenfalls gedrückt halten und drittens auf die Entfern-Taste <Entf> drücken. Diese muss dann aber nur kurz
gedrückt werden, sodass sich dann sofort der Windows-Taskmanager startet.
Übrigens: Ab Windows 7/10 lässt sich mit dem Windows-Taskmanger leider nicht
mehr der Rechner zwangsweise runterfahren, falls sich mal ein Programm
aufgehängt hat oder der PC streikt. Da der kleine „micro:bit“-Rechner mit dem stromsparenden „ARM Cortex M0“-Prozessor nicht über die absolute Rechenleistung und
Rechengeschwindigkeit verfügt, schließlich kostet dieser ja nur so um die 15
Euro, muss man damit rechnen, dass dieser beim „gleichzeitigen“ Betätigen der
beiden Taster A&B nicht sofort
reagiert, weil er im Hintergrund erst noch eine laufende Anwendung abarbeiten
muss. In der Praxis hat sich diesbezüglich herausgestellt, dass es hilfreich
ist, wenn man die beiden Taster
A&B
in rückwärtiger Reihenfolge betätigt. Also erstens den Taster B drücken, gedrückt halten und zweitens
gleich darauf den Taster A drücken. Was aber auf jeden Fall
klappt, ist, wenn man die beiden Taster A&B in der beschriebenen Weise drückt und dann etwa zwei
bis drei Sekunden lang gedrückt hält. Schließlich gilt es zu bedenken, dass es sich
bei den beiden Untermenüs in den Klassen „startKlasse_1“ und „startKlasse_2“ um eine „while“-Schleife handelt und eben nicht
um die im Hintergrund laufende „forever“-Routine: (Zum Vergrößern bitte
auf das Bild klicken!) Wissen Sie, was ein Computerprogramm ist? >> Ein Computerprogramm oder kurz Programm ist eine den Regeln einer bestimmten Programmiersprache genügende Folge von Anweisungen (bestehend aus Deklarationen und Instruktionen), um bestimmte Funktionen bzw. Aufgaben oder Probleme mithilfe eines Computers zu bearbeiten oder zu lösen. ( … )Ein Computerprogramm gehört zur Software eines
Computers. Es liegt meist auf einem Datenträger als ausführbare Programmdatei, häufig im
sogenannten Maschinencode vor, die zur Ausführung in
den Arbeitsspeicher des Rechners geladen
wird. Das Programm wird als Abfolge von Maschinen-, d. h.
Prozessorbefehlen von dem oder den Prozessoren des Computers verarbeitet
und damit ausgeführt. Unter Computerprogramm wird auch der Quelltext des
Programms verstanden, aus dem im Verlauf der Softwareentwicklung der ausführbare Code
entsteht. Eine Programmdatei, die aus
Maschinencode besteht, enthält Befehle aus dem Sprachschatz des Prozessors,
d. h. Befehle, die für den Prozessor „verständlich“ und damit ausführbar
sind. Die Erstellung eines solchen Programms bezeichnet man allgemein als Programmierung oder
auch als Implementierung. In den Anfängen der
Programmierung wurde – bis zur Entwicklung von Programmiersprachen –
ausschließlich in Maschinencode programmiert. (Quelle: Wikipedia) Jetzt wissen Sie, dass der Anwender, der mit einem (Computer-) Programm arbeitet, nicht in
dieses, d.h. in das Kompilat
(= Übersetzung des Quellkode, engl. „source code“, in Maschinen
lesbaren Programmkode) schauen kann: (Zum Vergrößern bitte
auf das Bild klicken!) Aber da wir uns ja selbst als Programmierer
des „micro:bit“-Rechners betätigen, wissen wir natürlich, dass
sich nur der Quellkode eines Programms kompilieren, d.h. in
Maschinen lesbaren Kode des „ARM Cortex
M0“-Prozessors übersetzen lässt. Demzufolge ist also der
Programmierer/Softwareentwickler der geistige Urheber des Programms, liegen
die Rechte des geistigen Eigentums bei diesem. Das ist dann auch der Grund
dafür, weshalb man den Quellkode
nicht einfach so an Dritte aus der Hand gibt. Diese könnten nämlich den
Quellkode verändern, das Programm entsprechend erweitern und als ihr eigenes
geistiges Eigentum verkaufen oder selbst vermarkten. Aber selbst wenn der Anwender Einblick in den Quellkode des Programms bekäme, würde er
den Quellkode nur dann lesen
können, wenn er eine der geläufigen Hochsprachen der Programmierung wie z.B.
C/C++, Java, Python, PHP oder JavaScript beherrschen würde. Aber das Lesen
von Quellkode heißt nicht
automatisch, dass man das Gelesene auch versteht. Das betrifft dann z.B. auch
Entwickler, die später einmal den Quellkode
von Fehlern beseitigen oder diesen
um neue Funktionen erweitern
sollen, das Programm aber selbst nicht „geschrieben“ haben. Auch diese
müssen sich mühsam in den Spaghetti-Kode des Programms einlesen, diesen
studieren und ausprobieren, um zu wissen, wie das Programm denn so tickt.
Dabei können die Fehlerbeseitigung
und das Erweitern eines Programms extrem teuer werden, insbesondere dann,
wenn es zum Programm selbst keine vernünftige Dokumentation des Quellkodes
gibt! Weil aber der Anwender mit der Dokumentation
des Quellkodes logischerweise
nichts anfangen kann, bräuchte dieser eine entsprechende, selbsterklärende Bedienungsanleitung,
damit dieser das Programm sofort richtig anwenden und bedienen kann. Eine
Bedienungsanleitung ist also auch eine Art Dokumentation des Programms, nur
halt für den Anwender! Dabei besteht die Herausforderung beim kleinen
„micro:bit“-Rechner mit seinem einfachen „5 x 5 Matrix“-LED-Display darin, die Bedienung mittels der beiden Taster A und B
möglichst so zu programmieren, dass sich
dieser intuitiv bedienen
lässt. - Bedienungsanleitung zum Programm „microbit_teil_02_prog_34.hex“ 1. Kabelverbindung
herstellen Um mit
dem „micro:bit“-Rechner kommunizieren und das
gewünschte Programm auf den Rechner einspielen zu können,
muss man zunächst eine entsprechende Verbindung herstellen. Dabei ist es am
einfachsten, wenn man ein entsprechendes USB-Kabel
verwendet,
das mit seinem kleinen „USB-2.0-Micro-B-Stecker“
direkt an den „micro:bit“-Rechner zwecks
Stromversorgung
über USB
und
zum
Datenaustausch
angeschlossen
wird. Der
größere
„USB-2.0-Typ-A-Stecker“
am anderen Ende des Kabels wird an die USB-2.0-Buchse
des
heimischen Windows-PCs angesteckt. Sobald
das USB-Kabel
mit dem
Windows-PC
verbunden
wird, erkennt Windows
von sich
aus, dass ein USB-Gerät
angeschlossen
wurde, lädt im Hintergrund die entsprechenden Treiber und bindet das
USB-Gerät
automatisch
in das
Windows-Dateisystem ein, sodass man ab
sofort auf dieses zugreifen kann. ACHTUNG In das
Windows-Dateisystem eingebundene USB-Geräte wie
z.B. USB-Speichersticks, externe USB-Festplatten oder auch der
„micro:bit“-Rechner
als USB-Gerät müssen nach Gebrauch, d.h. beim
Beenden der Arbeit, unter Windows (oder auch Linux
oder Android) ordnungsgemäß manuell vom Windows-Dateisystem abgemeldet werden, da es
ansonsten beim spontanen Abziehen des USB-Kabels zum
Datenverlust kommen kann! - 2. Aufspielen des
Programms Damit
sich das für den „micro:bit“-Rechner entwickelte Programm auf diesem
nutzen lässt, muss es zuvor auf das
Dateisystem
des
Rechners aufgespielt werden. Dazu muss zuvor eine entsprechende
Verbindung
z.B. über
das USB-Kabel erfolgreich hergestellt worden sein! Nachdem
das gewünschte Programm in das Hauptverzeichnis
des
„micro:bit“-Dateisystems
aufgespielt,
d.h. kopiert wurde, kann es bis zu 20 Sekunden
dauern,
bis dieses vom Dateisystem in den
Arbeitsspeichers
des
„micro:bit“-Rechners
„geflasht“,
d.h. geladen wurde. Während des „Flashens“ (= Laden in den
Arbeitsspeicher) blickt die rückwärtige, gelbe
Status-LED des
„micro:bit“-Rechners.
Dabei darf die Datenverbindung und
Stromversorung des
„micro:bit“-Rechners nicht unterbrochen werden, da es ansonsten zu unvorhersehbarem Verhalten bis hin zur Zerstörung des Rechners kommen kann! 3. Starten und Ausführen
des Programms Das in den Arbeitsspeichers
des
„micro:bit“-Rechners
geflashte Programm wird vom
System automatisch gestartet und
ausgeführt! Wenn
bei dem in den Arbeitsspeicher geladenen Programm nichts anderweitiges
programmiert wurde, wie z.B. ein kleiner Begrüßungstext
als
Laufschrift auf dem „5 x 5 LED-Matrix“-Display,
dann bleibt das Display dunkel, sieht man nicht,
dass das geladene Programm
gestartet wurde! Dies ist auch der Fall, wenn die Laufschrift durchgelaufen ist! Im
vorliegenden Fall, d.h. beim Programm „microbit_teil_02_prog_34.hex“, verhält es
sich so, dass sich das herunter geladene und in den Arbeitsspeicher geflashte Programm nach etwa 20
Sekunden von allein meldet und im Display die programmierte Laufschrift „Start
...“ anzeigt. Nachdem
die Laufschrift durchgelaufen ist,
bleibt das Display zwar dunkel,
aber das Programm mit den zwei
Tastern A, B und A&B (als Kombination von A & B)
weiterhin aktiv. 4. Taster A zum Aufrufen des Untermenüs 1 Nach
dem selbständigen Programmstart befindet sich das Programm im Grundmodus bei dem die beiden Taster A, B und A&B fortwährend auf einen eventuellen Tastendruck hin abgefragt werden. Drückt
man nun auf den Taster A, so verzweigt
das Programm in das Untermenü 1 mit den beiden Auswahlmöglichkeiten „Menü 1A“ und „Menü 1B“. Dabei wird aber im Display
nur die Auswahlmöglichkeit „Menue 1A“ angezeigt. Wir
befinden uns nun im Untermenü 1. Im Untermenü 1 lässt sich mittels Tastendruck auf den
Taster A das Menü 1A und auf den Taster B das Menü 1B aufrufen, sodass im Display die Laufschrift „Menue 1A“ oder „Menue 1B“ angezeigt wird. Durch
den kombinierten Tastendruck
auf die beiden Taster
A&B
für die Zeitdauer von bis zu 5 Sekunden lässt sich das Untermenü 1 wieder verlassen. Dabei erscheint im Display die Laufschrift „exit …“, sodass man sich anschließend wieder im Grundmodus befindet. 5. Taster B zum Aufrufen des Untermenüs 2 Das
Programm befindet sich im Grundmodus bei dem die beiden Taster A, B und A&B fortwährend auf einen eventuellen Tastendruck hin abgefragt werden. Drückt
man nun auf den Taster B, so verzweigt
das Programm in das Untermenü 2 mit den beiden Auswahlmöglichkeiten „Menü 2A“ und „Menü 2B“. Dabei wird aber im Display
nur die Auswahlmöglichkeit „Menue 2B“ angezeigt. Wir
befinden uns nun im Untermenü 2. Im Untermenü 2 lässt sich mittels Tastendruck auf den
Taster A das Menü 2A und auf den Taster B das Menü 2B aufrufen, sodass im Display die Laufschrift „Menue 2A“ oder „Menue 2B“ angezeigt wird. Durch
den kombinierten Tastendruck
auf die beiden Taster
A&B
für die Zeitdauer von bis zu 5 Sekunden lässt sich das Untermenü 2 wieder verlassen. Dabei erscheint im Display die Laufschrift „exit …“, sodass man sich anschließend wieder im Grundmodus befindet. 6. Mit dem
Kombi-Tastendruck das Untermenü 1 oder 2
verlassen Durch
den kombinierten Tastendruck
auf die beiden Taster
A&B
für die Zeitdauer von bis zu 5 Sekunden lässt sich das Untermenü 1 oder 2
wieder verlassen. Dabei erscheint im Display
die Laufschrift „exit …“, sodass man sich
anschließend wieder im Grundmodus befindet. 7. Mit dem „Reset“-Taster alles wieder auf
Anfang setzen Auf der
Rückseite des „micro:bit“-Rechners befindet sich ein sogenannter
„Reset“-Taster mit dem sich der Rechner neu starten lässt. Dabei wird auch das zuvor in
den Arbeitsspeicher geflashte Programm
wieder neu gestartet, sodass sich dieses wieder im zuvor beschriebenen
Grundmodus befindet! - Hier geht’s dann weiter zum „micro:bit“-Programmieren, Teil 3“ |
|
|
[ Home ] [ zurück ] [ Seitenanfang ] [ Teil 1 ] [ Teil 3 ] |
|