CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Tworzenie dynamiczne komponentów o nieznanej jeszcze liczbie
Strona 1 z 1

Tworzenie dynamiczne komponentów o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 01:34
przez bosch_1980
Witam

Zastanawiam się jak stworzyć dynamicznie komponenty np TLabel analogicznie do:

KOD cpp:     UKRYJ  
TLabel *label[10]; // w tym przypadku 10 komponentow

for(int i = 0; i < 10; i++) label[i] = new TLabel (this);
 


lecz w nieznanej podczas kompilacji ilości ??

Bardzo dziękuję za pomoc
Michał

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 11:24
przez polymorphism
Możesz użyć np. vectora:

KOD cpp:     UKRYJ  
#include <vector>
...

std::vector<TLabel*> label;

for(int i = 0; i < 10; i++)
    label.push_back(new TLabel(this));

Dostęp do elementów masz taki sam jak w zwykłej tablicy.

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 11:31
przez bosch_1980
Witaj polymorphism

Dzięki za odpowiedź. Twój sposób jest ok i właśnie tak zrobiłem - to jedyny sposób jaki udało mi się wymyślić w celu przechowywania wskaźnika do poszczególnych elementów TLabel, jednak chciałbym zrobić to klasycznie z pomocą tablic. Ale po wielu próbach zastanawiam się czy jest to możliwe :(

Pozdrawiam Michał

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 11:51
przez Cyfrowy Baron
Miałem ten sam pomysł, jednak chcę go bardziej rozwinąć:

plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
#include <vector>
// ..............
private:
        std::vector<TLabel *> LabelList;


plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  int x = 1;
  do
  {

   LabelList.push_back( new TLabel(this) ) ;
   std::vector<TLabel *>::iterator itLabel = LabelList.begin() + (x - 1);

   String lName = "Label" + (String)x;

   (*itLabel)->Name = lName;
   TLabel *tmpLabel = dynamic_cast<TLabel *>( FindComponent(lName) );
   tmpLabel->Parent = this;

   tmpLabel->Left = 8;
   tmpLabel->Top  = 16 * x;

   x++;
  }while(x < 5);
}


Teraz pozostaje kwestia podłączenia zdarzeń do tych obiektów. Podłączę jedno zdarzenie OnClick do wszystkich obiektów, ale kliknięcie na jeden z nich wyświetli komunikat o tym, który obiekt został kliknięty. Dla urozmaicenia zdarzenie będzie podłączane do obiektów nie podczas ich tworzenia, ale po kliknięciu na drugi przycisk. Wcześniej jednak trzeba utworzyć funkcję, która będzie zdarzeniem.
plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
private:
        std::vector<TLabel *> LabelList;
        void __fastcall LabelListClick(TObject *Sender);


plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
void __fastcall TForm1::LabelListClick(TObject *Sender)
{
 String lName = dynamic_cast<TLabel *>(Sender)->Name;

 ShowMessage("Kliknięto w obiekt: '" + lName + "'.");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{

 std::vector<TLabel *>::iterator itLabel = LabelList.begin();

 for(; itLabel < LabelList.end(); itLabel++)
 {

  TLabel *tmpLabel = dynamic_cast<TLabel *>((*itLabel));
  tmpLabel->OnClick = LabelListClick;

 }
}
//---------------------------------------------------------------------------


Trochę tutaj namieszałem, gdyż tworząc obiekty typu TLabel odwoływałem się do nich poprzez nazwę, którą wcześniej przypisałem do iteratora:

KOD cpp:     UKRYJ  
   String lName = "Label" + (String)x;
   (*itLabel)->Name = lName;
   TLabel *tmpLabel = dynamic_cast<TLabel *>( FindComponent(lName) );
   tmpLabel->Parent = this;


a przypisując im zdarzenie użyłem iteratora:

KOD cpp:     UKRYJ  
  TLabel *tmpLabel = dynamic_cast<TLabel *>((*itLabel));


By nie powtarzać kodu posłużyłem się dodatkowo rzutowaniem na tmpLabel. W pierwszym przypadku mogłem równie dobrze zamiast nazwy użyć iteratora, co więcej można im od razu przypisać zdarzenie:

KOD cpp:     UKRYJ  
  int x = 1;
  do
  {

   LabelList.push_back( new TLabel(this) ) ;
   std::vector<TLabel *>::iterator itLabel = LabelList.begin() + (x - 1);

   String lName = "Label" + (String)x;

  // (*itLabel)->Name = lName;
   TLabel *tmpLabel = dynamic_cast<TLabel *>( (*itLabel) );//( FindComponent(lName) );
   tmpLabel->Name = lName;
   tmpLabel->OnClick = LabelListClick;
   tmpLabel->Parent = this;

   tmpLabel->Left = 8;
   tmpLabel->Top  = 16 * x;

   x++;
  }while(x < 5);


Można też zrezygnować z rzutowania na tmpLabel i posłużyć się iteratorem:

KOD cpp:     UKRYJ  
  int x = 1;
  do
  {

   LabelList.push_back( new TLabel(this) ) ;
   std::vector<TLabel *>::iterator itLabel = LabelList.begin() + (x - 1);

   String lName = "Label" + (String)x;

   (*itLabel)->Name = lName;
   (*itLabel)->OnClick = LabelListClick;
   (*itLabel)->Parent = this;

   (*itLabel)->Left = 8;
   (*itLabel)->Top  = 16 * x;

   x++;
  }while(x < 5);


Pozostaje jeszcze kwestia niszczenia obiektów i czyszczenia tablicy:

KOD cpp:     UKRYJ  
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
 std::vector<TLabel *>::iterator itLabel = LabelList.begin();

 for(; itLabel < LabelList.end(); itLabel++) delete *itLabel;

 // na koniec czyszczę listę
 LabelList.clear();
}

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 11:55
przez polymorphism
Ale po wielu próbach zastanawiam się czy jest to możliwe

Możliwe to to jest, przecież vector tak robi. Pytanie tylko, po co się tak bawić?

Ale jeśli już musisz, masz tu algorytm powiększania tablicy:

  1. tworzysz tablicę B o jeden element większą od A (mam nadzieję, że wiesz, jak się tworzy tablice dynamiczne)
  2. przepisujesz wszystkie elementy z tablicy A do B
  3. ostatniemu elementowi tablicy B przypisujesz wartość, którą dodajesz - to samo, co vector::push_back.
  4. usuwasz tablicę A. B jest teraz tą właściwą tablicą (tablicą A z punktu pierwszego).

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:03
przez Cyfrowy Baron
Moja odpowiedź jest niekompletna, więc ją jeszcze uzupełnię. Pozostaje jeszcze kwestia odwoływania się do obiektów tworzonych dynamicznie za pomocą tablicy vector. Można to zrobić na dwa sposoby.

Pierwszy z wykorzystaniem vector i iterator:

KOD cpp:     UKRYJ  
void __fastcall TForm1::Button4Click(TObject *Sender)
{

  std::vector<TLabel *>::iterator itLabel = LabelList.begin() + 2;

  (*itLabel)->Caption = "jakiś nowy tekst";

 // lub prościej
  LabelList.at(2)->Caption = "jakiś tekst";

}
Drugi z wykorzystaniem polimorfizmu i funkcji szukającej komponentu:

KOD cpp:     UKRYJ  
void __fastcall TForm1::Button5Click(TObject *Sender)
{
  dynamic_cast<TLabel *>( FindComponent("Label3") )->Caption = "jakiś nowy tekst";
}

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:07
przez polymorphism
KOD cpp:     UKRYJ  
int x = 1;
do
{
    ...
    std::vector<TLabel *>::iterator itLabel = LabelList.begin() + (x - 1);
    ...

Jak chcesz mieć dostęp przez indeks, to po prostu użyj operatora [], czyli:
KOD cpp:     UKRYJ  
TLabel *tmpLabel = LabelList[x - 1]; // rzutowanie jest niepotrzebne

Nie wiem, dlaczego ten x jest liczony od jednego, przecież w C\C++\Javie\C#\i innych indeksuje się od zera. Jeśli chodzi o odwołanie się do ostatniego elementu, można jeszcze tak:
KOD cpp:     UKRYJ  
TLabel *tmpLabel = LabelList.back();

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:08
przez bosch_1980
Dzięki za szybką reakcję

Ja zrobiłem to tak i działą, ale dalej szukam rozwiązania w tablicach :)

KOD cpp:     UKRYJ  
deque<TLabel*> label;
for(int i=0; i<10; i++)
{
        label.push_back(new TLabel(this));
}

for(unsigned int i=0; i<label.size(); i++)
{

        label.at(i)->Parent = ImageScrollBox;
        label.at(i)->Top = i*39+adjust;
        label.at(i)->Left = 1;
        itd.

}

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:13
przez Cyfrowy Baron
Nie wiem, dlaczego ten x jest liczony od jednego, przecież w C\C++\Javie\C#\i innych indeksuje się od zera. Jeśli chodzi o odwołanie się do ostatniego elementu, można jeszcze tak:

Bo najpierw obmyśliłem to trochę inaczej, ale w trakcie pisania kodu zmieniłem, a x jak zapewne zauważyłeś służy również do nadawania nazwy obiektom, a chciałem żeby miały nazwę zaczynającą się od 1. Kod byłby oczywiście bardziej przejrzysty, gdyby x nadał wartość 0, gdyż inrementować o -1 mogę równie dobrze przy nadawaniu nazwy.



Do bosh_1980: używaj tagów, albo dostaniesz ostrzeżenie.

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:14
przez polymorphism
(...) ale dalej szukam rozwiązania w tablicach

No ale w czym problem, przecież dostałeś opis jak to zrobić na tablicach? No i dlaczego koniecznie tablice?

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:25
przez Cyfrowy Baron
KOD cpp:     UKRYJ  
deque<TLabel*> label;
for(int i=0; i<10; i++)
{
        label.push_back(new TLabel(this));
}

for(unsigned int i=0; i<label.size(); i++)
{

        label.at(i)->Parent = ImageScrollBox;
        label.at(i)->Top = i*39+adjust;
        label.at(i)->Left = 1;
        itd.

}


Dlaczego sądzisz że deque jest lepsze od vector:


Include the STL standard header <deque> to define the container template class deque and several supporting templates.

Include the STL standard header <vector> to define the container template class vector and several supporting templates.




Na czym według Ciebie polega różnica?



Dlaczego używasz drugiej pętli, skoro wszystko możesz zrobić w jednej. Dodatkowa pętla to dodatkowe opóźnienie. Musisz nadawać obiektom nazwy, jeżeli chcesz mieć do nich łatwy dostęp. Jeżeli tego nie zrobisz nie będziesz mógł odwoływać się poprzez nazwę. Poza tym obiekty powinny mieć nazwę, bez wygląda to jakoś... dziwnie. :oops:

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postNapisane: sobota, 13 listopada 2010, 12:28
przez bosch_1980
polymorphism, Cyfrowy Baron - jeszcze raz dzięki za pomoc

Zabrałem się do tego w celu pomocy z problemem znajomemu, który zaintrygował mnie troszeczkę problemem. Koniecznie chciał by problem rozwiązać na tablicach.
Jednak nie widzę tutaj prostszego rozwiązania niż użycie kontenerów, zresztą nie mam już siły na kombinowanie.

polymorphism - dzięki za pomoc

Cyfrowy Baron - dzięki za podanie tak wielu możliwości zastosowanie kontenerów do rozwiązania tego problemu. Wiele z nich będzie dla mnie pomocnych w innych zastosowaniach.

Dziękuję i pozdrawiam Michał

Zastosowałem deque, ponieważ wcześniej miałem dołączoną #include<deque.h>, więc chyba z próżności.

Zrobiłem to w dwóch pętlach by wytłumaczyć koledze przykład.