TabSheet klonen respektive Write- / ReadComponent



  • Hallo zusammen,

    ich habe gerade folgendes Problem:

    Ich versuche den Inhalt eines TabSheets zu klonen. So weit so gut. Mit den Funktionen Write- und ReadComponent bekomme ich bis dato nur eine Komponente ohne ihre Child-Elemente kopiert. 😞
    Ich möchte jedoch die auf dem TabSheet vorhandenen Komponenten mit dem TabSheet (der die Elternkomponente darstellt) zusammen kopieren und als neuen TabSheet einfügen.

    TMemoryStream *CloneStream = new TMemoryStream();
    for(int i=1; i < 5; i++)
                    {
                        RegisterClass(__classid(TTabSheet));
                        CloneStream->WriteComponent(TabSheet1); // Der erste TabSheet, der immer wieder geklont werden soll
                        CloneStream->Seek(0, soFromBeginning);
                        TTabSheet *Tab = new TTabSheet(PageCtrl);
                        Tab = (TTabSheet*) CloneStream->ReadComponent(NULL);
                        Tab->Name = "Tab" + IntToStr(i);
                        Tab->PageControl = PageCtrl;
                        Tab->Parent = PageCtrl;
                        Tab->Caption = "Tab" + IntToStr(i);
                    }
    

    Den obigen Code habe ich schonmal mit Panels ausprobiert und die Panels selber werden auch hübsch geklont, aber ihre Kindelement nicht.

    Laut der Hilfe sollten doch alle Kindelemente inklusive sein, oder?!

    Hat jemand eine Idee, woran das liegen kann? Bin für jede Hilfe dankbar, hab vllt. einfach nur Tomaten auf den Augen.

    Vielen Dank schonmal!
    Yoshi

    P.S.: Ja, die vorhandenen Threads dazu habe ich mir bereits angeschaut, aber die helfen mir bei meinem Problem leider nicht.



  • Das nervt!
    Ich hab jetzt zumindest rausgefunden, dass beim Schreiben einer TForm die Kind-Elemente mit in den Stream wandern, was sie bei einem Panel oder TabSheet nicht tun. Das rührt offensichtlich daher, dass die Komponente (die in den Stream geschrieben wird) nicht Parent der darin enthaltenen Komponenten sein muss, sondern Owner.
    Kann mir das einer erklären? Der Spass wird doch auch intern in der IDE verwendet, wenn man Controls per Copy 'n Paste irgendwo einfügt, richtig? Wird das dann einfach rekursiv auf die markierten Komponenten angewandt oder wie?
    Ich versteh nicht so wirklich, was das soll...

    Es gibt in den Google-Groups auch Beispiele dazu, aber (neben der Tatsache, dass die Beiträge oft ziemlich alt sind) funktioniert nicht ein einziges Beispiel bei mir.
    Hat das denn hier noch niemand gemacht / versucht?



  • Lass das mit dem Read/WriteComponent besser und bau dir dein TabSheet selber zusammen. Das ist zwar ein viel größerer Aufwand, beschert dir aber weit weniger Probleme.



  • Braunstein schrieb:

    Das ist zwar ein viel größerer Aufwand, beschert dir aber weit weniger Probleme.

    Ja, wem sagst du das! 😞

    Nichst desto trotz habe ich das jetzt mehr oder weniger mit 'ner rekursiven Funktion gelöst.
    Falls jemand mal das gleiche Problem hat:

    Aufruf z.B.:
        MyPanel = new TPanel(Owner);
        MyPanel  = (TPanel*)CloneComponent(Panel1, Form1, Form1);
        MyPanel->Visible = true; // Witzigerweise sind einige Komponenten nach dem Clonen nicht mehr sichtbar
    
    TComponent* CloneComponent(TComponent *Component, TComponent *Owner, TComponent *Parent)
    {
    	TMemoryStream *MemStream = new TMemoryStream();
            TComponent *ResComp = new TComponent(Owner);
    
            RegisterClass(Component->ClassType());
    
    	MemStream->WriteComponent(Component);
            MemStream->Seek(0, soFromBeginning);
            ResComp = MemStream->ReadComponent(NULL);
    
            if(Component->InheritsFrom(__classid(TControl)))
            	((TControl*)ResComp)->Parent = ((TWinControl*)Parent);
    
            if (Component->InheritsFrom(__classid(TWinControl)) && ((TWinControl*)ResComp)->ControlStyle.Contains(csAcceptsControls))
          	{
          		for(int i = 0; i < ((TWinControl*)Component)->ControlCount; i++)
          		{
             		TControl *ChildControl = ((TWinControl*)Component)->Controls[i];
             		if (ChildControl->Owner == Component->Owner)
                            {
              			if(CloneComponent(ChildControl,Owner,ResComp) == NULL)
                                    	break;
                            }
          		}
          	}
            MemStream->Free();
            return ResComp;
    }
    

    Gruß



  • Hallo,
    nochmal ein kurzes "reopen" des Threads.

    Mir schwirrt die ganze Zeit ein Frage im Kopf rum auf die ich keine vernünftige Antwort finde:

    Die Funktion aus meinem letzten Post funktioniert, aber warum meckert er nicht bzgl. der Namen der Komponenten? 😕
    Wenn ich mir das im Debugger anschaue haben die geklonten Komponenten den selben Namen wie die Originalkomponenten. Ich kann die geklonte Komponenten auch z.B. über FindChildControl mit dem Namen der Originalkomponente ansprechen...

    Das begreife ich nicht. Hat jemand eine Erklärung dafür?

    Schonmal danke!



  • Who clones goes to hell! 🙄
    Ich musste mittlerweile die durchaus unangenehme Erfahrung machen, das ein solches Klonen von verschachtelten Komponenten unangenehm und fehleranfällig ist...

    Mein größtes Problem ist, dass meine Komponente in der CloneComponent-Funktion bei der Erstellung einen Owner bekommt (siehe Code oben), nach dem ReadComponent ist der Owner allerdings = NULL! Das ist vermutlich der Grund, warum er nicht wegen Namenskonflikten meckert. Allerdings ist das wohl auch ein Speicherleck-Alptraum.
    Zudem kann ich nicht auf die untergeordneten Komponenten zugreifen, weil FindComponent() nicht mehr zieht 😞

    Stand noch nie jemand vor diesem Problem und hat es vernünftig gelöst?



  • __yoshi schrieb:

    Ich versuche den Inhalt eines TabSheets zu klonen.

    Vielleicht wäre TFrame hier eine Option?


Anmelden zum Antworten