IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++Builder Discussion :

[Débutant] Classe dérivée de TTabSheet & Suppression d'onglet


Sujet :

C++Builder

  1. #1
    Membre averti
    Inscrit en
    Juin 2004
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 49
    Par défaut [Débutant] Classe dérivée de TTabSheet & Suppression d'onglet
    Bonsoir à tous et à toutes.
    Pardon par avance si la question vous semble incongrue, mais je bute sur ce problème depuis une bonne heure et j'avoue que je commence à épuiser mon quotat de patience. Alors, parlons peu, mais parlons bien.
    J'ai créé une classe dérivée de TTabSheet, pour pouvoir créer un modèle d'onglet. Jusque là, tout va bien, jusque là, tout va bien.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    __fastcall CTabSheetDial::CTabSheetDial (TComponent* Owner, AnsiString StrTitreTab)
        :TTabSheet (Owner)
    {
         PageControl = (TPageControl*)Owner;
         this->Caption = StrTitreTab;
    }
    Je vous passe les détails du constructeur.
    Alors, le problème, c'est que je n'arrive pas à implémenter un destructeur qui fonctionne. Comprenez par là, un destructeur qui supprimerait au moment voulu le nouvel onglet créé, lorsque l'on cliquerait sur un banal TButton dudit onglet. J'ai donc une méthode que j'appelle lors du clic sur le bouton, et je souhaiterais que cette méthode supprime le nouvel onglet créé. J'ai tenté diverses approches, du style:

    Ou encore:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    delete PageControl->Pages[this->PageIndex];
    Mais ça coince. Soit je me prends une access violation dans la tête, ou alors une abstract error. Je pense que l'abstract error vient du fait que je n'ai justement pas implémenté un destructeur adéquat. Mais voilà, que mettre dedans ? Car j'ai testé avec le même code, et... Même souci.
    J'adoooore les sushis. Hum pardon.
    Donc, voilà où j'en suis à l'heure actuelle. Je suis sûr en plus que c'est un truc tout bête, mais voilà, l'heure avancée n'aidant pas, je sèche.
    Si une bonne âme voulait bien venir à ma rescousse, je lui en serais énormément reconnaissante.

    Par avance merci à vous.
    Cordialement.

    Run.

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    Le cas de figure du "delete this" revient à demander au composant de se suicider !
    Or ce n'est pas possible !

    Le mieux est de faire en sorte que ton TabSheet rajoute un TPopupMenu au PageControl.
    Donc ne pas utiliser de TButton sur ce TabSheet.

    Si le PageControl est déjà doté d'un PopupMenu, ça risque d'être délicat si ce
    dernier n'est pas celui que l'on cherche à rajouter...
    Voici un élément de réflexion où je ne montre qu'un cas de figure simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    __fastcall jTab::jTab(TComponent *Owner, AnsiString N)
        : TTabSheet(Owner)
    {
    Caption = N;
    PageControl = (TPageControl*)Owner;
    if(PageControl->PopupMenu == NULL)
        {
        PageControl->PopupMenu = new TPopupMenu(Owner);
        TMenuItem *MI = new TMenuItem(Owner);
        MI->Caption = "Supprimer cette page";
        MI->OnClick = SupprimerClick;
        PageControl->PopupMenu->Items->Add(MI);
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    __fastcall jTab::~jTab()
    {
    //To do...
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    void __fastcall jTab::SupprimerClick(TObject *Sender)
    {
    TMenuItem *MI = (TMenuItem*)Sender;
    TPageControl *PageCtrl = (TPageControl*)MI->Owner;
    if(PageCtrl->ActivePage->ClassNameIs("jTab"))
        {
        delete (jTab*)PageCtrl->ActivePage;
        }
    else
        {
        //..
        }
    }
    Testé avec BCB3 Pro !

    A plus !

  3. #3
    Membre averti
    Inscrit en
    Juin 2004
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 49
    Par défaut
    Salut henderson !
    Merci beaucoup pour ta réponse claire et précise. Alors, j'ai testé avec BCB 6, et le code que tu as passé fonctionne à merveille, impeccable.
    Le problème, c'est que je trouve cette façon de faire incroyablement "compliquée".

    De toute façon, je ne peux pas me permettre d'utiliser un popup menu pour fermer un onglet, il me faudra absolument passer par un bouton ^^
    Ceci dit je voulais quand même essayer, et ta solution marche parfaitement, merci, ça reste une alternative.
    Je t'avoue être très supris par les mécanismes qui permettent de gérer les TabSheet. Par exemple, je trouve notamment tout bonnement hallucinant qu'il n'y ait pas de moyen simple de dupliquer le container avec ses composants à l'intérieur. Alors oui, j'ai certes lu sur le forum qu'il y a une classe codée originellement en Delphi puis portée sous BCB qui permet ceci (DuplicateComponent si ma mémoire ne me fait pas défaut) mais avouons que ce n'est pas du maniement le plus aisé.

    Alors donc, je me suis retroussé les manches pour créer "à la mano" un modèle d'onglet que je puisse instancier dynamiquement, et j'apprends maintenant qu'on ne peut pas détruire cet objet de manière "simple". Ca me mine un peu le moral.
    Parce que, quelque chose m'échappe: On peut dériver une classe de TTabSheet de la manière la plus aisée qui soit, et par ce biais ajouter X onglets à un TPageControl, mais on ne dispose pas du mécanisme inverse de destruction si j'ai bien compris ?

    En fait, si je résume grossièrement, et n'hésite pas à me corriger si je me trompe, dans un sens ça marche nickel, mais pas dans l'autre ?
    Je t'avoue que je suis un peu perplexe

    Si j'avais su ça à l'avance, je pense que je me serais orienté vers un autre système de gestion pour ce que je suis en train de faire ^^. Enfin ceci dit, c'est toujours bon à savoir.

    Merci encore.

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    Il y a quand même une solution viable avec un seul bouton pour l'ensemble.

    Pour celà, il suffit d'utiliser un bouton dont le propriétaire et tout sauf le tabsheet (la form par exemple). On peut alors jongler avec son Parent pour le faire s'afficher sur la page active du PageControl ! Celà demande quand même une bonne bidouille !

    Voici mon test avec BCB3 Pro et des composants classiques :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
    {
    SpeedButton1->Visible = false;
    TTabSheet *TS = (TTabSheet*)SpeedButton1->Parent;
    SpeedButton1->Parent = Form1;
    TTabSheet *Next = PageControl1->FindNextPage(TS, true, true);
    TTabSheet *Prev = PageControl1->FindNextPage(TS, false, true);
    delete TS;
    if(Prev != NULL)
        {
        PageControl1->ActivePage = Prev;
        PageControl1Change(PageControl1);
        }
    else
        {
        if(Next != NULL)
            {
            PageControl1->ActivePage = Next;
            PageControl1Change(PageControl1);
            }
        }
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void __fastcall TForm1::PageControl1Change(TObject *Sender)
    {
    if(PageControl1->ActivePage != NULL)
        {
        SpeedButton1->Parent = PageControl1->ActivePage;
        SpeedButton1->SetBounds(20,
            PageControl1->ActivePage->Height - 10 - SpeedButton1->Height,
            SpeedButton1->Width, SpeedButton1->Height);
        SpeedButton1->Visible = true;
        }
    }
    A plus !

  5. #5
    Membre averti
    Inscrit en
    Juin 2004
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 49
    Par défaut
    Re bonjour henderson.

    Merci pour ta réponse, je testerai ce soir, mais au premier coup d'oeil ta solution me branche assez :]
    Sinon, au risque de paraître lourd, je tente quand même le coup. Pourquoi est-ce que ce code, mis dans le clic de mon bouton - celui instancié dans la classe dérivée de TTabSheet donc - génère-t-il une "abstract error" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void __fastcall CTabSheetDial::BtnFermerClick(TObject *Sender)
    {
          TPageControl* pControl = (TPageControl*) Owner;
          delete pControl->Pages[this->PageIndex];
    }//BtnFermerClick()
    J'ai l'impression de rien faire de mal pourtant. Je déclare un pointeur sur le PageControl originel, et j'essaie juste de lui deleter l'onglet créé.
    Si tu peux m'expliquer où est l'erreur, je suis preneur avec plaisir.
    Par avance merci.

    A bientôt.

  6. #6
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    Je pense que BCB doit anticiper que l'opération peut conduire au suicide du this ou qu'il y a un risque allant dans ce sens (donc pour éviter le crash à l'éxecution...).

    A plus !

  7. #7
    Membre émérite
    Avatar de bandit boy
    Profil pro
    Inscrit en
    Février 2006
    Messages
    916
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 916
    Par défaut
    Salut,
    J'arrive un peu tard, mais personnellement j'utilise une méthode très simpliste et très "bidouille".
    Lorsque je clique sur le bouton de supression de l'onglet à supprimer, je met une variable à la valeur de l'index de l'onglet que souhaite suprimer et je change d'onglet (onglet précédent par exemple). Dans mon application, un timer tournait pour m'afficher qq valeur, j'en ai profité pour lui faire tester ma variable prenant l'index de l'onglet. Si celle-ci est différente de -1, elle supprime l'onglet concerné.
    Ce timer intervenant après le changement d'onglet, et la tâche du bonton terminé, il n'y a aucun problème de violation ou d'accès mémoire.
    Voilà, je ne sais pas si cela peut t'aider, mais cette méthode marche.

  8. #8
    Membre averti
    Inscrit en
    Juin 2004
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 49
    Par défaut
    Re coucou les ptits loups.
    Alors bah, en fait henderson, désolé mais j'ai même pas eu à tester ta dernière solution, car celle décrite par bandit boy marche nickel chrome. Sois loué :]
    C'est juste un peu la honte de pas y avoir pensé tout seul quoi -_-

    Ca tombait pile poil, y avait déjà un timer tout prêt. Intervalle 5 ms, okay c'est pas ce qu'on peut appeler une fermeture d'onglet instantanée, mais le temps de latence passe inaperçu à l'utilisation.
    Merci mille fois pour votre aide, et la prochaine fois j'essairai de faire travailler un peu plus les méninges...

    Amicalement.

    Run.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 25/01/2007, 21h11
  2. [MFC] CArray et classe dérivée?
    Par TigreRouge dans le forum MFC
    Réponses: 14
    Dernier message: 02/08/2005, 22h45
  3. Déterminer le type d'une class dérivée
    Par LDDL dans le forum MFC
    Réponses: 3
    Dernier message: 10/12/2004, 17h36
  4. [Débutant]Classe d'Authentification : compilation impossible
    Par acyclique dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 23/08/2003, 19h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo