Witam,
mam trzy comboboxy, która mają być wypełnione tymi samymi danymi czy jest możliwości ich odwołanie do jednej wspólnej listy typu tstringlist. Czy muszę aktualizować tą samą listę dla każdego komponentu?
Oczywiście
//var lista:TSringList;
ComboBox1.Items.Assing(lista);
ComboBox2.Items.Assing(lista);
ComboBox2.Items.Assing(lista);
No właśnie chodzi mi o to, żeby tego nie robić. Żeby aktualizować wyłącznie listę a nie każdy combobox osobno.
Obrazowo:
Na starcie przypisuje listę do comboboxow
ComboBox1.Items.Assing(lista);
ComboBox2.Items.Assing(lista);
ComboBox3.Items.Assing(lista);
dodaję do listy element
lista.Items.Add('NewItem');
i chciałbym aby ta zmiana było widoczna we wszystkich comboboxach bez robienia kolejny raz
ComboBox1.Items.Assing(lista);
ComboBox2.Items.Assing(lista);
ComboBox3.Items.Assing(lista);
Tu raczej kariery nie zrobisz jedynie co to można by obsługiwać zdarzenie OnChange TStringList więc coś takiego:
private
{ Private declarations }
ls: TStringList;
procedure ListaOnChange(Sender: TObject);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ListaOnChange(Sender: TObject);
begin
ComboBox1.Items.Assign(ls);
ComboBox2.Items.Assign(ls);
ComboBox3.Items.Assign(ls);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ls:= TStringList.Create;
ls.OnChange:= ListaOnChange;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ls.Free;
end;
Gdyby był sposób aby zamiast obiektu przypisać miejsce w pamięci do comboboxa to może by to zadziałało, ale albo nie ma takiej możliwość albo ( co jest akurat pewnikiem ) moja wiedza na ten temat jest zbyt mała. W każdym razie dziękuję wszystkim za pomoc.
Masz błąd w stopce; pełny cytat brzmi mniej-więcej tak:
Są tylko dwie rzeczy nieskończone wszechświat i ludzka głupota, chociaż co do pierwszego nie jestem pewien. ~Albert Einstein
.
A cd.tego, to bez stworzenia własnej kontroli się nie obejdzie.
Fragment kodu TCustomComboBox (TComboBox dziedziczy po TCustomComboBox):
TCustomComboBox = class(TCustomCombo)
private
{ ... }
FItems: TStringList;
TCustomCombo:
TCustomCombo = class(TCustomListControl)
public
property Items: TStrings read FItems write SetItems;
end;
No i kod procedury SetItems:
procedure TCustomCombo.SetItems(const Value: TStrings);
begin
if Assigned(FItems) then
FItems.Assign(Value)
else
FItems := Value;
end;
Jeżeli byłoby samo przypisanie:
FItems := Value
Wtedy Value
oraz FItems
wskazywałyby na to samo miejsce w pamięci i to o czym mówisz byłoby możliwe.
Edit: jak widać, przypisanie jest także, gdy FItems
jest równe nil.
Niestety, nie można wykonać Assign(nil)
; gdyby było to możliwe, można by zrobić obj.Assign(nil); obj.Assign(stringlist)
i FItems
wskazywałoby na stringlist
, ale podczas wykonania Assign(nil)
otrzymamy wyjątek Cannot assign nil to ...
.
procedure TCustomCombo.SetItems(const Value: TStrings);
begin
if Assigned(FItems) then
FItems.Assign(Value)
else
FItems := Value;
end;
Jak zwykle LCL/VCL usiłuje być mądrzejsze niż użytkownik. O ile w przypadku newbie powoduje to ułatwienie to w przypadku zaawansowanych konstrukcji już tak łatwo nie ma (por. Java i porównywanie stringów).
FItems := Value
Tja, przy okazji tracimy referencję do FItems które może być zainicjalizowane.
Najlepiej chyba zrobić swój obiekt dziedziczący z TStringList tak żeby miał listę ComboBox do zmiany i przy każdej zmianie zmieniał również wartości w tych ComboBox. W przypadku małej liczby zmian nie powinno być dużych utrat prędkości.
Patryk27 napisał(a):
Niestety, nie można wykonać
Assign(nil)
; gdyby było to możliwe, można by zrobićobj.Assign(nil); obj.Assign(stringlist)
iFItems
wskazywałoby nastringlist
, ale podczas wykonaniaAssign(nil)
otrzymamy wyjątekCannot assign nil to ...
.
Przecież Assign to konstruktor kopiujący, tak? Więc jaki sens ma wysyłanie mu nil? I czemu uważasz że danie obj.Assign(stringlist);
spowoduje ustawienie FItems na stringlist. Mi się wydaje że to spowoduje ustawienie FItems na kopię stringlist. Jak gdzieś mam błąd w myśleniu to poprawcie, ekspertem z LCL nie jestem.
Zrobię to na razie w sposób prosty a później spróbuje bardziej finezyjne rozwiązania
//-----------------------------------------------------------------------------
// Lista ClientBoxow; Clients : List<TAdvComboBox>
procedure TDTM.AddClient(var Client: TAdvComboBox );
begin
self.Clients.Add( Client );
end;
//-----------------------------------------------------------------------------
// Synchronizacja klientów w ComboBoxach;
procedure TDTM.SyncClient( ListClients : TStringList );
var i : integer;
begin
for i := 0 to self.Clients.Count - 1 do
self.Clients[i].Items.Assign( ListClients );
end;
//-----------------------------------------------------------------------------
```delphi