Mit einem Knopf etwas an- und ausschalten?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

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();
  }
}

Forenfrager438  27.04.2021, 14:38

Leider kommt an der Stelle

lampe[i].istAn()

Dann immer eine Fehlermeldung:

Cannot find symbol
0
regex9  27.04.2021, 14:46
@Forenfrager438

Die istAn-Methode musst du dir natürlich selbst schreiben, wenn es noch keine solche gibt, die den Lampenzustand liefert.

0
Forenfrager438  27.04.2021, 14:52
@regex9

Wie sieht die dann aus?

Kommt die dann zu Lampe, wo auch setzeFarbe usw. ist?

0
regex9  27.04.2021, 16:09
@Forenfrager1802

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.

0
Forenfrager1802 
Fragesteller
 27.04.2021, 18:22
@regex9

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();
 
            }
          }
0
regex9  27.04.2021, 23:45
@Forenfrager1802

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.

0
Forenfrager1802 
Fragesteller
 30.04.2021, 19:12
@regex9

Kann man nicht einfach nur den An Knopf programmieren, ohne irgendwas dazu zu erfinden? Weil sonst check ich das einfach nicht.

0
Forenfrager438  30.04.2021, 19:21
@regex9

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. :/

0
regex9  30.04.2021, 21:07
@Forenfrager1802

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.

0
Forenfrager1802 
Fragesteller
 03.05.2021, 17:20
@regex9

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

0
regex9  04.05.2021, 01:58
@Forenfrager1802

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 ...
}
0
regex9  04.05.2021, 02:15
@Forenfrager1802

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).

0