Clonen eines Tabsheets zur Laufzeit und ansprechen der Komponenten



  • HI,

    kann mir einer verraten wie ich am einfachsten alle Controls die ein Tabhseet beinhaltet auf ein - zur Laufzeit erstelltes - neues Tabhsheet kopieren/clonen kann?

    Momentan gehe ich dvon aus das mir wohl nix anderes übrig bleiben wird und die Komponenten tatsächlich alle von Hand zu erstellen. Die Controls von TabsheetX werden derzeit noch durch einen Thread mit Daten gefüllt. Der Thread ruft eine Funktion im Formular auf (via Function Pointer) und schreibt die Daten ins Tabsheet. Muss ich aber dann ändern (siehe unten).

    Allerdings will ich das Programm umstricken damit man mehrere "Accounts" eintragen kann. Mein Forum hat 2 Tabsheets, das erste ist und wird statisch bleiben, das 2te jedoch will ich sozusagen "vererben / clonen".

    Ein Tabsheet repräsentiert sozusagen einen "Account". Für jeden Account läuft ein Thread der dann das jeweilige Tabsheet mit leben füllen soll. Da ich momentan eine (ebenfalls) statische Funktion habe, dachte ich mir ich mache einfach einen internen Zähler den ich für die Tabsheets als "ID" benutzen kann, damit ich weiss welches Tabsheet der ThreadX füllen muss.

    Wäre es sinnvoll die "Datenfüller-Funktion" weiterhin via Functionpointer aufzurufen oder reicht es, wenn ich dann einfach im Thread die Sync Funktion aufrufe? Letztendlich kommts aufs selbe raus würde ich sagen.

    Also die Verwaltung der Accounts sowie der Threads stellt mich nicht vor ein großes Problem, dass "clonen" des Tabsheets allerdings schon...

    Hat jemand einen Vorschlag wie ich das am einfachsten/effizientesten Lösen kann? Habe mich damit noch nie beschäftigt da ich das bis heute nicht benötigt habe.

    Danke!



  • Du kannst dir auch einmal ein Formular mit allen Controls erstellen, und das dann jeweils als Client auf das neue TabSheet setzen.

    grüssle 🙂



  • Smitty schrieb:

    Du kannst dir auch einmal ein Formular mit allen Controls erstellen, und das dann jeweils als Client auf das neue TabSheet setzen.

    Wie meinst du das?



  • na in etwa so:

    tSheet = new TTabSheet( PageControl1 );   // TabSheet
    		tSheet->DoubleBuffered = true;
    
    		tSheet->PageControl = PageControl1;
    		tSheet->Caption = "Title";
    		wsView = new TWorkSpaceView( tSheet );  // TWorkSpaceView = Formular( TForm ) mit den Edits, Labels, oder was sonst ...
    		wsView->Parent = tSheet;
    

    grüssle 🙂



  • hier bietet sich eher ein TFrame an, funktiniert im Prinzip wie TForm, allerdings ohne Rahmen und Systemmenü



  • Smitty schrieb:

    na in etwa so:

    tSheet = new TTabSheet( PageControl1 );   // TabSheet
    		tSheet->DoubleBuffered = true;
    
    		tSheet->PageControl = PageControl1;
    		tSheet->Caption = "Title";
    		wsView = new TWorkSpaceView( tSheet );  // TWorkSpaceView = Formular( TForm ) mit den Edits, Labels, oder was sonst ...
    		wsView->Parent = tSheet;
    

    grüssle 🙂

    Also gemäss dem Code sollte das Formular im Tabsheet erzeugt werden, passiert aber nichts 😞

    €dit1
    Mit dem Frame hats funktioniert.

    €dit2
    Also mit TFrame funzt das astrein! Aber ist das normal das dort das Oncreate nicht ausgeführt wird? 😕

    €dit3
    Zu schnell guckt, gibt gar kein OnCreate, naja hat man davon wenn man sich die Eigenschaften nicht anguckt und wie gewohnt einfach 'nen Doppelclick macht 😉

    €dit4

    Also mit TFrame ist das echt Klasse. Hab das noch nie benutzt und bin absolut begeistert 😃

    Danke an euch beide!



  • So, nun muss ich mal meinen eigenen Thread nochmal hoch holen.

    Aaalso, ich erzeuge zur Laufzeit eine Anzahl von x TabSheets dynamisch, dazu noch dann das Frame und übergebe ihm den Parent vom jeweiligen Tabsheet.

    Im Frame hab ich mir eine Membervariable gemacht wo ich den Counter vom Frame speichere - damit ich innerhalb dem Frame weiss welche "ID" es hat.

    Das Tabsheet und Frame hab ich mit dynamicarray deklariert.

    tSheet und FrameArray sind wie folgt deklariert:

    DynamicArray<TFrame1*>FrameArray;
    DynamicArray<TTabSheet*>tSheet;
    

    Im Fall vom Frame leite ich keine neue Klasse ab sondern benutz TFrame1 direkt. Erstellen vom Frame und Tabhseet mach ich so:

    tSheet.Length = framecounter+1;
    FrameArray.Length = tSheet.Length;
    
    tSheet[framecounter] = new TTabSheet(PageControl1);
    tSheet[framecounter]->PageControl = PageControl1;
    tSheet[framecounter]->Caption = "Unnamed: " + IntToStr(framecounter+1);
    tSheet[framecounter]->Name = "tSheetClient" + IntToStr(framecounter+1);
    PageControl1->ActivePage = tSheet[framecounter];
    
    FrameArray[framecounter] = new TFrame1(tSheet[framecounter]);
    FrameArray[framecounter]->Parent = tSheet[framecounter];
    FrameArray[framecounter]->Name = "ClientFrame" + IntToStr(framecounter+1);
    FrameArray[framecounter]->FrameID = framecounter;
    FrameArray[framecounter]->Align = alClient;
    FrameArray[framecounter]->MyOnCreate();
    
    framecounter++;
    

    Im MyOnCreate was ich beim Frame aufrufe, erzeuge ich eine Instanz meiner Klasse. Innerhalb der Klasse habe ich einen Funktionszeiger wo ich eine Memberfunktion vom Frame übergebe und genau hier liegt der Hund begraben:
    Die Memberfunktion hab ich als Static deklariert, d.h. das die Memberfunktion statisch ist und letztendlich nur einmal existiert, ganz gleich wieviele Frames ich erzeuge. Wenn ich ein weiteres Frame erzeuge funktioniert es (noch), wenn ich aber dann ein weiteres Frame erzeuge und eine Schaltfläche klicke die eine Funktion meiner Klasse aufruft (die Funktion selbst ruft dann den Methodenzeiger auf um das Ergebnis der Funktion der Memberfunktion vom Frame zu übergeben) werd mein Memo nicht mehr im momentanen Frame aktualisiert sondern im nächsten Frame.

    Das liegt daran das die Memberfunktion statisch ist.

    Da ist jetzt mein Problem... wie muss ich das den machen damit das funktioniert wie ich möchte? Wie ich gelesen habe, ist es normalerweise nicht erglaubt Methodenzeiger auf Klassenmember zeigen zu lassen, d.h. es ist eigentlich "illegal".

    Haken an der Sache ist, das ich momentan schlicht ergreifend feststecke.

    Wenn ich die Memberfunktion nicht als static deklariere, bekomme ich vom Compiler folgenden Fehler mit dem ich pers. nichts anfangen kann...

    [C++ Fehler] ClientFrame.cpp(331): E2034 Konvertierung von 'void (* (_closure )(unsigned char *,bool))(unsigned char *,bool)' nach 'void (*)(unsigned char *,bool)' nicht möglich
    

    Den Methodenzeiger in der Klasse hab ich so deklariert:

    void (*FuncPtrTest)(unsigned char *, bool);
    

    Das MyOnCreate sieht so aus:

    if (!MyClassTest) 
    {
    TMyClassTest *MyClassTest = new TMyClassTest();
    MyClassTest->FuncPtrTest = &this->WriteLogPacket;
    }
    

    Also eigentlich möchte ich nur meine Klassenfunktion aufrufen können da sie Daten verarbeitet und das Ergebnis dann die Memberfunktion im Frame übergeben soll. Eine Statische Funktion würde in dem Fall ja nicht funktionieren, da die Frame 2 ClientSockets beinhaltet und wenn die Sockets in mehreren Frames laufen kommen die sich ja dann in die Quere.

    Hat jemand eine Idee wie ich meinen bestehenden Ansatz anpassen muss (wegen dem static) damit es mit dem Methodenzeiger funktioniert, oder gibt es evtl. sogar eine einfachere Variante die sich mir von der Logik her noch nicht erschlossen hat?

    Das Problem ist letztendlich nur daran, das ich daran scheitere das ich die Daten an das jeweilige Frame übergeben kann.

    Wenn ich nur ein Tabsheet erzeuge funktioniert es ja - also so ganz falsch dürfte der Ansatz ja nicht unbedingt sein, vielleicht nicht sonderlich effizient, aber naja.

    Ich hoffe das es verständlich was ich meine.



  • Maverick schrieb:

    Hat jemand eine Idee wie ich meinen bestehenden Ansatz anpassen muss (wegen dem static) damit es mit dem Methodenzeiger funktioniert, oder gibt es evtl. sogar eine einfachere Variante die sich mir von der Logik her noch nicht erschlossen hat?

    Der Sprachstandard hat da wenig zu bieten. C++ kennt zwar Methodenzeiger, doch sind diese in polymorphen Klassenhierarchien nur von begrenzer Tauglichkeit (z.B. kannst du in einem Zeiger auf eine Methode einer Basisklasse keine Methode einer abgeleiteten Klasse zuweisen).
    Da diese Möglichkeit bei der Zuweisung von Events aber essentiell ist, bietet der C++Builder ein Sprachmittel namens Closures - das ja auch in deiner Fehlermeldung auftaucht.

    Deklariere das Closure so:

    void (__closure * FuncPtrTest)(unsigned char *, bool);
    

    Während ein Funktionszeiger nur eine Code-Adresse enthält, sind in einem Closure sowohl die Code-Adresse als auch die Objektreferenz - der this-Zeiger - untergebracht.



  • Thx @ audacia

    Aber ich hab den Wald vor lauter Bäumen nicht gesehen. Übergebe meiner Klasse nun einfach das Frame als Object.


Anmelden zum Antworten