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

Tworzenie dynamiczne komponentów o nieznanej jeszcze liczbie

dział ogólny

Tworzenie dynamiczne komponentów o nieznanej jeszcze liczbie

Nowy postprzez bosch_1980 » sobota, 13 listopada 2010, 01:34

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ł
Avatar użytkownika
bosch_1980
Bladawiec
Bladawiec
 
Posty: 4
Dołączył(a): środa, 22 września 2010, 11:46
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: brak kompilatora
Gadu Gadu: 0
    Windows 7Chrome

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez polymorphism » sobota, 13 listopada 2010, 11:24

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.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez bosch_1980 » sobota, 13 listopada 2010, 11:31

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ł
Avatar użytkownika
bosch_1980
Bladawiec
Bladawiec
 
Posty: 4
Dołączył(a): środa, 22 września 2010, 11:46
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: brak kompilatora
Gadu Gadu: 0
    Windows 7Chrome

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez Cyfrowy Baron » sobota, 13 listopada 2010, 11:51

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();
}
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez polymorphism » sobota, 13 listopada 2010, 11:55

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).
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez Cyfrowy Baron » sobota, 13 listopada 2010, 12:03

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";
}
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez polymorphism » sobota, 13 listopada 2010, 12:07

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();
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez bosch_1980 » sobota, 13 listopada 2010, 12:08

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.

}
Avatar użytkownika
bosch_1980
Bladawiec
Bladawiec
 
Posty: 4
Dołączył(a): środa, 22 września 2010, 11:46
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: brak kompilatora
Gadu Gadu: 0
    Windows 7Chrome

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez Cyfrowy Baron » sobota, 13 listopada 2010, 12:13

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.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez polymorphism » sobota, 13 listopada 2010, 12:14

(...) 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?
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez Cyfrowy Baron » sobota, 13 listopada 2010, 12:25

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:
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Tworzenie dynamiczne komponentow o nieznanej jeszcze liczbie

Nowy postprzez bosch_1980 » sobota, 13 listopada 2010, 12:28

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.
Avatar użytkownika
bosch_1980
Bladawiec
Bladawiec
 
Posty: 4
Dołączył(a): środa, 22 września 2010, 11:46
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: brak kompilatora
Gadu Gadu: 0
    Windows 7Chrome


Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 53 gości

cron