Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How do you handle selection of QGraphicsItem?
Qt 6.11 is out! See what's new in the release blog

How do you handle selection of QGraphicsItem?

Scheduled Pinned Locked Moved Unsolved General and Desktop
15 Posts 3 Posters 2.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ? A Former User

    I've these in hover and press events in the subclass of QGraphicsItem:

    void Slice::hoverEnterEvent(QGraphicsSceneHoverEvent*){
        qDebug() << "hoverEnterEvent" << isSelected();
        if(isSelected()) return;
        m_color = Qt::gray;
        moveBy(dx, dy);
        auto view = static_cast<PieView*>(scene()->parent());
        emit view->mouseOver(m_series);
    
    }
    void Slice::hoverLeaveEvent(QGraphicsSceneHoverEvent*){
        qDebug() << "hoverLeaveEvent" << isSelected();
        if(isSelected()) return;
        m_color = m_realColor;
        moveBy(-dx, -dy);
        auto view = static_cast<PieView*>(scene()->parent());
        emit view->mouseLeave();
    }
    void Slice::mousePressEvent(QGraphicsSceneMouseEvent *e){
        if(e->button() != Qt::LeftButton) return;
        if(isSelected()) {
            setSelected(false);
            qDebug() << "deselected" << scene()->selectedItems().size();
        }
        else {
            setSelected(true);
            qDebug() << "selected" << scene()->selectedItems().size();
        }
    }
    

    and here're the things I've done:

    x1.gif

    first sequence: mouse entered, pressed the button, released the button and left the item. In the output, I got:

    hoverEnterEvent false
    selected 1
    hoverLeaveEvent true
    

    Correct.

    second sequence: same as (1) and I got these:

    hoverEnterEvent true
    deselected 0
    hoverLeaveEvent true
    

    Incorrect!

    third sequence: mouse entered and left the item, without any press, and got these:

    hoverEnterEvent true
    hoverLeaveEvent true
    

    Incorrect, again!

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by
    #2

    @Emon-Haque
    I have not followed your code. But in each of these ...Event overrides you do not allow the event to proceed through to default handling (by calling base method), is that what is causing whatever your behaviour is?

    ? 1 Reply Last reply
    2
    • ? A Former User

      I've these in hover and press events in the subclass of QGraphicsItem:

      void Slice::hoverEnterEvent(QGraphicsSceneHoverEvent*){
          qDebug() << "hoverEnterEvent" << isSelected();
          if(isSelected()) return;
          m_color = Qt::gray;
          moveBy(dx, dy);
          auto view = static_cast<PieView*>(scene()->parent());
          emit view->mouseOver(m_series);
      
      }
      void Slice::hoverLeaveEvent(QGraphicsSceneHoverEvent*){
          qDebug() << "hoverLeaveEvent" << isSelected();
          if(isSelected()) return;
          m_color = m_realColor;
          moveBy(-dx, -dy);
          auto view = static_cast<PieView*>(scene()->parent());
          emit view->mouseLeave();
      }
      void Slice::mousePressEvent(QGraphicsSceneMouseEvent *e){
          if(e->button() != Qt::LeftButton) return;
          if(isSelected()) {
              setSelected(false);
              qDebug() << "deselected" << scene()->selectedItems().size();
          }
          else {
              setSelected(true);
              qDebug() << "selected" << scene()->selectedItems().size();
          }
      }
      

      and here're the things I've done:

      x1.gif

      first sequence: mouse entered, pressed the button, released the button and left the item. In the output, I got:

      hoverEnterEvent false
      selected 1
      hoverLeaveEvent true
      

      Correct.

      second sequence: same as (1) and I got these:

      hoverEnterEvent true
      deselected 0
      hoverLeaveEvent true
      

      Incorrect!

      third sequence: mouse entered and left the item, without any press, and got these:

      hoverEnterEvent true
      hoverLeaveEvent true
      

      Incorrect, again!

      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote on last edited by Pl45m4
      #3

      @Emon-Haque

      Do you call the base class' c'tor in Slice() while creating your Slice?
      Also, like @JonB said: Pass the event to the base class in your overriden functions (call the base event handler).
      E.g:

      void Slice::hoverEnterEvent(QGraphicsSceneHoverEvent* ev){
      // ....
      QGraphicsItem::hoverEnterEvent(ev);
      }
      

      Edit:

      Show your Slice constructor


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      ? 1 Reply Last reply
      1
      • JonBJ JonB

        @Emon-Haque
        I have not followed your code. But in each of these ...Event overrides you do not allow the event to proceed through to default handling (by calling base method), is that what is causing whatever your behaviour is?

        ? Offline
        ? Offline
        A Former User
        wrote on last edited by
        #4

        @JonB, First, added QGraphicsItem::...Event(e); in the beginning of each function. Second, removed those from beginning and added at the end of each function and third, in addition to those in the end of hoverEvents, added same before return. Didn't work!

        Pl45m4P 1 Reply Last reply
        0
        • ? A Former User

          @JonB, First, added QGraphicsItem::...Event(e); in the beginning of each function. Second, removed those from beginning and added at the end of each function and third, in addition to those in the end of hoverEvents, added same before return. Didn't work!

          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by Pl45m4
          #5

          @Emon-Haque

          The default implementation calls update(); otherwise it does nothing.

          • https://doc.qt.io/qt-5/qgraphicsitem.html#hoverEnterEvent

          The default implementation will update your item. When you dont call it, it could lead to unwanted bahavior.


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          ? 1 Reply Last reply
          0
          • Pl45m4P Pl45m4

            @Emon-Haque

            Do you call the base class' c'tor in Slice() while creating your Slice?
            Also, like @JonB said: Pass the event to the base class in your overriden functions (call the base event handler).
            E.g:

            void Slice::hoverEnterEvent(QGraphicsSceneHoverEvent* ev){
            // ....
            QGraphicsItem::hoverEnterEvent(ev);
            }
            

            Edit:

            Show your Slice constructor

            ? Offline
            ? Offline
            A Former User
            wrote on last edited by A Former User
            #6

            @Pl45m4, didn't have that in constructor. Tried this:

            Slice::Slice(float start, float sweep, QColor color, QRectF rect, PieSeries& series, QGraphicsItem *parent)
                : QGraphicsItem(parent), m_start(start), m_sweep(sweep), m_color(color), m_series(series)
            {...}
            

            with and without those base event calls mentioned in reply to @JonB. Didn't work.

            EDIT
            Here's the whole content:

            #define whats16 16
            Slice::Slice(float start, float sweep, QColor color, QRectF rect, PieSeries& series, QGraphicsItem *parent)
                : QGraphicsItem(parent), m_start(start), m_sweep(sweep), m_color(color), m_series(series){
                m_realColor = color;
                m_rect = rect;
                m_path = QPainterPath(QPointF(m_rect.width() / 2, m_rect.height() / 2));
                m_path.arcTo(m_rect, -m_start, -m_sweep);
                m_path.closeSubpath();
                dx = 10 * cos((m_start + m_sweep / 2) * M_PI / 180);
                dy = 10 * sin((m_start + m_sweep / 2) * M_PI / 180);
                float dimension = m_rect.width() + 2 * 20;
                m_boundingRect = QRectF(-20, -20, dimension, dimension);
                setAcceptHoverEvents(true);
                setFlag(QGraphicsItem::ItemIsSelectable);
            }
            

            EDIT

            and for the working example, you can get all code of different classes/struct here

            1 Reply Last reply
            0
            • Pl45m4P Pl45m4

              @Emon-Haque

              The default implementation calls update(); otherwise it does nothing.

              • https://doc.qt.io/qt-5/qgraphicsitem.html#hoverEnterEvent

              The default implementation will update your item. When you dont call it, it could lead to unwanted bahavior.

              ? Offline
              ? Offline
              A Former User
              wrote on last edited by
              #7

              @Pl45m4, with QGraphicsItem(parent) in the constructor, added update() at the end of each of those three event handlers with and without calling base QGraphicsItem::...Event(e). Didn't work

              1 Reply Last reply
              0
              • ? Offline
                ? Offline
                A Former User
                wrote on last edited by
                #8

                You can download the project from GitHub to avoid copy/paste and refactoring.

                Pl45m4P 1 Reply Last reply
                0
                • ? A Former User

                  You can download the project from GitHub to avoid copy/paste and refactoring.

                  Pl45m4P Offline
                  Pl45m4P Offline
                  Pl45m4
                  wrote on last edited by
                  #9

                  @Emon-Haque

                  I will try later with a minimal example to test the hover behavior.
                  Usually it should work, unless you have done something else wrong.

                  Does mouseOver do something with you item?
                  Better use qobject_cast to cast QObjects.

                  auto view = static_cast<PieView*>(scene()->parent());
                  emit view->mouseOver(m_series);


                  If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                  ~E. W. Dijkstra

                  ? 1 Reply Last reply
                  0
                  • Pl45m4P Pl45m4

                    @Emon-Haque

                    I will try later with a minimal example to test the hover behavior.
                    Usually it should work, unless you have done something else wrong.

                    Does mouseOver do something with you item?
                    Better use qobject_cast to cast QObjects.

                    auto view = static_cast<PieView*>(scene()->parent());
                    emit view->mouseOver(m_series);

                    ? Offline
                    ? Offline
                    A Former User
                    wrote on last edited by A Former User
                    #10

                    @Pl45m4, in mouseOver I add an ellipse (ellipse = new QGraphicsEllipseItem();) in the scene and that ellipse has a text (text = new QGraphicsTextItem(ellipse);):

                    void PieView::onMouseOver(PieSeries &s){
                        text->document()->clear();
                        auto cursor = QTextCursor(text->document());
                        QTextBlockFormat blockFormat;
                        QTextCharFormat charFormat;
                    
                        blockFormat.setAlignment(Qt::AlignHCenter);
                        charFormat.setForeground(Qt::darkGreen);
                        charFormat.setFontPointSize(16);
                        cursor.setBlockFormat(blockFormat);
                        cursor.setBlockCharFormat(charFormat);
                        cursor.insertText(s.name);
                    
                        charFormat.setForeground(Qt::red);
                        charFormat.setFontPointSize(14);
                        cursor.insertBlock(blockFormat, charFormat);
                        cursor.insertText(QString::number(s.value));
                    
                        charFormat.setForeground(Qt::black);
                        charFormat.setFontPointSize(12);
                        cursor.insertBlock(blockFormat, charFormat);
                        cursor.insertText(QString::number(s.value / m_total * 100) + "%");
                    
                        text->setY(ellipse->boundingRect().center().y() - text->boundingRect().height()/2);
                        scene()->addItem(ellipse);
                    }
                    

                    and I remove that onMouseLeave: void PieView::onMouseLeave(){ scene()->removeItem(ellipse); }. PieView is the subclass of QGraphicsView.

                    EDIT
                    Will change that static to qobject cast later. Thanks for the reminder.

                    JonBJ 1 Reply Last reply
                    0
                    • ? A Former User

                      @Pl45m4, in mouseOver I add an ellipse (ellipse = new QGraphicsEllipseItem();) in the scene and that ellipse has a text (text = new QGraphicsTextItem(ellipse);):

                      void PieView::onMouseOver(PieSeries &s){
                          text->document()->clear();
                          auto cursor = QTextCursor(text->document());
                          QTextBlockFormat blockFormat;
                          QTextCharFormat charFormat;
                      
                          blockFormat.setAlignment(Qt::AlignHCenter);
                          charFormat.setForeground(Qt::darkGreen);
                          charFormat.setFontPointSize(16);
                          cursor.setBlockFormat(blockFormat);
                          cursor.setBlockCharFormat(charFormat);
                          cursor.insertText(s.name);
                      
                          charFormat.setForeground(Qt::red);
                          charFormat.setFontPointSize(14);
                          cursor.insertBlock(blockFormat, charFormat);
                          cursor.insertText(QString::number(s.value));
                      
                          charFormat.setForeground(Qt::black);
                          charFormat.setFontPointSize(12);
                          cursor.insertBlock(blockFormat, charFormat);
                          cursor.insertText(QString::number(s.value / m_total * 100) + "%");
                      
                          text->setY(ellipse->boundingRect().center().y() - text->boundingRect().height()/2);
                          scene()->addItem(ellipse);
                      }
                      

                      and I remove that onMouseLeave: void PieView::onMouseLeave(){ scene()->removeItem(ellipse); }. PieView is the subclass of QGraphicsView.

                      EDIT
                      Will change that static to qobject cast later. Thanks for the reminder.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #11

                      @Emon-Haque
                      Just one quickie: that pie chart/view does not use any QGraphicsItemGroup does it?

                      ? 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @Emon-Haque
                        Just one quickie: that pie chart/view does not use any QGraphicsItemGroup does it?

                        ? Offline
                        ? Offline
                        A Former User
                        wrote on last edited by A Former User
                        #12

                        @JonB, no, it doesn't use any group. In the PieView, QGriphicsView, constructor I initialize the ellipse and text AND PieView has a function makePie where I add slice. Here's the constructor:

                        PieView::PieView(QWidget *parent) : QGraphicsView(parent){
                            auto scene = new QGraphicsScene(this);
                            setScene(scene);
                            setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                            setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                            ellipse = new QGraphicsEllipseItem();
                            ellipse->setBrush(Qt::white);
                            ellipse->setPen(Qt::NoPen);
                            ellipse->setAcceptHoverEvents(false);
                            text = new QGraphicsTextItem(ellipse);
                            text->setAcceptHoverEvents(false);
                            connect(this, &PieView::mouseOver, this, &PieView::onMouseOver);
                            connect(this, &PieView::mouseLeave, this, &PieView::onMouseLeave);
                        }
                        

                        and here's makePie:

                        void PieView::makePie(QVector<PieSeries>& series){
                            scene()->clear();
                            m_total = 0;
                            float startAngle = 0, spanAngle;
                            for (int i = 0; i < series.size(); i++) m_total += series[i].value;
                            QRandomGenerator rand;
                            auto rect = QRectF(0,0, 200,200);
                            for (int i = 0; i < series.size(); i++){
                                spanAngle = series[i].value / m_total * 360;
                                auto color = QColor::fromRgb(rand.global()->bounded(0,255), rand.global()->bounded(0,255), rand.global()->bounded(0,255));
                                auto slice = new Slice(startAngle, spanAngle, color, rect, series[i]);
                                scene()->addItem(slice);
                                startAngle += spanAngle;
                            }
                            auto eRect = QRectF(QPoint(sceneRect().center().x() - 75, sceneRect().center().y() - 75), QSize(150,150));
                            ellipse->setRect(eRect);
                            text->setTextWidth(rect.width());
                        }
                        
                        1 Reply Last reply
                        0
                        • ? Offline
                          ? Offline
                          A Former User
                          wrote on last edited by A Former User
                          #13

                          Problem is the base calls. Probably, there's something in the base mouseReleaseEvent that created the issue. I've taken it back to the original state, removed base constructor, update and base::...Event calls and added an empty mouseReleaseEvent like this:

                          void Slice::mousePressEvent(QGraphicsSceneMouseEvent *e){
                              if(e->button() != Qt::LeftButton) return;
                              if(isSelected()) setSelected(false);
                              else setSelected(true);
                          }
                          void Slice::mouseReleaseEvent(QGraphicsSceneMouseEvent*){}
                          

                          Now it behaves normally:

                          x2.gif

                          One thing that I couldn't figure out yet is: when I first hover over a slice, rest of the slices are displaced. In the animation see, when mouse entered the bottom right slice for the first time, other two slices moved to the left! This happens only once with 3 slices. Why does it move?

                          Updated the github repo with these changes.

                          Pl45m4P 1 Reply Last reply
                          0
                          • ? A Former User

                            Problem is the base calls. Probably, there's something in the base mouseReleaseEvent that created the issue. I've taken it back to the original state, removed base constructor, update and base::...Event calls and added an empty mouseReleaseEvent like this:

                            void Slice::mousePressEvent(QGraphicsSceneMouseEvent *e){
                                if(e->button() != Qt::LeftButton) return;
                                if(isSelected()) setSelected(false);
                                else setSelected(true);
                            }
                            void Slice::mouseReleaseEvent(QGraphicsSceneMouseEvent*){}
                            

                            Now it behaves normally:

                            x2.gif

                            One thing that I couldn't figure out yet is: when I first hover over a slice, rest of the slices are displaced. In the animation see, when mouse entered the bottom right slice for the first time, other two slices moved to the left! This happens only once with 3 slices. Why does it move?

                            Updated the github repo with these changes.

                            Pl45m4P Offline
                            Pl45m4P Offline
                            Pl45m4
                            wrote on last edited by Pl45m4
                            #14

                            @Emon-Haque said in How do you handle selection of QGraphicsItem?:

                            when I first hover over a slice, rest of the slices are displaced. In the animation see, when mouse entered the bottom right slice for the first time, other two slices moved to the left! This happens only once with 3 slices. Why does it move?

                            This seem to be a miscalculation of your slice coordinates.
                            When you hover the slice, it moves a bit out of the pie chart and the rest seems to follow. So the whole pie moves by X to the right.
                            Can't tell where exactly but I would check the coordinates where the pie is drawn and how the relation between the "highlighted" (moved out) slice and the rest of the pie slices works.

                            Edit:

                            Or the whole pie "jumps" to the right in your scene to react on the geometry change... You need to test it. Do you center your pie in your scene?


                            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                            ~E. W. Dijkstra

                            ? 1 Reply Last reply
                            0
                            • Pl45m4P Pl45m4

                              @Emon-Haque said in How do you handle selection of QGraphicsItem?:

                              when I first hover over a slice, rest of the slices are displaced. In the animation see, when mouse entered the bottom right slice for the first time, other two slices moved to the left! This happens only once with 3 slices. Why does it move?

                              This seem to be a miscalculation of your slice coordinates.
                              When you hover the slice, it moves a bit out of the pie chart and the rest seems to follow. So the whole pie moves by X to the right.
                              Can't tell where exactly but I would check the coordinates where the pie is drawn and how the relation between the "highlighted" (moved out) slice and the rest of the pie slices works.

                              Edit:

                              Or the whole pie "jumps" to the right in your scene to react on the geometry change... You need to test it. Do you center your pie in your scene?

                              ? Offline
                              ? Offline
                              A Former User
                              wrote on last edited by
                              #15

                              @Pl45m4, at that time I didn't have the call setSceneRect(....). With that line, now it doesn't move.

                              1 Reply Last reply
                              1

                              • Login

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt
                              • Unsolved