Frame ändern bei Klick auf Eintrag in TreeView



  • Ich habe mich nun mal mit Frames beschäftigt und hoffe, dass sie für mein Vorhaben geeignet sind. Ich habe eine TreeView mit mehreren Einträgen und Untereinträgen. Wenn ich auf eines der Untereinträge klicke, soll immer ein anderer Frame in der Form angezeigt werden.
    Habs mal versucht:

    void __fastcall TfrmMain::TreeView1Click(TObject *Sender)
    {
       if (TreeView1->Selected != 0) {
          if (TreeView1->Selected->Text == "Eintrag1") {
             //hier soll der Frame zur laufzeit geladen werden
          }
       }
    }
    


  • und was genau funktioniert jetzt nicht? bzw. wobei brauchst du Hilfe?



  • an der kommentierten Stelle müsste der Frame geladen werden. Wie kann ich den Frame zuweisen? Wenn ich einen Frame über die Komponentenleiste auf die Form ziehe muss ich ja auch den Frame zuweisen.

    void __fastcall TfrmMain::TreeView1Click(TObject *Sender)
    {
       if (TreeView1->Selected != 0) {
          if (TreeView1->Selected->Text == "Element1") {
             TFrame* fra = new TFrame(this);
             fra->Parent = this;
             fra->Color = clRed;
             fra->Left = 150;
             fra->Top = 20;
          }
       }
    }
    


  • Du musst doch hier nur statt TFrame deinen konkreten Frame instanziieren. TFrame ist doch nur die Basisklasse dafür.



  • Also so?

    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
       if (TreeView1->Selected != 0) {
          if (TreeView1->Selected->Text == "A") {
             TFrame* fra = fraElement1;
             fra->Parent = this;
             fra->Left = 150;
             fra->Top = 50;
             fra->Visible = true;
          }
       }
    

    }
    Code läuft fehlerfrei durch. Leider passiert nix wenn ich den Eintrag A auswähle.



  • nein

    dein Frame ist wirklich noch mit TFrame benannt?
    mal als Beispiel: ein neues Frames

    class TMyFrame : public TFrame
    

    dann folgt daraus:

    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
       if (TreeView1->Selected != 0) {
          if (TreeView1->Selected->Text == "A") {
             TMyFrame * fra = new TMyFrame(this); // <-- hier muß deine Frameinstanz erzeugt werden !!
             fra->Parent = this;
             fra->Left = 150;
             fra->Top = 50;
             fra->Visible = true;
          }
       }
    


  • ja ok, das funktioniert. Wenn ich auf den 1. Eintrag klicke wird in der Form der Frame angezeigt. Beim Klick auf den 2. Eintrag erscheint auch der 2. Frame.
    Wenn ich dann aber ein zweites Mal auf den 1. oder 2. Eintrag im Treeview klicke, kommt ein EKomponentError, dass die Komponente bereits existiert.



  • Hast du den gleichen Code wie bei Linnea?
    Setzt du einen Namen für dein Frame?
    Solltest du den alten Frame nicht erstmal entfernen bevor du einen neuen einfügst?



  • hier mein Code:

    void __fastcall TForm1::TreeView1Click(TObject *Sender)
    {
       if (TreeView1->Selected != 0) {
          if (TreeView1->Selected->Text == "A") {
             TfraElement1* fraElement1 = new TfraElement1(this);
             fraElement1->Parent = this;
             fraElement1->Left = 150;
             fraElement1->Top = 50;
             fraElement1->Visible = true;
          }
          if (TreeView1->Selected->Text == "B") {
             TfraElement2* fraElement2 = new TfraElement2(this);
             fraElement2->Parent = this;
             fraElement2->Left = 150;
             fraElement2->Top = 50;
             fraElement2->Visible = true;
          }
       }
    }
    

    Die beiden Frames hab ich über "Datei-->NeuerFrame" angelegt und gespeichert. Hier der Code von frameElement1.h:

    class TfraElement1 : public TFrame
    {
    __published:	// Von der IDE verwaltete Komponenten
       TButton *Button1;
       TButton *Button2;
       TButton *Button3;
    private:	// Anwender-Deklarationen
    public:		// Anwender-Deklarationen
       __fastcall TfraElement1(TComponent* Owner);
    };
    


  • Warum willst du eigentlich die Frames immer wieder neu erzeugen?
    Du könntest doch Zeiger auf deine Frames als Member deiner Form speichern, so dass du einfach darauf zugreifen kannst.



  • ja ok, das seh ich ein. Ich muss nur wenn ich das Element1 ein zweites Mal anklicke, das Element 2 unsichtbar machen, da es sonst vom 2. Frame überdeckt wird. Aber so funktioniert es.

    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
       TTreeView *TreeView1;
       void __fastcall TreeView1Click(TObject *Sender);
    private:	// Anwender-Deklarationen
       TfraElement1* frameElement1;
       TfraElement2* frameElement2;
    public:		// Anwender-Deklarationen
       __fastcall TForm1(TComponent* Owner);
    };
    
    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
       fraElement1 = new TfraElement1(this);
       fraElement2 = new TfraElement2(this);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::TreeView1Click(TObject *Sender)
    {
       if (TreeView1->Selected != 0) {
          if (TreeView1->Selected->Text == "A") {
             fraElement1->Parent = this;
             fraElement1->Left = 150;
             fraElement1->Top = 50;
             fraElement1->Visible = true;
             fraElement2->Visible = false;
          }
          if (TreeView1->Selected->Text == "B") {
             fraElement2->Parent = this;
             fraElement2->Left = 150;
             fraElement2->Top = 50;
             fraElement2->Visible = true;
             fraElement1->Visible = false;
          }
       }
    }
    

    Da ich in meinem Programm ca. 40 Frames habe, die über den TreeView nach oben gezeigter Methode umgeschaltet werden, muss ich in jeder if-Schleife alle anderen 39 Frames mit Visible = false unsichtbar machen. Das wird dann ja ein sehr langer Code. Wie kann ich das besser machen bzw gibts eine effizientere Methode?



  • Hallo

    Erstell ein zusätzliches Array von deines Frames (Siehe FAQ, dynamische Arrays von Komponenten), dann kannst du die Frames mit Indexen ansprechend und die "Schaltlogik" verallgemeinern.

    bis bald
    akari



  • die Frames haben doch aber immer einen anderen Typ TfraElement1*, TfraElement2*, usw. Die Elemente in einem DynamicArray müssen doch den gleichen Typ haben.



  • Hallo

    Aber bei der Zusammenarbeit mit deinem TreeView benutzt du auch nur die Eigenschaften eines TFrames. Also kann dein Container die Basisklasse TFrame verwenden, um Parent, Left, Top oder Visibke anzusprechen. Und du kannst trotzdem Zeiger auf beliebige von TFrame abgeleitete Instanzen in den Container legen.

    Erst wenn du über TFrame weiter hinausgehende Gemeinsamkeiten nutzen willst, mußt du dann zusätzliche Lösungen finden, wie zum Beispiel eine eigene polymorphe Basisklasse als Interface.

    bis bald
    akari



  • class TForm1 : public TForm
    {
    __published:    // Von der IDE verwaltete Komponenten
       TTreeView *TreeView1;
       void __fastcall TreeView1Click(TObject *Sender);
    private:    // Anwender-Deklarationen
        TfraElement1* frameElement1;
        TfraElement2* frameElement2;
        //usw. bis fraElement40;
        int numFrames;
        DynamicArray<TFrame*>aFrames; //Deklaration des dyn. Arrays für die Frames
    public:        // Anwender-Deklarationen
       __fastcall TForm1(TComponent* Owner);
    };
    
    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner),
         numFrames(40)
    {
        fraElement1 = new TfraElement1(this);
        fraElement2 = new TfraElement2(this);
         //usw. bis fraElement40;
    
        aFrames.Length = numFrames;
        for (int i=0; i<aFrames.Length; i++) {
            aFrames[i] = new TFrame(this);
            aFrames[i].Parent = this;
            aFrames[i].Left = 150;
            aFrames[i].Top = 50;
        }
    }
    

    Nun muss ich aber doch meine erzeugten Frames irgendwie noch in das Array legen. Die sind immer anders bezeichnet. Element1, Element2 usw war nur beispielhaft. Wie mach ich das?



  • Du brauchst doch hier nur das Array. Lass die separaten Membervariablen weg und belege dein Array mit den konkreten Klassen.
    etwa so

    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner),
         numFrames(40)
    {
        aFrames[1] = new TfraElement1(this);
        aFrames[1]->Parent = this;
        aFrames[1]->Left = 150;
        aFrames[1]->Top = 50;    
        aFrames[2] = new TfraElement2(this);
         //usw. bis fraElement40;
    
    // das hier ist Unsinn, weg damit
        //aFrames.Length = numFrames;
        //for (int i=0; i<aFrames.Length; i++) {
        //    aFrames[i] = new TFrame(this);
        //    aFrames[i].Parent = this;
        //    aFrames[i].Left = 150;
        //    aFrames[i].Top = 50;
        //}
    }
    

    Ich würde statt dem DynamicArray lieber std::vector nehmen, aber das ist wohl Geschmackssache.


Log in to reply