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.
  • ? Offline
    ? Offline
    A Former User
    wrote on last edited by
    #1

    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 Pl45m4P 2 Replies Last reply
    0
    • ? 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 Online
      JonBJ Online
      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 Online
                        JonBJ Online
                        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