A
Offen gesagt finde ich das UI-Design fragwürdig. Wenn ich z.B. die Prioritäten 1 und 2 tauschen will, muß ich erst Combobox 2 auf einen völlig unbeteiligten Wert setzen, dann Combobox 1 auf den alten Wert von Combobox 2, schließlich Combobox 2 auf den alten von Combobox 1 - furchtbar umständlich.
Besser wäre es, wenn du z.B. die bereits belegten Einträge irgendwie markierst (durchgestrichen, ausgegraut oder ähnliches) und, sobald ein bereits belegter Eintrag ausgewählt wird, die Combobox-Werte einfach tauschst.
Zur Lösung könntest du dir etwa ein TComboBox-Derivat schreiben, das folgenden Ansatz etwas besser kapselt:
object ComboBox1: TComboBox
Left = 8
Top = 8
Width = 145
Height = 22
Style = csOwnerDrawFixed
ItemHeight = 16
TabOrder = 0
OnDrawItem = ComboBoxDrawItem
OnSelect = ComboBoxSelect
end
object ComboBox2: TComboBox
Left = 8
Top = 40
Width = 145
Height = 22
Style = csOwnerDrawFixed
ItemHeight = 16
TabOrder = 1
OnDrawItem = ComboBoxDrawItem
OnSelect = ComboBoxSelect
end
object ComboBox3: TComboBox
Left = 8
Top = 72
Width = 145
Height = 22
Style = csOwnerDrawFixed
ItemHeight = 16
TabOrder = 2
OnDrawItem = ComboBoxDrawItem
OnSelect = ComboBoxSelect
end
// MyUnit.h
#include <vector>
#include <utility>
class TForm1 : public TForm
{
...
private: // Anwender-Deklarationen
struct MutualExclusiveEntry
{
String name;
TCustomCombo* control;
MutualExclusiveEntry (String _name)
: name (_name), control (0)
{}
};
std::vector <MutualExclusiveEntry> FComboBoxEntries;
...
};
// MyUnit.cpp
#include <StrUtils.hpp>
...
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
// Das hier wäre natürlich im wirklich wahren Leben etwas dynamischer.
FComboBoxEntries.push_back (MutualExclusiveEntry ("Grau"));
FComboBoxEntries.push_back (MutualExclusiveEntry ("Grüngrau ins Bräunliche"));
FComboBoxEntries.push_back (MutualExclusiveEntry ("Braungrau mit Grün"));
FComboBoxEntries.push_back (MutualExclusiveEntry ("Braungrüngrau"));
FComboBoxEntries.push_back (MutualExclusiveEntry ("Grünlich-blaues Braunrotgrau"));
// HACK - das sollte besser über eine eigene Komponente gelöst werden!
ComboBox1->Items->Text = DupeString ("\n", FComboBoxEntries.size ());
ComboBox2->Items->Text = DupeString ("\n", FComboBoxEntries.size ());
ComboBox3->Items->Text = DupeString ("\n", FComboBoxEntries.size ());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBoxDrawItem(TWinControl *Control, int Index,
TRect &Rect, TOwnerDrawState State)
{
TCustomCombo* comboBox = static_cast <TCustomCombo*> (Control);
if (FComboBoxEntries[Index].control != 0 // Item bereits belegt
&& FComboBoxEntries[Index].control != Control) // ... und nicht von uns
comboBox->Canvas->Font->Color = clGrayText;
comboBox->Canvas->FillRect (Rect);
comboBox->Canvas->TextOut (Rect.Left + 1, Rect.Top + 1, FComboBoxEntries[Index].name);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBoxSelect(TObject *Sender)
{
TCustomCombo* comboBox = static_cast <TCustomCombo*> (Sender);
TCustomCombo*& controlRef = FComboBoxEntries[comboBox->ItemIndex].control;
if (comboBox->Tag > 0)
FComboBoxEntries[comboBox->Tag - 1].control = controlRef;
if (controlRef != 0 && controlRef != comboBox)
{
controlRef->ItemIndex = comboBox->Tag - 1; // Einträge tauschen
controlRef->Tag = comboBox->Tag;
}
controlRef = comboBox;
// HACK: wir mißbrauchen TComponent::Tag zum Speichern des zuvor
// gewählten Indexeintrages + 1 (+ 1, weil es mit 0 initialisiert wird).
// Auch das gehört für eine saubere Lösung in eine eigene Komponente.
comboBox->Tag = comboBox->ItemIndex + 1;
}