Mit einem Knopf etwas an- und ausschalten?
Moin zusammen,
ich habe seit einiger Zeit das Problem, dass ich mit meinem Knopf nur die Lichterkette anschalten kann. Doch ich möchte, dass ich die Lichterkette mit dem selben Knopf auch ausschalten kann.
Hat jemand eine Lösung für mich, wie ich dieses Problem lösen kann?
Hier der Pastebin-Link: https://pastebin.com/3jCz0A7P
1 Antwort
Auffällig ist, dass du den Zustand der Lampen dauernd wieder auf false setzt.
for (i = 0; i < 10; i++) {
lampe[i].setzeAn(false);
und ziemlich oft über alle Lampen iterierst. Würde es nicht ausreichen, den Lampenzustand nur dann zu ändern, wenn ein Button gedrückt wird? Bei dem derzeitigen Zustand könnte ich mir gut vorstellen, dass du sich Anwendungsfälle gegenseitig ausschalten.
Den aktuellen Zustand der Lampe jedenfalls kannst du bestimmt auch mit einer Methode (wie z.B. istAn, u.ä.) holen. So würde nur ein if-Block für die Zustandsänderung der Lampe ausreichen.
if (kAn.wurdeGedrueckt()) {
for (i = 0; i < 10; i++) {
boolean istAn = lampe[i].istAn();
lampe[i].setzeAn(!istAn);
lampe[i].zeigeLampe();
}
}
Die istAn-Methode musst du dir natürlich selbst schreiben, wenn es noch keine solche gibt, die den Lampenzustand liefert.
Ist das so richtig?
Hier noch der link zur Klasse Lampe der Lichterkette:https://pastebin.com/ArjYXc2P
public void istAn(boolean pIstAn) {
this.istAn = pIstAn;
}
Hattet ihr noch keine Getter-Methoden / return im Unterricht? Die Definition müsste so aussehen:
public boolean istAn() {
return this.istAn;
}
Die Methode gibt via return-Befehl den Wert von istAn zurück an den Aufrufer. So wird er hier also:
boolean istAn = lampe[i].istAn();
in der Variable istAn gespeichert.
Die Lampenklasse schau ich mir frühestens heute Abend an.
Jetzt hab ich das mit return dazugeschrieben, doch die Lampen lassen sich immernoch nicht ausschalten. Hab leider kein Plan mit dem Knopf :(
Das ist jetzt in der Klasse Lampe
public void istAn(boolean pIstAn) {
this.istAn = pIstAn;
}
public boolean istAn() {
return this.istAn;
}
und das in der Klasse Lichterkette.
if (kAn.wurdeGedrueckt()) {
for (i=0;i<10;i++) {
boolean istAn = lampe[i].istAn();
lampe[i].setzeAn(!istAn);
lampe[i].zeigeLampe();
}
}
Es verhält sich so, wie ich es schon geahnt habe. Du überschreibst deine Änderungen selbst wieder durch deine unnötige Schleife. Außerdem hast du, dass muss ich ehrlich sagen, bei der zeigeLampe-Methode irgendwie nicht nachgedacht.
Also: Ich gehe folgend von dem Zustand der beiden pastebin-Codes aus.
public void zeigeLampe() {
stift.normal();
if (an) {
stift.setzeFuellMuster(Muster.GEFUELLT);
stift.setzeFarbe(farbe);
stift.kreis(xPosition, yPosition, groesse);
}
else {
loescheLampe();
}
}
Das Feld an speichert deinen Lampenzustand bereits. Wenn es angeschaltet wurde, wird der Kreis gezeichnet. Ansonsten kann die loescheLampe-Methode aufgerufen werden, die den Kreis wieder überzeichnet / ausradiert.
Das Feld:
private boolean istAn;
fliegt wieder raus, da es ja sonst doppelt ist. Die Methode istAn gibt den Feldwert von an zurück:
public boolean istAn() {
return an;
}
Die fuehreAus-Methode wird, wie schon angedeutet, entschlackt. Folgend zeige ich nur den relevanten Code + Struktur.
while (true) {
Hilfe.kurzePause();
if (kAn.wurdeGedrueckt()) {
for (int i = 0; i < lampen.length; i++) {
lampen[i].setzeAn(!lampen[i].istAn());
lampen[i].zeigeLampe();
}
}
if (kRot.wurdeGedrueckt()) {
// ...
}
if (kGrün.wurdeGedrueckt()) {
// ...
}
if (kBlau.wurdeGedrueckt()) {
// ...
}
if (kFarbwechsel.wurdeGedrueckt()) {
// ...
}
if (kEnde.wurdeGedrueckt()) {
// ...
}
if (kAbbrechen.wurdeGedrueckt()) {
// ...
}
}
Beachte, dass die Variable i herausgeflogen ist. Stattdessen sollte jede Schleife ihre eigene lokale Zählervariable anlegen. Auch die hartkodierte 10 sollte raus. Wenn du einmal die Anzahl an Lampen ändern möchtest, brauchst das nämlich nur noch an einer Stelle tun und nicht nachträglich x-Stellen im Code aktualisieren.
Sinnigerweise würde ich das Array in lampen umbenennen. Es beinhaltet immerhin mehrere.
Damit die Lampen anfangs auch weiß gezeichnet werden, sollte initial (wenn du deine Lampen das erste Mal erstellst) die Farbe gesetzt werden.
lampe[i] = new Lampe();
lampe[i].setzeFarbe(Farbe.rgb(255, 255, 255));
// ...
lampe[i].setzeAn(false); // <<< raus
lampe[i].zeigeLampe(); // <<< raus
Die beiden letzten Aufrufe können übrigens ebenso raus. Du zeichnest die Lampen doch eh erst, wenn man sie anschaltet.
Anschließend könnte man das Programm sicherlich noch an anderen Stellen verkürzen, doch das überlasse ich dir.
Kann man nicht einfach nur den An Knopf programmieren, ohne irgendwas dazu zu erfinden? Weil sonst check ich das einfach nicht.
Die komplette Klasse Lampe und ein großer Teil von Lichterkette wurden so bom Lehrer vorgegeben.
Wenn wir dann was hinzufügen sollen, werden wir ins kalte Wasser geworfen, ohne das jemals besprochen zu haben.
Deswegen leider unsere Unbeholfenheit und unsere fehlende Ahnung, wie wir was du sagts verstehen sollen. :/
Es wurde nichts dazu erfunden, was im Code nicht eh schon genutzt werden würde. Es sind keine neuen sprachlichen Mittel o.ä.. Stattdessen habe ich den Code mit meinem Lösungsvorschlag vereinfacht. Nun lässt sich erst wieder durchblicken, was wann, wo passiert, da sich Abläufe nicht gegenseitig wieder überschreiben. Das Problem deines Programms war rein logischer Natur.
Zu dem Lampenzustand: Um eine Lampe ein-/ausschalten zu können, musst du stets ihren Zustand kennen / einfordern können. Denn dann lässt er sich auch negieren / umdrehen. Daher gibt es die Variable an.
Die Negation übernimmt diese Zeile:
lampen[i].setzeAn(!lampen[i].istAn());
Aufgesplittet:
boolean aktuellerZustad = lampen[i].istAn(); // holen
boolean neuerZustand = !aktuellerZustand; // umdrehen
lampen[i].setzeAn(neuerZustand); // setzen
Wenn du grundsätzliche Fragen zu den vorgegebenen Elementen von deinem Lehrer hast (zu den Bestandteilen der Klasse Lampe beispielsweise - Methoden, Variablen, ...), dann frage ruhig.
Ich hab jetzt leider noch ein Problem. Unser Lehrer meinte, dass wir auch noch einen Knopf programmieren sollen, der die Farben der einzelnen Lampen zufällig wechselt. Das hab ich auch hinbekommen, doch ich fands ein bisschen langweilig, wenn die Farbe nur gewechselt wird, wenn man den Knopf drückt. Das heißt ich hab eine while-Schleife programmiert, doch ich bekomm es nicht hin, dass wenn man einen anderen Knopf drückt (z.b.: kBlau), das die while-Schleife verlassen wird. Wüsstest du vielleicht was ich da rein schreiben kann, dass die while-Schleife verlassen wird, wenn ich einen anderen Knopf drücke?
Hier noch der pastebin-Link: https://pastebin.com/BEdveg2w
Du müsstest innerhalb der Schleife nochmals den Knopfdruck für jeden einzelnen Button prüfen. Anders kommst du da mit der Schleife nicht heraus.
Es geht aber viel einfacher. Du kannst dir eine boolsche Variable anlegen, die sich merkt, dass der Button für den ständigen Farbwechsel gedrückt wurde. So lange diese boolsche Variable dann wahr ist, werden pro Schleifenlauf zufällige Farben für die Lampen generiert.
Random wuerfel = new Random();
boolean farbwechsel = false;
while (true) {
Hilfe.kurzePause();
if (farbwechsel) {
for (int i = 0; i < 10; i++) {
int rot = wuerfel.nextInt(256);
int gruen = wuerfel.nextInt(256);
int blau = wuerfel.nextInt(256);
lampen[i].setzeFarbe(Farbe.rgb(rot, gruen, blau));
lampen[i].zeigeLampe();
}
}
// check other buttons (kRot, kGrün, etc.) ...
if (kFarbwechsel.wurdeGedrueckt()) {
farbwechsel = true;
}
// ...
}
Die wuerfel-Variable würde ich außerhalb der Schleife anlegen. Du brauchst nur ein einziges Objekt. Innerhalb der Schleifen würdest du hingegen mit jedem Schleifenlauf ein neues Random-Objekt erzeugen und somit Speicherplatz verscherbeln.
Des Weiteren könnte man noch die Bedingung für den Farbwechsel etwas anpassen:
if (farbwechsel && lampen.length > 0 && lampen[0].istAn()) {
// ...
Wenn die Lampen aus sind, braucht man ja keine Zufallsfarben erzeugen, geschweige denn die Lampen überhaupt zeichnen. Da bisher alle Lampen stets gleichzeitig an- und ausgeschaltet werden, reicht es für die Prüfung, sich (sofern es denn Lampen gibt) eine beliebige Lampe herauszusuchen und zu schauen, ob diese an oder aus ist.
Damit der Farbwechsel bei Klick auf die anderen Buttons wieder aufhört, musst du die boolsche Variable wieder auf false setzen.
Beispiel für den roten Button:
if (kRot.wurdeGedrueckt()) {
farbwechsel = false;
// other code ...
}
Jedes Lampenobjekt besitzt ein Attribut an, welches sich merkt, ob die Lampe selbst gerade an ist (true) oder nicht (false). Um den Wert dieses Attributs zu bekommen, wurde die istAn-Methode geschrieben. Um den Wert des Attributs zu ändern, gibt es die setzeAn-Methode.
Bei Klick auf den An-/Aus-Button wird nun lediglich je Lampenobjekt geschaut, ob es Licht spendet oder nicht und dementsprechend reagiert. Wenn die Lampe bereits an ist (true), wird sie auf false gesetzt. Ist sie noch nicht an, auf true. Es ist wie bei einem ganz normalen Lichtschalter.
Man könnte es auch so (in längerer Form als im Snippet meines letzten Kommentars) schreiben:
Lampe aktuelleLampe = lampen[i];
boolean aktuellerZustand = aktuelleLampe.istAn();
if (aktuellerZustand == true) {
aktuelleLampe.setzeAn(false); // ausschalten
}
else {
aktuelleLampe.setzeAn(true); // anschalten
}
Später, wenn die zeigeLampe-Methode aufgerufen wird, orientiert diese sich an dem Zustand des an-Attributs. Entweder zeichnet sie daraufhin einen Kreis mit der aktuellen Lampenfarbe oder sie ruft die loescheLampe-Methode auf, die im Grunde ebenso einen Kreis zeichnet, allerdings mit der Farbe des Fensterhintergrundes (= radieren).
Leider kommt an der Stelle
Dann immer eine Fehlermeldung: