Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Unsolved QStyledItemDelegate paint event on cell (not row) hover

    General and Desktop
    2
    6
    560
    Loading More Posts
    • 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.
    • D
      DaveK 0 last edited by

      I have a custom QStyledItemDelegate that paints a QPixmap in a particular column. When that cell is hovered over with the mouse, I would like to paint it differently.

      Below is my paint event, which does paint the cell correctly when not State_MouseOver. However, it changes the color when I hover anywhere on the row. How can I make it change only when the mouse is hovering over the cell with the pixmap in it?

      void myDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
      {
          Q_ASSERT(index.isValid());
      
          switch(index.column()) {
              case DAY_COLUMN:
              {
                  QSize btnSize = QSize(option.rect.height() * .9, option.rect.height() * .9);
                  QRect r = option.rect;
                  int x = r.right() - btnSize.width() - 10;
                  int y = r.top();
                  QRect btnRect = QRect(x, y, btnSize.width(), btnSize.height());
      
                  QPixmap pixmap(":/icons/edit.png");
      
                  // If hovered over, change color.
                  if(option.state & QStyle::State_MouseOver) {
                      auto mask = pixmap.createMaskFromColor(QColor("Black"), Qt::MaskOutColor);
                      pixmap.fill(QColor("Red"));
                      pixmap.setMask(mask);
                  }
      
                  painter->drawPixmap(btnRect, pixmap, pixmap.rect());
      
                  return;
              }
      
              /*.... draw other column(s) as appropriate ...*/
          }
      
      }
      

      I'm using this delegate on all rows withing a QTreeView.
      Qt 5.12

      1 Reply Last reply Reply Quote 0
      • sierdzio
        sierdzio Moderators last edited by

        I have not tested this, but you can probably get the styled widget like this:

        const auto widget = qobject_cast<QWidget*>(option.styleObject);
        

        Then you can probably check if mouse is inside of it using:

        widget->rect().contains(mapFromGlobal(QCursor::pos()));
        

        (Z(:^

        1 Reply Last reply Reply Quote 0
        • D
          DaveK 0 last edited by

          Thanks, that certainly seems to be on the right track. mapFromGlobal was not available within QStyledItemDelegate, so I used the created widget to call mapFromGlobal:

          widget->rect().contains(widget->mapFromGlobal(QCursor::pos()));
          

          However, the widget->rect() that is returned, is that of the treeView as a whole, not the cell. So it is always true, any time the cursor is inside the treeView.

          1 Reply Last reply Reply Quote 0
          • sierdzio
            sierdzio Moderators last edited by

            Hm, right. The delegates themselves are not QObjects, only QPainDevices. Well then, you can maybe get at this from the other side:

            • map cursor position to widget coordinates (like you do above)
            • then map option.rect to widget coordinates
            • then check if position is within the rect

            No idea if it will work, but maybe...

            (Z(:^

            1 Reply Last reply Reply Quote 0
            • D
              DaveK 0 last edited by

              @sierdzio I was about to reply with something like that - I think this is close. The cell now changes color only when you hover over it, BUT it does not repaint if you move between cells within the same row. So you can move vertically between rows, and the cell will only change colors when you are over the pixmap - BUT if you move horizontally off of it, and back on, it does not repaint (and stays black).

              Is there a way I can force a re-paint when moving between columns?

              const auto widget = qobject_cast<QWidget*>(option.styleObject);
              auto cursorX = widget->mapFromGlobal(QCursor::pos()).x();
              
              // If hovered over, change color.
              if(option.state & QStyle::State_MouseOver && btnRect.contains(cursorX, btnRect.y())) {
                  auto mask = pixmap.createMaskFromColor(QColor("Black"), Qt::MaskOutColor);
                  pixmap.fill(QColor("Red"));
                  pixmap.setMask(mask);
              }
              
              painter->drawPixmap(btnRect, pixmap, pixmap.rect());
              
              1 Reply Last reply Reply Quote 0
              • sierdzio
                sierdzio Moderators last edited by

                Is paint() not called at all when you move horizontally? Check with some debug messages.

                Also, print btnRect. cursorX, btnRect.y(), maybe it will offer some clues, perhaps paint() is called, but always thinks cursorX is within the rectangle?

                Is there a way I can force a re-paint when moving between columns?

                There must be some way, yeah. I'm not sure how to do it yet, though.

                (Z(:^

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post