Qt World Summit: Submit your Presentation

ToolTip events not shown for recursive overlapping QGraphicsItem objects

  • Hello folks,
    Newbee with event programming (and more generally GUI programming) I am in deep trouble to understand how events and signals-slots are supposed to be managed. Would you recommend some clear and basic course or wiki or book, with nice simple examples using QtGUI?
    Precisely, I am presently stuck with a QGraphicsScene object on which are painted a number of QgraphicsPG objects. QgraphicsPG class is based on QGraphics item class. QgraphicsPG objects are constructed and painted recursively (tree-like) , with the same tree structure as their ptr_source member (my type Phygenic*).
    I wanted to display as ToolTip some text describing the ptr_source, for instance its ptr_source->nom i.e. its name.
    The QgraphicsPG sub-objects have their rectBounds rectangle inside the mother QgraphicsPG object, and they are painted after the mother QgraphicsPG object, assuming this gives them a higher Z-value (correct?) .
    Neverthess, tooltip behavior is not what I expect, using the re-implemented QGraphicsPG::hoverEnterEvent as shown below:
    I never see the QgraphicsPG sub-objects' ToolTip appearing inside the mother object's RectBounds , but only the mother QgraphicsPG ToolTip itself.

    PG_Qt_MainWindow::PG_Qt_MainWindow(QWidget *parent) :
        ui(new Ui::PG_Qt_MainWindow)
        ui->graphicsView->show() ;
    void PG_Qt_MainWindow::on_actionOuvrir_triggered()
        QString fileName = QFileDialog::getOpenFileName(this, tr("Ouvrir le fichier..."), QString(),
                tr("Fichiers de modèle brut (*.pgML);") ) ;
    // (...) file opened and model constructed, if file is valid
            QGraphicsPG* item= new QGraphicsPG(ptr_modele.back(), position  ) ;
    QGraphicsPG::QGraphicsPG(Phygenic *ptr_pg, Indices2D position, QGraphicsItem *parent, bool develop, bool avecCalcul )
        : rectBoite() , rectTexte(), texte() , flecheEntreeBoite() , flecheSortieBoite() , rectCadre(), rectBounds()
        setAcceptHoverEvents(true) ;
        setToolTip( c_QString(" "+ptr_pg->nom) ) ;
        Q_UNUSED(parent) ;
        ptr_source= ptr_pg ;
        Etat_develop= develop ;
        boite= position ;
        cadre= position ;
        flechesInternes.clear() ;
        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, this, Etat_develop, false ) ) ; 
    // NOTE: recursive constructor is called for sub-objects. No calc for sub-objects
        } // next iph
        if (avecCalcul) calculer(boite, develop) ; 
    } // fin de QGraphicsPG::QGraphicsPG(Phygenic *ptr_pg, QGraphicsItem *parent, bool develop)
    void QGraphicsPG::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget) {
        if ( !Etat_develop || ptr_source->Nph== 0 ) {
            // boite
            painter->drawRect(rectBoite) ;
    // (...)
           // sous-boites
            if (Etat_develop) {
                for  ( int iph= 0 ; iph< ptr_source->Nph ; iph++ ) ss_qgpg.at(iph)->paint(painter, option, widget)  ;
    // NOTE: paint function is called recursively here for sub-objects, after the paint operations on the mother object.
            } // end if (Etat_develop)
    } // fin de QGraphicsPG::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    void QGraphicsPG::hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
        QToolTip::showText(event->screenPos(), c_QString(" "+ptr_source->nom) ) ;
    } // fin de: void QGraphicsPG::hoverEnterEvent(QGraphicsSceneHoverEvent *event)

    Apparently, no hoverEnterEvent is triggered for the sub-objects QGraphicsPG although they should be painted on top of the mother object. What did I miss?

  • Lifetime Qt Champion

    I cant answer for the HoverEvent but i wondered if you checked with

    if (event->type() == QEvent::ToolTip) { .... }

  • @mrjj
    Following your suggestion, this is what I tried :

    bool QGraphicsPG::sceneEvent(QEvent *event) {
        bool retour= false ;
        if (event->type() == QEvent::ToolTip) {
            QToolTip::showText(event->screenPos(), c_QString(" "+ptr_source->nom) ) ;
            retour= true ;
        } // end if
        return retour ;
    } // fin de: QGraphicsPG::sceneEvent(QEvent *event)

    But it won't compile since event->screenPos() is not defined, apparently. Should I cast event somehow (static or dynamic?) to be able to compile.

    But may be I should not re-implement any event handler and let Qt do the work for me, (since QToolTip being set in the constructor, everything else should work automatically)? So I tried and removed all specific event handlers from this class, but the result is event worse: there is no longer any ToolTip text displayed...

  • @TGVF
    Finally, I nailed my bug:
    I added what was missing e.g.construction of the base object in the QGraphicsPG constructor, with : QGraphicsItem(parent) instead of declaring Q_USED (parent) .

    QGraphicsPG::QGraphicsPG(Phygenic *ptr_pg, Indices2D position, QGraphicsItem *parent, bool develop, bool avecCalcul )
        : QGraphicsItem(parent) , rectBoite() , rectTexte(), texte() , flecheEntreeBoite() , flecheSortieBoite() , rectCadre(), rectBounds()
        //setAcceptHoverEvents(true) ;
        setToolTip( c_QString(" "+ptr_pg->nom) ) ;
        //Q_UNUSED(parent) ;

    I also changed the default value of parent to 0 instead of NULL pointer, since the documentation says =0 (isn't it the same, actually?).

       QGraphicsPG(Phygenic* ptr_pg, Indices2D position, QGraphicsItem *parent = 0, bool develop= true, bool avecCalcul= true );

    Finally, ToolTip works as desired without need for a hoverEnterEvent handler, nor any other specific event handler!
    I feel better now, thanks!

  • Lifetime Qt Champion

    Super you found it.
    Yes using 0 or NULL is the same.
    If you want use something else beside 0 or NULL , then use std::nullptr

Log in to reply