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 :

quelques questions sur un Shape créé dynamiquement


Sujet :

C++Builder

  1. #1
    Membre actif Avatar de SmileSoft
    Inscrit en
    Mars 2008
    Messages
    436
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 436
    Points : 214
    Points
    214
    Par défaut quelques questions sur un Shape créé dynamiquement
    Salut,

    1- je crée dynamiquement des shapes afin d'afficher un graphe sous forme d'un arbre binaire, je cherche la formule qui me permet de bien positionner ces shapescomme le montre la figure suivante:



    la meilleure façon est de mettre les opérandes de l'expression dans une lignes en bas et les opérateurs un par ligne jusqu'à la racine.

    2-je cherche aussi un code qui me permet de supprimer ces shapes.


    code de la création dynamique des shapes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int n=StrToInt(Edit1->Text);//récupérer le nombre de shape à créer 
     
    if (n != 0)
    {
     
     for( int i=1;i<=n;i++)
     {
     TShape *Shapei = new TShape(this);
     Shapei->Parent = Form1;
     Shapei->Shape=stCircle;
      Shapei->Width =30;
     Shapei->Top = i*random (100);
     Shapei->Left = i*(100)+5;
        Shapei->Visible=true;}}


    Merci d'avance

  2. #2
    Membre chevronné
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Points : 2 189
    Points
    2 189
    Par défaut
    La façon la plus intelligente de faire ce que tu demande est d'utiliser un vecteur dont l'on efface le contenu à chaque modification de Edit1.

    Par contre, cette façon est longue à expliquer et c'est vendredi . Donc, je te donne une réponse facile avec quelques lignes de code:

    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
        for (int i = 0; i < ComponentCount; i++) {
            if (Components[i]->ClassName() == "TShape") {
                delete Components[i];
                i--;
            }
        }
     
        // Rien n'a été modifié ci-dessous, à part le formatage du code
        int n = StrToInt(Edit1->Text); // récupérer le nombre de shape à créer
     
        if (n != 0) {
            for (int i = 1; i <= n; i++) {
                TShape *Shapei = new TShape(this);
                Shapei->Parent = Form1;
                Shapei->Shape = stCircle;
                Shapei->Width = 30;
                Shapei->Top = i * random(100);
                Shapei->Left = i * (100) + 5;
                Shapei->Visible = true;
            }
        }
    Ce code fait le tour de tout les composants sur ta form et efface tout ceux qui sont des TShape.

  3. #3
    Membre chevronné
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Points : 2 189
    Points
    2 189
    Par défaut
    En passant, à la place de ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        int n = StrToInt(Edit1->Text); // récupérer le nombre de shape à créer
    Je te conseil d'utiliser ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        int n = StrToIntDef(Edit1->Text, 0); // récupérer le nombre de shape à créer, la valeur par défaut est zéro en cas de problème de conversion

  4. #4
    Membre actif Avatar de SmileSoft
    Inscrit en
    Mars 2008
    Messages
    436
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 436
    Points : 214
    Points
    214
    Par défaut
    Citation Envoyé par Crayon Voir le message
    La façon la plus intelligente de faire ce que tu demande est d'utiliser un vecteur dont l'on efface le contenu à chaque modification de Edit1.

    Par contre, cette façon est longue à expliquer et c'est vendredi . Donc, je te donne une réponse facile avec quelques lignes de code:
    Merci beaucoup c'est ce que je cherchais en fait, mais j'ai eu une erreur avec l'opérateur '==' du test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (Components[i]->ClassName() == "TShape")
    Erreur:
    'operator==' non implémenté dans le type 'ShortString' pour les arguments de type 'char*'

  5. #5
    Membre chevronné
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Points : 2 189
    Points
    2 189
    Par défaut
    Citation Envoyé par SmileSoft Voir le message
    Merci beaucoup c'est ce que je cherchais en fait, mais j'ai eu une erreur avec l'opérateur '==' du test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (Components[i]->ClassName() == "TShape")
    Utilise plutôt ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (Components[i]->ClassNameIs("TShape"))

  6. #6
    Membre chevronné

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

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 390
    Points : 1 777
    Points
    1 777
    Par défaut
    Salut !

    Je pense que tu aurais mieux fait de poster cette deuxième question en premier !
    En fait, il n'est pas nécessaire d'utiliser TShape car il suffirait de passer par une solution purement graphique.

    Par ailleurs, il me semble que les parenthèses ne sont pas indispensables au niveau de ton arbre.
    Donc : a&b&c&d&e... (& est n'importe quel opérateur) est amplement suffisant.
    Ca montre un entrelacement (feuille, noeud, feuille ...) qu'on va exploiter dans ce qui va suivre.

    Le point le plus délicat est de coder un traitement récursif :
    - dans la phase montante (empiler) on va dessiner les segments
    - dans la phase descendante (dépiler) on va dessiner les cercles
    Simplement pour dessiner par dessus les segments.

    Comme il faut faire une distinction entre feuille et noeud, j'ai pris la liberté d'utiliser un switch un peu particulier en exploitant l'entrelacement des données.
    J'ai donc deux méthodes récursives (Leaf et Node) qui se sollicitent mutuellement.

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    class jTree : public TGraphicControl
    {
    protected :
    bool Flag;
     
    private :
    AnsiString B;
    AnsiString FCaption;
    int FCellDim;
    int FRadius;
    AnsiString Tree;
    TPoint LeafPos;
    TPoint NodePos;
        void __fastcall SetCaption(AnsiString Value);
     
    Graphics::TBitmap *Bitmap;
    public :
        __fastcall jTree(TComponent *AOwner);
        __fastcall ~jTree();
     
        // méthodes récursives entrelacées
        void __fastcall Leaf(TPoint P1, int I);
        void __fastcall Node(TPoint P1, int I);
     
        void __fastcall Paint();
     
    __property AnsiString Caption={read=FCaption, write=SetCaption};
    __property int CellDim={read=FCellDim};
    __property int Radius={read=FRadius};
    };
    Les méthodes :

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
     
    __fastcall jTree::jTree(TComponent *AOwner)
        : TGraphicControl(AOwner)
    {
    Flag = false;
    if(AOwner->InheritsFrom(__classid(TWinControl)))
        {
        Parent = (TWinControl*)AOwner;
        }
    Bitmap = new Graphics::TBitmap;
    FCaption = "a&b";
    Tree = FCaption;
     
    FCellDim = 40;
    FRadius = 10;
    }
    //------------------------------------
    __fastcall jTree::~jTree()
    {
    delete Bitmap;
    Bitmap = NULL;
    }
    //------------------------------------
    void __fastcall jTree::SetCaption(AnsiString Value)
    {
    if(Value != "")
        {
        FCaption = Value;
        AnsiString A = "";
        TReplaceFlags Flags = Flags << rfReplaceAll;
        Tree = StringReplace(Value, "(", A, Flags);
        Tree = StringReplace(Tree, ")", A, Flags);
        Tree = StringReplace(Tree, " ", A, Flags);
        Repaint();
        }
    }
    //------------------------------------
    void __fastcall jTree::Leaf(TPoint P1, int I)
    {
    LeafPos.x = LeafPos.x + CellDim;
    TPoint P = LeafPos;
    if(I <= Tree.Length())
        {
        TCanvas *C = Bitmap->Canvas;
        C->MoveTo(P1.x, P1.y);
        C->LineTo(P.x, P.y);
     
        Node(NodePos, I+1); // <<
     
        B = Tree.SubString(I, 1);
        C->Ellipse(P.x - Radius, P.y - Radius, P.x + Radius, P.y + Radius);
        C->TextOut(P.x - (C->TextWidth(B) / 2),
                   P.y - (C->TextHeight(B) / 2),
                   B);
        }
    }
    //------------------------------------
    void __fastcall jTree::Node(TPoint P1, int I)
    {
    NodePos.x = NodePos.x + CellDim;
    NodePos.y = NodePos.y - CellDim;
    TPoint P = NodePos;
    if(I <= Tree.Length())
        {
        TCanvas *C = Bitmap->Canvas;
        C->MoveTo(P1.x, P1.y);
        C->LineTo(P.x, P.y);
     
        Leaf(P, I+1); // <<
     
        C->Ellipse(P.x - Radius, P.y - Radius, P.x + Radius, P.y + Radius);
        B = Tree.SubString(I, 1);
        C->TextOut(P.x - (C->TextWidth(B) / 2),
                   P.y - (C->TextHeight(B) / 2),
                   B);
        }
    }
    //------------------------------------
    void __fastcall jTree::Paint()
    {
    if(Flag) return;
     
    int n = Tree.Length();
    int we = ((n / 2) + 2) * CellDim;
    int he = ((n / 2) + 2) * CellDim;
    if((we != Width) || (he != Height))
        {
        Flag = true;
        SetBounds(Left,Top, we, he);
        Flag = false;
        }
    if(Bitmap != NULL)
        {
        if(Bitmap->Width != we) Bitmap->Width = we;
        if(Bitmap->Height != he) Bitmap->Height = he;
        TCanvas *C = Bitmap->Canvas;
        C->Brush->Color = clWhite;
        C->Brush->Style = bsSolid;
        C->FillRect(Rect(0, 0, we, he));
        //REM : a&b&c&d...
        LeafPos = Point(CellDim, he - CellDim);
        NodePos = Point((CellDim / 2), he - CellDim);
        int i = 1;
        TPoint P1 = LeafPos;
     
        Node(P1, i+1); // <<
     
        C->Ellipse(P1.x - Radius,
                   P1.y - Radius,
                   P1.x + Radius,
                   P1.y + Radius);
        B = Tree.SubString(i, 1);
        C->TextOut(P1.x - (C->TextWidth(B) / 2),
                   P1.y - (C->TextHeight(B) / 2),
                   B);
     
        C->TextOut((Width - C->TextWidth(Caption)) / 2,
                    Height - 2 - C->TextHeight(Caption),
                    Caption);
     
        Canvas->Draw(0, 0, Bitmap);
        }
    }
    Comme la classe jTree porte tout le code, son utilisation est simplifiée :

    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
     
    jTree *Tree;
     
    //-----------------------------------
    //-----------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    Tree = new jTree(this);
    Tree->SetBounds(5,30,10,10); // << placé chez moi sous Edit1
    }
     
    //-----------------------------------
    void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
    if(Key == VK_RETURN)
        {
        Tree->Caption = Edit1->Text;
        }
    }

    Je n'ai pas le temps d'aller plus loin ... mais je pense que l'essentiel est fait.
    Il faudrait finaliser en mettant en place les setter des propriétés.

    A plus !

  7. #7
    Membre chevronné

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

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 390
    Points : 1 777
    Points
    1 777
    Par défaut
    Salut !

    On peut bien entendu se contenter d'une fonction unique.
    Dans ce qui suit le flag (bool) Leaf permet de s'affranchir de la parité de l'index (au cas où...).

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    void __fastcall jTree::LeafOrNode(TPoint P1, int I, bool Leaf)
    {
    // la position de l'objet,
    TPoint P;
    // le point qui sera passé comme paramère P1 
    TPoint S; 
     
    if(I <= Tree.Length())
        {
        if(Leaf)
            {
            LeafPos.x = LeafPos.x + CellDim;
            P = LeafPos;
            S = NodePos;
            }
        else
            {
            NodePos.x = NodePos.x + CellDim;
            NodePos.y = NodePos.y - CellDim;
            P = NodePos;
            S = P;
            }
        TCanvas *C = Bitmap->Canvas;
     
        C->MoveTo(P1.x, P1.y);
        C->LineTo(P.x, P.y);
     
        LeafOrNode(S, I+1, !Leaf); // <<
     
        C->Ellipse(P.x - Radius, P.y - Radius, P.x + Radius, P.y + Radius);
        B = Tree.SubString(I, 1);
        C->TextOut(P.x - (C->TextWidth(B) / 2),
                   P.y - (C->TextHeight(B) / 2),
                   B);
        }
    }
    L'appel dans la méthode Paint devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    //..
    LeafOrNode(P1, i+1, false); // en lieu et place de : Node(P1, i+1);
    //..
    A plus !

  8. #8
    Membre actif Avatar de SmileSoft
    Inscrit en
    Mars 2008
    Messages
    436
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 436
    Points : 214
    Points
    214
    Par défaut
    Merci henderson pour ce code, trop fort , quoique je trouve des difficultés de compréhension , je l'ai testé et il marche impeccable, je n'ai pas parlé au début de l'opérateur unaire not (!) et d'un ordre de priorité pour les opérateurs={!(not),^(et logique),v(ou logique),;(séquence)} par exemple si on a l'expression: (A^B)v(C^D), je dois avoir v dans la racine de l'arbre càd v(^(A,B),^(C,D)).

    Merci

  9. #9
    Membre chevronné

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

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 390
    Points : 1 777
    Points
    1 777
    Par défaut
    Salut !

    Finalement j'ai eu un peu de temps donc ...

    Voici quelque chose qui va te sembler un peu pointu ... mais je pense que ça l'est un peu !
    Il y a peut-être deux ou trois trucs à revoir ... c'est possible !
    Peut-être peut-on aussi le faire autrement ... ou plus simplement ... ???

    En tout cas, ça donne l'impression de fonctionner ...

    Cependant, voici les conventions :

    a) les ambiguïtés doivent être levées à la saisie.
    Par exemple : (a&b)^(c&d) et non pas a&b^c&d si on veut que le EOR soit l'opérateur de sortie (le résultat)

    b) le NOT :
    - il est pris en compte tel quel (ici, pas de simplification : NOT+AND ne donne pas NAND)
    - il affecte l'opérateur ou l'opérande qu'il précède :
    Par exemple : (a!&!b) donnera :
    - NOT <- AND <- a
    <- NOT <- b

    c) au cas où les ambiguïtés se seraient pas levées par l'utilisateur, l'opérateur de sortie est le dernier dans la formule (lecture de gauche à droite).
    Par exemple a&b^c est résolu comme :
    ^ <- c
    <- & <- b
    <- a

    d) l'arbre accèpte N entrées par opérateur.
    Les opérateurs à plus de 2 entrées doivent être exprimés comme ceci : &abcd ou bien a&bcd

    e) L'opérateur se centre, sur le plan horizontal, automatiquement par rapport à ses entrées.

    Donc voici le code qui est encore une usine à gaz :

    Les classes :

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    // histoire de lire ce que l'on fait :
    #define as_operator true
    #define as_operand false
     
    class jNode : public TComponent
    {
    public :
    AnsiString Caption;
    TPoint Pos;
    int Level;
    TList *Inputs;
        __fastcall jNode(TComponent *AOwner, AnsiString ACaption, TPoint APos,
                          bool AsOperator);
        __fastcall ~jNode();
     
        int __fastcall PosX();
        int __fastcall PosY();
        void __fastcall LinkTo(jNode *Target);
        void __fastcall PaintLinks(TCanvas *C, int Bottom);
        void __fastcall PaintCore(TCanvas *C, int Bottom, int R);
     
    };
     
    class jTree : public TGraphicControl
    {
    private :
    Graphics::TBitmap *Bitmap;
    AnsiString FCaption;
    AnsiString A;
    AnsiString B;
    TReplaceFlags Flags;
    int FRadius;
    int Operand_x;
    int Operator_x;
        void __fastcall SetCaption(AnsiString Value);
        void __fastcall SetRadius(int Value);
     
    public :
    AnsiString Operators;
    int Length;
    int Index;
     
        __fastcall jTree(TComponent *AOwner);
        __fastcall ~jTree();
        void __fastcall Paint();
        jNode* __fastcall Logic();
     
    __property AnsiString Caption={read=FCaption, write=SetCaption};
    __property int Radius={read=FRadius, write=SetRadius};
    };
    Les méthodes :

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
     
    //---- Constructeur de jNode
     
    __fastcall jNode::jNode(TComponent *AOwner, AnsiString ACaption, TPoint APos,
                          bool AsOperator)
        : TComponent(AOwner)
    {
    Caption = ACaption;
    Pos = APos;
    Level = 0;
    if(AsOperator) Inputs = new TList;
    else Inputs = NULL;
    }
     
    //---- Destructeur de jNode
     
    __fastcall jNode::~jNode()
    {
    if(Inputs != NULL)
        {
        Inputs->Clear();
        delete Inputs;
        }
    }
     
    //---- Calcul de la position finale du jNode en X
     
    int __fastcall jNode::PosX()
    {
    int j;
    if(Inputs != NULL)
        {
        if(Inputs->Count != 0)
            {
             for(j=0; j < Inputs->Count; j++)
                {
                ((jNode*)Inputs->Items[j])->PosX();
                }
            if(Caption == "!")
                {
                Pos.x = ((jNode*)Inputs->First())->Pos.x;
                }
            else
                {
                for(j=0; j < Inputs->Count; j++)
                    {
                    Pos.x = (((jNode*)Inputs->First())->Pos.x +
                             ((jNode*)Inputs->Last())->Pos.x) / 2;
     
                    }
                }
            }
        }
    return Pos.x;
    }
     
    //---- Calcul de la position finale du jNode en Y
     
    int __fastcall jNode::PosY()
    {
    int j;
    int val;
    if(Inputs != NULL)
        {
        if(Inputs->Count != 0)
            {
            for(j=0; j < Inputs->Count; j++)
                {
                val = 1 + ((jNode*)Inputs->Items[j])->PosY();
                if( val > Level) Level = val;
                }
            }
        }
    return Level;
    }
     
    //---- jNode sait se lier à un jNode
    // selon un mécanisme assez particulier...
     
    void __fastcall jNode::LinkTo(jNode *Target)
    {
    if(Inputs != NULL)
        {
        // Tester si NOT
        if(Caption == "!")
            {
            // Tester si un lien est déjà établi
            if(Inputs->Count == 0)
                {
                // si aucun lien n'existe, target se lie à NOT
                Inputs->Add(Target);
                }
            else
                {
                // si un lien existe, target se lie à un dernier opérateur
                ((jNode*)Inputs->Last())->Inputs->Add(Target);
                }
            }
        else
            {
            // un opérateur autre que NOT se lie directement à target
            Inputs->Add(Target);
            }
        }
    }
     
    //---- jNode sait dessiner les liens vers d'autres jNode
     
    void __fastcall jNode::PaintLinks(TCanvas *C, int Bottom)
    {
    int j;
    int x1 = Pos.x;
    int y1 = Bottom - (Level * 40);
    int x2;
    int y2;
    jNode *Target;
    if(Inputs != NULL)
        {
        for(j = 0; j < Inputs->Count; j++)
            {
            Target = (jNode*)Inputs->Items[j];
            x2 = Target->Pos.x;
            y2 = Bottom - (Target->Level * 40);
            C->MoveTo(x1, y1);
            C->LineTo(x2, y2);
            }
        }
    }
     
    //----- jNode sait se dessiner
     
    void __fastcall jNode::PaintCore(TCanvas *C, int Bottom, int R)
    {
    int x = Pos.x;
    int y = Bottom - (Level * 40);
    C->Ellipse(x - R, y - R, x + R, y + R );
    C->TextOut(x - (C->TextWidth(Caption) / 2),
               y - (C->TextHeight(Caption) / 2),
               Caption);
    }
     
     
    //*******************************************************
     
     
    //---- Le constructeur de jTree
     
    __fastcall jTree::jTree(TComponent *AOwner)
        : TGraphicControl(AOwner)
    {
    if(AOwner->InheritsFrom(__classid(TWinControl)))
        {
        Parent = (TWinControl*)AOwner;
        }
    Bitmap = new Graphics::TBitmap;
    FRadius = 10;
    Flags = Flags << rfReplaceAll;
    Operators = "&*|+!^";
    }
     
    //---- Le destructeur de jTree
     
    __fastcall jTree::~jTree()
    {
    delete Bitmap;
    Bitmap = NULL;
    }
     
    //---- Pour faire echo immédiat de la modification du rayon des cercles
     
    void __fastcall jTree::SetRadius(int Value)
    {
    FRadius = Value;
    Repaint();
    }
     
    //---- Méthode récursive pour générer l'arbre des objets jNode
    //---- elle réentre si on détecte '('
    //---- elle ressort si on détecte ')' en renvoyant un objet ou NULL (selon...)
     
    jNode* __fastcall jTree::Logic()
    {
    jNode *Temp = NULL;
    jNode *Not = NULL;
    jNode *Operand = NULL;
    jNode *Operator = NULL;
    while(Index < Length)
        {
        B = A.SubString(Index, 1);
        Index++;
     
        if(B == "(")
            {
            Temp = Logic(); // << on récupère dans temp un opérateur
            if(Temp != NULL)
                {
                if(Operator != NULL)
                    {
                    // si un opérateur a déjà été crée on le lie
                    Operator->LinkTo(Temp);
                    }
                else
                    {
                    // sinon il est mis en attente comme opérande
                    Operand = Temp;
                    }
                }
            }
        else
            {
            if(B == ")")
                {
                // on retourne un opérateur qui peut éventuellement être NULL
                return Operator;
                }
            else
                {
                // tester s'il s'agit d'un opérateur
                if(Operators.Pos(B) != 0)
                    {
                    Temp = new jNode(this, B, Point(0, 0), as_operator);
                    // tester si on vient de créer un NOT
                    if(B == "!")
                        {
                        // si oui on le met en attente
                        Not = Temp;
                        }
                    else
                        {
                        // ce n'est pas un NOT
                        if(Not == NULL)
                            {
                            // si aucun NOT n'est en attente
                            Operator = Temp;
                            if(Operand != NULL)
                                {
                                // on accroche un opérande en attente
                                Operator->LinkTo(Operand);
                                }
                            // l'opérateur est un opérande potentiel
                            Operand = Temp;
                            }
                        else
                            {
                            // On a un NOT en attente
                            // s'il existe une feuille on accroche à OP
                            if(Operand != NULL) Temp->LinkTo(Operand);
     
                            // on accroche OP à NOT
                            Not->LinkTo(Temp);
     
                            // OP devient opérateur indirect via NOT
                            // mécanisme dans jNode::LinkTo(jNode* Target)
                            Operator = Not;
     
                            // mais NOT est aussi un opérande potentiel
                            Operand = Not;
     
                            // prêt pour un prochain NOT
                            Not = NULL;
                            }
                        }
                    }
                else
                    {
                    // donc il s'agit d'un opérande
                    Temp = new jNode(this, B, Point(Operand_x, 0), as_operand);
                    Operand_x +=40;
                    // on vérifie si on a un NOT en attente
                    if(Not == NULL)
                        {
                        // non, donc on teste si on a un opérateur en cours
                        // si oui on lie
                        if(Operator != NULL) Operator->LinkTo(Temp);
     
                        // sinon l'opérande est mis en attente
                        else Operand = Temp;
                        }
                    else
                        {
                        // on a un NOT en attente
                        // on accroche la feuille au NOT
                        Not->LinkTo(Temp);
     
                        // si OP existe on accroche NOT à OP
                        if(Operator != NULL) Operator->LinkTo(Not);
     
                        // sinon NOT devient un opérande potentiel
                        else Operand = Not;
     
                        // prêt pour un prochain NOT
                        Not = NULL;
                        }
                    }
                }
            }
        }
    return Operator;
    }
     
    //---- Pour faire echo immédiat de la modification de Caption
     
    void __fastcall jTree::SetCaption(AnsiString Value)
    {
    int j;
    B = "";
    if(Value != "")
        {
        FCaption = Value;
        A = StringReplace(Value, " ", B, Flags);
        DestroyComponents();
        Index = 1;
        Length = A.Length() + 1;
        Operand_x = 20;
        Operator_x = 40;
        Logic();
        for(j=0; j < ComponentCount; j++) ((jNode*)Components[j])->PosX();
        for(j=0; j < ComponentCount; j++) ((jNode*)Components[j])->PosY();
        }
    Repaint();
    }
     
    //---- L'objet sait se peindre
     
    void __fastcall jTree::Paint()
    {
    int j;
    TCanvas *C;
    if(Bitmap != NULL)
        {
        if(Bitmap->Width != Width) Bitmap->Width = Width;
        if(Bitmap->Height != Height) Bitmap->Height = Height;
     
        C = Bitmap->Canvas;
     
        C->Pen->Mode =pmCopy;
        C->Pen->Style = psSolid;
        C->Pen->Color = clBlack;
     
        C->Brush->Style = bsSolid;
        C->Brush->Color = clWhite;
     
        C->FillRect(Rect(0,0,Width, Height));
     
        // on dessine d'abord les segments (les liens)
     
        for(j = 0;j < ComponentCount; j++)
            {
            ((jNode*)Components[j])->PaintLinks(C, Height - 40);
            }
     
        // puis on dessine les objets (par dessus les liens)
     
        for(j = 0;j < ComponentCount; j++)
            {
            ((jNode*)Components[j])->PaintCore(C, Height - 40, Radius);
            }
     
        // A toi de centrer et dessiner le texte de la formule !
        // ...
     
        Canvas->Draw(0,0,Bitmap);
        }
    }

    Donc l'usage que j'en ai fait, en considérant que les deux classes sont déclarées dans le header de TForm1 et que les méthodes sont dans unit1.cpp :

    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
     
    jTree *Tree;
     
    //-----
    //-----
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    Edit1->Align = alTop;
    Tree = new jTree(this);
    Tree->Align = alClient;
    }
    //-----
    void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
    if(Key == VK_RETURN)
        {
        Tree->Caption = Edit1->Text;
        }
    }
    Sinon... il y a aussi le forum Algorithmes !

    A plus !

  10. #10
    Membre actif Avatar de SmileSoft
    Inscrit en
    Mars 2008
    Messages
    436
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 436
    Points : 214
    Points
    214
    Par défaut
    Merci henderson, le code marche très bien et répond à toutes les contraintes, j'ai pas bien compris la philosophie suivie, j'ai du mal à comprendre la méthode PosX() et le remplissage de la liste Inputs dans la méthode LinkTo().

    Merci d'avance

  11. #11
    Membre actif Avatar de SmileSoft
    Inscrit en
    Mars 2008
    Messages
    436
    Détails du profil
    Informations forums :
    Inscription : Mars 2008
    Messages : 436
    Points : 214
    Points
    214
    Par défaut
    salut,

    j'aimerai extraire la racine de l'arbre, j'utilise ce code pour des expressions non parenthésées
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    AnsiString expression=Tree->A;
    int l=expression.Length();
    char Racine= expression[l-1];
    if( Racine== '!') Racine=expression[l-2];
    comment faire pour les expressions parenthésées?

Discussions similaires

  1. Quelques questions sur les threads
    Par benj63 dans le forum C++Builder
    Réponses: 28
    Dernier message: 21/11/2005, 14h27
  2. Réponses: 19
    Dernier message: 21/10/2005, 20h24
  3. Quelques questions sur la mémoire
    Par Gruik dans le forum C
    Réponses: 6
    Dernier message: 17/11/2004, 15h38
  4. Quelques question sur Win 32 Appli
    Par lvdnono dans le forum Windows
    Réponses: 5
    Dernier message: 15/06/2004, 13h37
  5. Quelques questions sur le TWebBrowser...
    Par CorO dans le forum Web & réseau
    Réponses: 3
    Dernier message: 17/01/2003, 22h23

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