Bonjour,
J'utilise QtCreator et ai défini une classe PG_QT_MainWindow héritant de QMainWindow, avec un central QWidget qui inclut un QTabWidget.
L'un des volets contient un QGraphicsView (tout ce qu'il y a de plus standard), destiné à afficher un plusieurs objets de type QGraphicsPG héritant de QGraphicsItem.
La structure arborescente des QGraphicsPG reflète celle des modèles physiques sous-jacents (type Phygenic), avec des sous-modèles de même type et des liens entre sous-modèles.
Voici la fenêtre obtenue après chargement de 3 modèles, le 2nd étant représenté sélectionné et développé (grand cadre rouge):
Nom : Tout_développé.png
Affichages : 87
Taille : 25,9 Ko
Un double clic sur ce modèle permet réduire sa représentation, en ne faisant plus apparaître aucun des sous-modèles:
Nom : Tout_réduit.png
Affichages : 100
Taille : 16,4 Ko
Cela fonctionne "presque" comme souhaité, sauf qu'il n'est plus possible s'agir avec la souris
sur le 3me modèle ("Dzanibekov"): pas de ToolTip visible, pas de détection de clic ou de double-clic.
Voici le header de PG_Qt_MainWindow:
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
 
#ifndef PG_QT_MAINWINDOW_H
#define PG_QT_MAINWINDOW_H
 
#include <QMainWindow>
#include "xploit_pg.h"
#include <QGraphicsScene>
#include "qgraphicspg.h"
 
namespace Ui { class PG_Qt_MainWindow; }
class PG_Qt_MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit PG_Qt_MainWindow(QWidget *parent = 0);
    ~PG_Qt_MainWindow();
    void redessiner_architecture() ;
private slots:
    void on_actionQuitter_triggered();
    void on_actionOuvrir_triggered();
    void on_graphicsView_customContextMenuRequested(const QPoint &pos);
private:
    bool chargerModelePG(const std::string nom_pgML ) ;
    Ui::PG_Qt_MainWindow *ui;
    QGraphicsScene scene ; 
    std::vector<Phygenic*> ptr_modele ; 
    std::vector<QGraphicsPG*> items ; 
};
#endif // PG_QT_MAINWINDOW_H
Voici l'implementation de PG_Qt_MainWindow (extrait):
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
 
#include "pg_qt_mainwindow.h"
#include "ui_pg_qt_mainwindow.h"
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QGraphicsTextItem>
PG_Qt_MainWindow::PG_Qt_MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::PG_Qt_MainWindow)
{
    ui->setupUi(this);
    ui->graphicsView->setScene(&scene);
    QObject::connect(&scene, SIGNAL(selectionChanged()), &scene, SLOT(update()));
    ui->graphicsView->show() ;
}
void PG_Qt_MainWindow::on_actionOuvrir_triggered()
{
	// (... détail omis = ouverture et lecture d'un fichier, push_back dans le Vector ptr_modele )
        Indices2D position= { 0 , 0 } ;
        if ( items.size() > 0 ) {
            position.iV= items.at(items.size()-1)->Etat_develop && items.at(items.size()-1)->ptr_source->Nph >0 
		       ? items.at(items.size()-1)->cadre.iV+1 : items.at(items.size()-1)->boite.iV+1 ;
        }
        bool develop= true ; int item_racine= items.size() ;
        QGraphicsPG* item= new QGraphicsPG(ptr_modele.back(), position, this, item_racine, 0, develop  ) ;
        items.push_back(item);
        scene.addItem(item);
} 
void PG_Qt_MainWindow::redessiner_architecture() 
{
    Indices2D position= { 0 , 0 } ;
    for ( std::vector<QGraphicsPG*>::iterator it= items.begin() ; it !=items.end() ; ++it ) {
        (*it)->calculer(position) ;
        position.iV= (*it)->cadre.iV +1 ;
    } 
    scene.update() ;
}
Voici le header de QGraphicsPG (extrait):
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
 
#ifndef QGRAPHICSPG_H
#define QGRAPHICSPG_H
 
#include <QGraphicsItem>
#include <QMessageBox>
#include "xploit_pg.h"
class PG_Qt_MainWindow ;
 
struct Indices2D { int iH ; int iV ; } ;
(...)
struct FlecheTransfert {
    QRect boule_o ; 
    QVector<QPointF> chemin ;
} ;
struct FlecheTransfert {
    QRect boule_o ;
    QVector<QPointF> chemin ;
} ;
char* c_char(QString qs) ;
QString c_QString(std::string s) ;
 
const int DIM_NOM_BOITE= 30 , DIM_TOTAL_BOITE= 70 ;
const double LONG_ENTREES= 20. , LONG_BOITE= 60. , LONG_SORTIES= 10. , LONG_CELL= 100. ;
const double HAUT_CELL= 46. , HAUT_BOITE= 30. , L_MARGE_CADRE= -4. ;
const double RAYON_BOULE=  3. ;
const QPen noir(Qt::black) ;
const QBrush jaune(Qt::yellow) ;
const QBrush brush_boule(Qt::black) ;
const QPen rouge(Qt::red) ;
const QPen bleu(Qt::blue) ;
const QPen sans_trait(Qt::transparent) ;
const QBrush nonRempli(Qt::transparent) ;
const QBrush couleur_selection(Qt::black , Qt::Dense7Pattern) ;
 
class QGraphicsPG : public QGraphicsItem
{
public:
    QGraphicsPG(Phygenic* ptr_pg, Indices2D position, PG_Qt_MainWindow *fenetre, int item_racine, 
		QGraphicsItem *parent = 0, bool develop= true, bool avecCalcul= true );
    ~QGraphicsPG();
    QRectF boundingRect() const ;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget) ;
    void calculer(const Indices2D &position) ;
 
    PG_Qt_MainWindow *fenetre ; 
    Phygenic* ptr_source    ; 
    bool Etat_develop       ; 
    vector<QGraphicsPG*> ss_qgpg ; /*!< vecteur des sous-boites, lorsque *ptr_pg est un assemblage */
    Indices2D boite ; 
    Indices2D cadre ; 
    QRectF rectBoite ; 
    QRectF rectTexte ; 
    QString texte ; 
    QPolygonF flecheEntreeBoite ; 
    QPolygonF flecheSortieBoite ; 
    QRectF rectCadre ; 
    vector<FlecheTransfert> flechesInternes ; 
    vector<QVector<QPointF> > flechesResultats ; 
    QRectF rectBounds ; 
protected:
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event) ;
};
#endif // QGRAPHICSPG_H
Voici enfin l'implementation de QGraphicsPG (extrait):
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
 
#include <QtGui>
#include <QGraphicsSceneMouseEvent>
#include <QToolTip>
#include "qgraphicspg.h"
#include "pg_qt_mainwindow.h"
const char* c_chr(QString qs) 
{
    std::string s= qs.toStdString() ;
    return s.c_str() ;
} 
QString c_QString(std::string s) { 
    return QString(s.c_str() ) ; 
}
QGraphicsPG::QGraphicsPG(Phygenic *ptr_pg, Indices2D position,  PG_Qt_MainWindow *fenetre1, int item_racine , 
                         QGraphicsItem *parent, bool develop, bool avecCalcul )
    : QGraphicsItem(parent) , rectBoite() , rectTexte(), texte() , flecheEntreeBoite() , 
      flecheSortieBoite() , rectCadre(), rectBounds()
{
    setToolTip( c_QString(" "+ptr_pg->nom) ) ;
    setFlag(QGraphicsItem::ItemIsSelectable, true) ;
    fenetre= fenetre1 ;
    ptr_source= ptr_pg ;
    Etat_develop= develop ;
    boite= position ;
    cadre= position ;
    Indices2D ss_pos ;
    for  ( int iph= 0 ; iph< ptr_source->Nph ; iph++ ) {
       ss_pos.iH= position.iH ; ss_pos.iV= position.iV + iph ;
       ss_qgpg.push_back ( new QGraphicsPG(ptr_source->ph[iph], ss_pos, fenetre, item_racine, this, Etat_develop, false ) ) ;
    } // next iph
    if (avecCalcul) calculer(boite) ;
} 
QRectF QGraphicsPG::boundingRect() const 
{ 
    return rectBounds; 
}
void QGraphicsPG::calculer(const Indices2D &position) 
{
    flechesInternes.clear() ;
    // (... omis= tuyautage pour flèches d'entrée des sous-modèles ... )
    boite= position ;
    cadre= boite ;
    if ( Etat_develop && ptr_source->Nph> 0 ) 
    {
        // (... omis= calcul de la position des sous-boites et du cadre, avec appel réentrant de calculer(), si nécessaire )
    }
    // géométrie boite
    double x_boite= LONG_ENTREES +LONG_CELL * boite.iH , y_boite= (HAUT_CELL-HAUT_BOITE)/2 +HAUT_CELL * boite.iV ;
    rectBoite.setRect(x_boite, y_boite, LONG_BOITE, HAUT_BOITE) ;
    rectBounds.setRect(x_boite, y_boite, LONG_BOITE, HAUT_BOITE) ;
    // géométrie texte
   texte= c_QString(" "+ptr_source->nom) ;
    texte.append("\n") ;
    texte.append(c_QString(" "+ptr_source->espece) ) ;
    rectTexte.setRect(x_boite, y_boite+2 , 2.*LONG_BOITE, HAUT_BOITE) ;
    rectBounds|=rectTexte ;
    // géométrie cadre
    if ( ptr_source->Nph> 0 ) { // assemblage => cadre à tracer
        if ( Etat_develop )  cadre= ss_qgpg.at(ptr_source->Nph-1)->boite  ; else cadre= boite ;
        double L_cadre= LONG_CELL +2.*L_MARGE_CADRE +(Etat_develop ? LONG_CELL * (cadre.iH -boite.iH) : 0 ) ;
        double H_cadre= HAUT_CELL +2.*L_MARGE_CADRE +(Etat_develop ? HAUT_CELL * (cadre.iV -boite.iV) : 0 ) ;
        rectCadre.setRect(x_boite -LONG_ENTREES -L_MARGE_CADRE, y_boite -(HAUT_CELL-HAUT_BOITE)/2 -L_MARGE_CADRE, L_cadre, H_cadre ) ;
        rectBounds|=rectCadre ;
    } //end if ( ptr_source->Nph> 0 )
    // géométrie petite flèche d'entrée boite
    double x_entree= x_boite -LONG_ENTREES/2 ;
    flecheEntreeBoite.erase(flecheEntreeBoite.begin(),flecheEntreeBoite.end());
    flecheEntreeBoite<<QPointF(x_entree, y_boite +HAUT_BOITE/2. )
               <<QPointF(x_boite, y_boite +HAUT_BOITE/2. )
               <<QPointF(x_boite-3., y_boite +HAUT_BOITE/2. -3.)
               <<QPointF(x_boite-3., y_boite +HAUT_BOITE/2. +3.)
               <<QPointF(x_boite, y_boite +HAUT_BOITE/2. )  ;
    rectBounds|= flecheEntreeBoite.boundingRect() ;
    // géométrie petite flèche de sortie boite
    double x_sortie= x_boite +LONG_BOITE +LONG_SORTIES  ;
    flecheSortieBoite.erase(flecheSortieBoite.begin(),flecheSortieBoite.end());
    flecheSortieBoite<<QPointF(x_boite +LONG_BOITE, y_boite +HAUT_BOITE/2. )
               <<QPointF(x_sortie, y_boite +HAUT_BOITE/2. )
               <<QPointF(x_sortie-3., y_boite +HAUT_BOITE/2. -3.)
               <<QPointF(x_sortie-3., y_boite +HAUT_BOITE/2. +3.)
               <<QPointF(x_sortie, y_boite +HAUT_BOITE/2. )  ;
    rectBounds|= flecheSortieBoite.boundingRect() ;
    // géométrie flèches des liaisons internes
    if (Etat_develop && ptr_source->Nph >0) {
        QVector<QPointF> cheminFl ;
        double x_orig, y_orig, x_dest, y_dest ;
        for ( size_t it= 0 ; it<TuyauxEntree.size() ; it++ ) { 
            x_orig= TuyauxEntree.at(it).sortie
              ? LONG_ENTREES +LONG_CELL * ( ss_qgpg.at( TuyauxEntree.at(it).iph_orig )->boite.iH ) +LONG_BOITE +LONG_SORTIES +RAYON_BOULE
              : LONG_ENTREES +LONG_CELL * ( ss_qgpg.at( TuyauxEntree.at(it).iph_orig )->boite.iH ) -LONG_ENTREES/2    ;
            y_orig=  HAUT_CELL/2 +HAUT_CELL * ( ss_qgpg.at( TuyauxEntree.at(it).iph_orig )->boite.iV ) ;
            x_dest=  LONG_CELL * ( ss_qgpg.at( TuyauxEntree.at(it).iph_dest )->boite.iH )  +LONG_ENTREES/2 ;
            y_dest=  HAUT_CELL/2 +HAUT_CELL * ( ss_qgpg.at( TuyauxEntree.at(it).iph_dest )->boite.iV ) ;
            cheminFl.clear() ;
            cheminFl.push_back(QPointF(x_orig   , y_orig ));
            // (... omis= le détail du chemin)
            cheminFl.push_back(QPointF(x_dest   , y_dest ));
            QRect boule(x_orig -RAYON_BOULE, y_orig-RAYON_BOULE, 2.*RAYON_BOULE, 2.*RAYON_BOULE) ;
            FlecheTransfert fl ; fl.boule_o= boule ; fl.chemin= cheminFl ;
            flechesInternes.push_back(fl);
        } 
        // géométrie flèches de distribution à l'entrée
        x_orig= LONG_ENTREES +LONG_CELL * ss_qgpg.at( 0 )->boite.iH -LONG_ENTREES/2    ;
        y_orig=  HAUT_CELL/2 +HAUT_CELL * ss_qgpg.at( 0 )->boite.iV ;
        QRect boule(x_orig -RAYON_BOULE, y_orig-RAYON_BOULE, 2.*RAYON_BOULE, 2.*RAYON_BOULE) ;
 
        for  ( int iph= 1 ; iph< ptr_source->Nph ; iph++ ) {
            x_dest=  LONG_ENTREES +LONG_CELL * ss_qgpg.at( iph )->boite.iH -LONG_ENTREES/2  ;
            y_dest=  HAUT_CELL/2 +HAUT_CELL * ss_qgpg.at( iph )->boite.iV ;
            cheminFl.clear() ;
            cheminFl.push_back(QPointF(x_orig   , y_orig ));
            // (... omis= le détail du chemin)
            cheminFl.push_back(QPointF(x_dest   , y_dest ));
            FlecheTransfert fl ; fl.boule_o= boule ; fl.chemin= cheminFl ;
            flechesInternes.push_back(fl);
        } // next iph
        // géométrie des flèches collectant les résultats
        x_dest=  LONG_ENTREES +LONG_CELL * ss_qgpg.at( ptr_source->Nph-1 )->boite.iH +LONG_BOITE +LONG_SORTIES   ;
        y_dest=  HAUT_CELL/2 +HAUT_CELL * ss_qgpg.at( ptr_source->Nph-1 )->boite.iV ;
        for  ( int iph= 0 ; iph< ptr_source->Nph-1 ; iph++ ) {
            x_orig= LONG_ENTREES +LONG_CELL * ss_qgpg.at( iph )->boite.iH +LONG_BOITE +LONG_SORTIES   ;
            y_orig= HAUT_CELL/2 +HAUT_CELL * ss_qgpg.at( iph )->boite.iV ; ;
            cheminFl.clear() ;
            cheminFl.push_back(QPointF(x_orig   , y_orig ));
            // (... omis= le détail du chemin)
            cheminFl.push_back(QPointF(x_dest   , y_dest-RAYON_BOULE ));
            flechesResultats.push_back(cheminFl);
        } // next iph
    } 
}
void QGraphicsPG::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
           QWidget *widget) 
{
    Q_UNUSED(option) ;
    Q_UNUSED(widget) ;
    QGraphicsItem *parent= this->parentItem() ;
    if ( parent != 0 && ((QGraphicsPG*)(parent))->Etat_develop == false ) return ;
    if ( isSelected() ) 
    {
        painter->setBrush(couleur_selection) ;
        painter->setPen(sans_trait) ;
        painter->drawRect(rectBounds);
    }
    if ( ptr_source->Nph== 0 || (!Etat_develop && ptr_source->Nph> 0 )  ) 
    {
        // boite
        painter->setBrush(jaune);
        painter->setPen(noir);
        painter->drawRect(rectBoite);
        // texte
        QTextOption texteOption= QTextOption() ; texteOption.setWrapMode(QTextOption::NoWrap) ;
        painter->drawText(rectTexte , texte, texteOption );
        // flèche d'entrée boite
        painter->setBrush(nonRempli);
        QPainterPath pathEntree ; pathEntree.addPolygon(flecheEntreeBoite) ;
        painter->drawPath(pathEntree );
        // flèche de sortie boite
        painter->setPen(bleu);
        QPainterPath pathSortie ; pathSortie.addPolygon(flecheSortieBoite) ;
        painter->drawPath(pathSortie );
    }
    if ( ptr_source->Nph> 0 ) 
    { 
        // cadre
        painter->setBrush(nonRempli);
        painter->setPen(rouge);
        painter->drawRect(rectCadre) ;
        if ( Etat_develop && ptr_source->Nph> 0 ) 
        {
            // flèches internes
            painter->setPen(noir);
            for ( size_t ifl= 0 ; ifl<flechesInternes.size() ; ifl++ ) { // parcours des flèches
                painter->setBrush(brush_boule);
                QRect boule= flechesInternes.at(ifl).boule_o ;
                painter->drawEllipse(boule) ;
                painter->setBrush(nonRempli);
                QPainterPath pathTransfert; pathTransfert.addPolygon(flechesInternes.at(ifl).chemin) ;
                painter->drawPath(pathTransfert);
            } 
            // flèches collectant les résultats
            painter->setPen(bleu);
            painter->setBrush(nonRempli);
            for ( size_t ifl= 0 ; ifl<flechesResultats.size() ; ifl++ ) { // parcours des flèches
                QPainterPath pathResultat; pathResultat.addPolygon(flechesResultats.at(ifl)) ;
                painter->drawPath(pathResultat);
            } 
        }
    }
}
void QGraphicsPG::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event) 
{
    Q_UNUSED(event) ;
    qDebug()<<"Evènement double clic détecté sur "<<c_QString(ptr_source->nom) ;
   if ( ptr_source->Nph >0  ) {
       Etat_develop= !Etat_develop ;
       for  ( int iph= 0 ; iph< ptr_source->Nph ; iph++ ) ss_qgpg.at(iph)->setVisible(Etat_develop)  ;
       fenetre->redessiner_architecture() ;
   }
}
Quelqu'un peut-il m'aider à comprendre pourquoi il n'est plus possible d'interagir avec le QGraphicsPG du vecteur items
situé après celui qui a été réduit (visibilité?). Noter que si l'on double-clic à nouveau sur le modèle réduit pour le développer, on retrouve la visibilité normale sur tous les items.