Scripting-Hilfe: Zählvariablen

Ergänzung:

Das bisher gesagte ist alles ganz prima, wenn man die Objekte der Reihe nach abfrühstücken möchte. Will man zum Beispiel von fünf Buttons (BUTTON.1 bis BUTTON.5) einen nur einzigen (z. B. die Nummer 4) einschalten und alle anderen sollen ausgehen, dann könnte man das so lösen:

var
  i: integer

begin
  for i := 1 to 5 do
    begin
      ExecuteCommand('BUTTON.' + IntToStr(i) + ' OFF'); // Hier werden zunächst alle abgeschaltet.
    end;
  ExecuteCommand('BUTTON.4 ON');                        // Und hier der vierte eingeschaltet.
end.

Was aber, wenn mehrere bestimmte Buttons zugleich eingeschaltet werden sollen? Man könnte das mit einem Haufen if/then-Abfragen erledigen, aber dann wird der Code wieder sperrig. Für diesen Fall gibt es die case-Anweisung dieses Formats:

var
  k: integer;

begin

  case k of
   1:             // wenn k=1, dann …
    begin
                  // tu was
    end;
   2,3,4:         //wenn k=2 oder 3 oder 4, dann …
    begin
                  // tu auch was
    end;
   5..8:          // wenn k=5 oder 6 oder 7 oder 8, dann …
    begin
                  // tu wieder was
    end;
  else            // ansonsten … 
    begin
                  // tu was anderes
    end;
  end;            // und zum Abschluß ein end;

end;

Das else ist optional und, im Gegensatz zum else beim if/then, es steht davor ein Semikolon.

Wie können wir das jetzt nutzbringend verwerten?

In diesem Thread möchte @ELBE-Tom eine Reihe von Streams, aber immer anderer, aufschalten und dazu je ein Lämpchen (also einen Button) leuchten lassen. Eine Lösung dafür sieht so aus:

begin
  Encoder.GetConnections.GetItem(0).SetEnabled(false);
  ExecuteCommand('BUTTON.0 OFF');
  Encoder.GetConnections.GetItem(1).SetEnabled(true);
  ExecuteCommand('BUTTON.1 ON');
  Encoder.GetConnections.GetItem(2).SetEnabled(true);
  ExecuteCommand('BUTTON.2 OFF');
  Encoder.GetConnections.GetItem(3).SetEnabled(false);
  ExecuteCommand('BUTTON.3 OFF');
  Encoder.GetConnections.GetItem(4).SetEnabled(false);
  ExecuteCommand('BUTTON.4 OFF');
  Encoder.GetConnections.GetItem(5).SetEnabled(true);
  ExecuteCommand('BUTTON.5 ON');
  Encoder.GetConnections.GetItem(6).SetEnabled(false);
  ExecuteCommand('BUTTON.6 OFF');
  Encoder.GetConnections.GetItem(7).SetEnabled(false);
  ExecuteCommand('BUTTON.7 OFF');
  Encoder.GetConnections.GetItem(8).SetEnabled(true);
  ExecuteCommand('BUTTON.8 ON');
  Encoder.GetConnections.GetItem(9).SetEnabled(true);
  ExecuteCommand('BUTTON.9 ON');
  Encoder.GetConnections.GetItem(10).SetEnabled(true);
  ExecuteCommand('BUTTON.10 ON');
  Encoder.GetConnections.GetItem(11).SetEnabled(true);
  ExecuteCommand('BUTTON.11 ON');
  Encoder.GetConnections.GetItem(12).SetEnabled(true);
  ExecuteCommand('BUTTON.12 ON');
  Encoder.GetConnections.GetItem(13).SetEnabled(false);
  ExecuteCommand('BUTTON.13 OFF');
  Encoder.GetConnections.GetItem(14).SetEnabled(true);
  ExecuteCommand('BUTTON.14 ON');
  Encoder.GetConnections.GetItem(15).SetEnabled(false);
  ExecuteCommand('BUTTON.15 OFF');
end.

Das ist aber wieder so eine Lösung, die ich weiter oben als „doof“ bezeichnet habe, wegen der vielen Tipparbeit. Man bedenke, daß für jede gewünschte Kombination von aufzuschaltenden Streams ein solches Skript erstellt werden muß. Es ist auch ziemlich unübersichtlich. Eleganter geht es hiermit:

{
Zwischen die geschweiften Klammern kann der Spickzettel hin, z.B.:

1: SWR, 2: HR, 3: RIAS.
4: NDR, 5: RB; 6: ORF
usw.
}

const
  iMax = 15;          // Hier die maximale Senderanzahl minus 1 einsetzen.

var
  i: integer;
  Stream: array[0 .. iMax] of boolean;
  Button: array[0 .. iMax] of string;

begin
 for i := 0 to iMax do
  case i of
  1, 5, 8..12, 14 :   // Hier aufzuschaltende Sender durch Kommata getrennt eintragen.
    begin
      Stream[i] := true;
      Button[i] := ' ON';
    end;
  else
    begin
      Stream[i] := false;
      Button[i] := ' OFF';
    end;
  end;

for i := 0 to iMax do
  begin 
    Encoder.GetConnections.GetItem(i).SetEnabled(Stream[i]);
    ExecuteCommand('BUTTON.' + IntToStr(i) + Button[i]);
  end;

end.

Was passiert hier also? Ich versuche es mal aufzudröseln, ich wollte das Skript nicht mit zuvielen Kommentarzeilen verstopfen:

  • Zunächst: Kommentare kann man auch zwischen geschweiften Klammern {} schreiben, alles dazwischen wird ignoriert.

  • const iMax = 15;
    

    Hier wird eine Konstante definiert, d. h. eine Größe, die sich nie ändert. Hier iMax genannt, die maximale Anzahl der Sender (minus eins, da nullbasiert).

  • var
      i: integer;
      Stream: array[0 .. iMax] of boolean;
      Button: array[0 .. iMax] of string;
    

    Mit dem array wird praktisch ein Schränkchen mit einer Anzahl (nämlich iMax + 1) Schubladen aufgestellt, die zunächst freilich noch leer sind. Später kommen da Variablen, also Werte, rein. Die Schubladen sind durchnumeriert, und in jedes Schränkchen passen jeweils nur Werte eines bestimmten Typs. Hier einmal boolean, d. h. wahr/falsch-Werte und einmal string, das sind Buchstaben.

  • for i := 0 to iMax do
    

    Es wird nun jede Schublade von oben nach unten durchgezählt.

  • case i of
    1, 5, 8..12, 14 :
    

    Hier kommt jetzt dieses case ins Spiel: In diesem Beispiel werden wie oben die Streams 1, 5, 8, 9, 10, 11, 12 und 14 angesprochen (die sollen aufgeschaltet werden), die Streams 0, 2, 3, 4, 6, 7, 13 und 15 gehen leer aus. Sollen andere Streams aufgeschaltet werden, braucht man lediglich diese Zahlen zu verändern.

    Noch ein Trick: Fortlaufende Zahlen können zusammengefaßt werden, hier 8..12, das bedeutet also die Werte 8, 9, 10, 11 und 12.

  • Stream[i] := true;
    Button[i] := ' ON';
    

    Jetzt werden die Schubladen gefüllt, und zwar im Falle („case“) der oben genannten Streams 1, 5, 8, usw. Jeder Stream hat zwei Schubladen, eine im Schränkchen Stream, und eine im Schränkchen Button. Die jeweiligen Stream-Schubladen bekommen den Wert true eingelegt, in die Button-Schubladen kommt eine Zeichenkette, nämlich ' ON' (mit Apostrophen und Leerzeichen).

  • else
      begin
        Stream[i] := false;
        Button[i] := ' OFF';
      end;
    

    Alle anderen Schubladen werden mit false bzw. ' OFF' belegt.

  • Encoder.GetConnections.GetItem(i).SetEnabled(Stream[i]);
    

    Hier werden die Schubladen aufgemacht und die einzelnen Encoder (i) nacheinander mit dem Wert aus ihrem Schubfach (Stream[i]) versehen, also aufgeschaltet, wenn Stream[i] = true und umgekehrt.

  • ExecuteCommand('BUTTON.' + IntToStr(i) + Button[i]);
    

    Und hier wird einmal der Befehl BUTTON. mit der passenden Nummer versehen (IntToStr(i)) und dann der gewünschte Schaltzustand aus dem entsprechenden Schubkästchen geholt und angehängt.

Das sieht zunächst komplizierter aus als als das obige Skript, ist es tatsächlich aber, zumindest von der Anwendung her, nicht. Vielleicht kann der eine oder andere sich ja diese Beispiele zunutze machen und etwas für sich abzweigen.

@Torben: Sollte ich hier Unsinn posten, bitte schnell eingreifen!

Bestimmte Grüße

TSD