Wenn ich es richtig verstehe, geht es hier nicht um das Mischen von Bildschirmfarben, sondern um das Zuordnen von Farbnamen für bestimmte Mischungen einer Reihe von Grundfarben.
Ich versuche es mal etwas ausführlicher:
Du hast eine bestimmte Anzahl von Grundfarben.
Du möchtest jeder Farbmischung (d.h. jeder Kombination dieser Grundfarben) einen Namen geben.
Dein Ansatz war es, jeder Grundfarbe eine CheckBox zuzuordnen und die Namen der (Misch-)farben dann mit if-then-else zu bestimmen. Das ist ein direkter Ansatz und völlig in Ordnung, wenn man wenige (z.B. 2) Grundfarben hat. Bei 4 Grundfarben gibt es aber bereits 16 Kombinationen - und da wird die if-then-else Abfrage doch
etwas unübersichtlich.
Was mschnell dir nun geraten hat, ist dies: Benutze Bits!
Das Rechnen mit Bits stammt zwar aus der Computer-Steinzeit, aber auch heute ist es recht nützlich zu wissen, wie es geht (und wenn du jemals etwas Systemnahes programmieren möchtest, dann
musst du jedes Bit beim Vornamen kennen).
Ziel ist es, am Ende den Namen der (Misch-)Farbe möglichst einfach ermitteln zu können. Am besten wäre es, wir hätten für jede Farbmischung einen eindeutigen Integer-Wert, den wir dann als Index eines Arrays benutzen könnten. Also etwa
Code: Alles auswählen
var
Farbname: array [1..n] of string = ('Farbe1', 'Farbe2', ...);
...
Label1.Caption := Farbname[Farbmischung];
Die Frage ist also diese: wie berechnen wir den Wert für Farbmischung so, dass wir ihn wie oben gezeigt verwenden können?
Die Antwort: wir ordnen jeder Grundfarbe (also jeder CheckBox) ein Bit zu:
Code: Alles auswählen
CheckBox Bit (Binär) Wert als Integer
1 00000001 1
2 00000010 2
3 00000100 4
4 00001000 8
5 00010000 16
Mischen tun wir die Grundfarben dann, indem wir ihre Werte (Bits) bitweise mit Oder verbinden. Pascal hat keinen extra-Operator für bitweises Oder, sondern nutzt - wie in Booleschen Ausdrücken - ebenfalls "or" (in C++ ist das z.B. anders, dort gibt es "||" für Boolesche Ausdrücke und "|" für bitweises Rechnen).
Wenn du jetzt einen Wert wie (binär) 00010101 hast, dann kannst du sofort sehen, dass er eine Mischung der ersten, dritten und fünften Grundfarbe repräsentiert (das Bit für die erste Grundfarbe steht ganz rechts). Und du hast auch sofort einen Integerwert, den du als Array-Index benutzen kannst, nämlich 1 + 4 + 16 = 21.
Fragt sich, wie du aus der Nummer der Checkbox schnell das zugehörige Bit berechnen kannst. Schau dir die Binärdarstellung der Bits nochmal an: die 1 wandert jedesmal eine Stelle nach links. Und genau das ist es, was der Operator shl macht: er verschiebt den Wert x um n Stellen nach links. Also:
Da wir für die erste Checkbox die Eins nicht verschieben müssen, arbeiten wir mit (Nummer_der_CheckBox - 1). 1 shl n entspricht übrigens 2 hoch n, du arbeitest hier also mit Zweierpotenzen.
Nächstes Problem: Woher bekommen wir die Nummer der Checkbox?
Viele Wege führen nach Rom. Am flexibelsten ist es, ein Checkbox-Array anzulegen (der Index der Checkbox in diesem Array ist ihre Nummer) und die Checkboxen dann zur Laufzeit zu erzeugen:
Code: Alles auswählen
const
Grundfarben = 4;
type
TForm1 = class(TForm)
Label1: TLabel;
procedure FormCreate(Sender: TObject);
public
Checkboxen: array [1..Grundfarben] of TCheckBox;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
for i := 1 to Grundfarben do
begin
Checkboxen[i] := TCheckBox.Create(self);
with Checkboxen[i] do
begin
Caption := '...';
Width := ...;
Height := ...;
Left := ...;
Top := ...;
...
end;
end;
...
end;
Dies hat einen Hauptvorteil: Flexibilität. Und einen Hauptnachteil: du siehst die Checkboxen erst, wenn das Programm läuft. Im Lazarus Formular-Designer bleiben sie unsichtbar und du kannst sie nicht beschriften, positionieren, usw. Darum würde ich, wenn die Anzahl der Grundfarben feststeht, eher einen anderen Weg gehen:
Bau dein Formular ganz normal auf und lass Lazarus die Namen der Checkboxen automatisch vergeben. Du erhältst dann CheckBox1, CheckBox2, CheckBox3, usw. - deine Checkboxen haben also eine Nummer im Namen. Und diese Nummer benutzen wir, mit Hilfe der Methode FindComponent:
Code: Alles auswählen
GesuchteCheckbox := FindComponent('CheckBox' + IntToStr(Nummer_der_Checkbox));
Zuletzt bleibt noch die Frage, wie du das Array mit den Farbnamen aufbauen musst. Zunächsteinmal, wie groß muss es sein? Naja, du hast 2 hoch n Möglichkeiten, n Grundfarben zu mischen. Und wie wir 2 hoch n berechnen, wissen wir ja schon (shl). Wir fangen das Array bei Null an, denn auch "keine Grundfarbe" ist eine mögliche Farbmischung. Also:
Code: Alles auswählen
const
Grundfarben = 4;
Farbname: array [0..(1 shl Grundfarben)-1] of string = (
'Keine Farbe', // 0000
'Grundfarbe 1', // 0001
'Grundfarbe 2', // 0010
'Mischfarbe (2+1)', // 0011
'Grundfarbe 3', // 0100
'Mischfarbe (3+1)', // 0101
'Mischfarbe (3+2)', // 0110
'Mischfarbe (3+2+1)', // 0111
'Grundfarbe 4', // 1000
'Mischfarbe (4+1)', // 1001
'Mischfarbe (4+2)', // 1010
'Mischfarbe (4+2+1)', // 1011
'Mischfarbe (4+3)', // 1100
'Mischfarbe (4+3+1)', // 1101
'Mischfarbe (4+3+2)', // 1110
'Mischfarbe (4+3+2+1)'); // 1111
Zuletzt noch - als Beispiel - eine Funktion, die den Namen der Mischfarbe liefert:
Code: Alles auswählen
function TForm1.BerechneFarbnamen: string;
var
i: Integer;
Mischfarbe: Integer;
begin
Farbwert := 0;
for i := 1 to Grundfarben do
if (FindComponent('CheckBox' + IntToStr(i)) as TCheckBox).Checked then
Farbwert := Farbwert or (1 shl (i-1));
Result := Farbname[Farbwert];
end;
PS: alles ungetestet und ohne Gewähr