Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Mouse hover on QRect not working as expected
Forum Updated to NodeBB v4.3 + New Features

Mouse hover on QRect not working as expected

Scheduled Pinned Locked Moved Solved General and Desktop
20 Posts 5 Posters 3.4k 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 A Former User
    #1

    Hey,

    I have a prolem with mouse hover. I have created a QListView with a custom delegat subclassed from QStyledItemDelegate. I following created:

    void ToggleListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    	QString text = index.data(Qt::DisplayRole).toString();
    	QRect original = option.rect;
    	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0); // QSize mButtonSize = QSize(40,40);
    	QRect label = original.adjusted(0,0, -mButtonSize.width(),0);
    	painter->drawText(label, Qt::AlignLeft, text);
    
    	QIcon icon = QIcon(":/icons/trash_black.png");
    	icon.paint(painter, button);
    
    	const auto widget = qobject_cast<QWidget*>(option.styleObject);
    
    	QPoint cursor = QCursor::pos();
    	QPoint position = widget->mapFromGlobal(cursor);
    
    	if(button.contains(position)){
    		bool hover = option.state & QStyle::State_MouseOver;
    		if(hover){
    			icon = QIcon(":/icons/trash_red.png");
    			icon.paint(painter, button);
    		}
    	}
    	painter->save();
    	painter->restore();
    }
    

    image.gif

    As you can see in the animated graphic it also works when I hover over the icon it turns red. But only if I move from top to bottom. If I move from the bottom to the top, the icon is not red. Likewise if I move out of the area to the left, the icon does not turn black again.

    Does anyone have an idea? Why hover is false if I move from bottom to top or from the icon to the left side?

    Thanks

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

      A very big thanks goes to @jeremy_k . Your tip and the code example was worth its weight in gold. Thank you!

      Now my code looks like this:
      Delegate:

      void ToggleListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
      {
      	QString text = index.data(Qt::DisplayRole).toString();
      	QRect original = option.rect;
      	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
      	QRect label = original.adjusted(0,0, -mButtonSize.width(),0);
      	painter->drawText(label, Qt::AlignLeft, text);
      
      	QIcon icon = QIcon(":/icons/trash_black.png");
      	icon.paint(painter, button);
      
      	const auto widget = qobject_cast<ToggleListView*>(option.styleObject);
      
      	QPoint cursor = QCursor::pos();
      	QPoint position = widget->viewport()->mapFromGlobal(cursor);
      
      	if(button.contains(position)){
      		const bool hover = option.state & QStyle::State_MouseOver;
      		if(hover){
      			icon = QIcon(":/icons/trash_red.png");
      			icon.paint(painter, button);
      		}
      	}
      	painter->save();
      	painter->restore();
      }
      

      mouseMoveEvent:

      void ToggleListView::mouseMoveEvent(QMouseEvent *event)
      {
      	QPoint position = event->pos();
      	QModelIndex index = indexAt(position);
      	QRect original = visualRect(index);
      	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
      
      	bool currentButtonState = button.contains(position);
      
      	if(index != mPreviousIndex){
      		if(mPreviousIndex.isValid())
      			update(mPreviousIndex);
      		if(index.isValid())
      			update(index);
      	} else if(currentButtonState != mPreviousButtonState){
      		update(index);
      	}
      	mPreviousIndex = index;
      	mPreviousButtonState = currentButtonState;
      }
      
      jeremy_kJ 1 Reply Last reply
      0
      • Christian EhrlicherC Online
        Christian EhrlicherC Online
        Christian Ehrlicher
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Print out the values of button and position to see what's going on. I would guess paint is not called since there is no need for a repaint.

        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
        Visit the Qt Academy at https://academy.qt.io/catalog

        ? 1 Reply Last reply
        0
        • Christian EhrlicherC Christian Ehrlicher

          Print out the values of button and position to see what's going on. I would guess paint is not called since there is no need for a repaint.

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

          @Christian-Ehrlicher

          Thank you for your reply. I have taken my screen again. The output is underneath:

          image2.gif

          ---------------------
          Button:  QRect(280,0 40x28)
          Position:  QPoint(305,2)
          ---------------------
          Button:  QRect(280,28 40x28)
          Position:  QPoint(306,30)
          ---------------------
          Button:  QRect(280,56 40x28)
          Position:  QPoint(308,58)
          ---------------------
          Button:  QRect(280,56 40x28)
          Position:  QPoint(308,57)
          ---------------------
          Button:  QRect(280,28 40x28)
          Position:  QPoint(305,29)
          ---------------------
          Button:  QRect(280,0 40x28)
          Position:  QPoint(305,1)
          

          My code part:

          	if(button.contains(position)){
          
          		qDebug() << "---------------------";
          		qDebug() << "Button: " << button;
          		qDebug() << "Position: " << position;
          
          		bool hover = option.state & QStyle::State_MouseOver;
          		if(hover){
          			icon = QIcon(":/icons/trash_red.png");
          			icon.paint(painter, button);
          		}
          	}
          
          Christian EhrlicherC 1 Reply Last reply
          0
          • ? A Former User

            @Christian-Ehrlicher

            Thank you for your reply. I have taken my screen again. The output is underneath:

            image2.gif

            ---------------------
            Button:  QRect(280,0 40x28)
            Position:  QPoint(305,2)
            ---------------------
            Button:  QRect(280,28 40x28)
            Position:  QPoint(306,30)
            ---------------------
            Button:  QRect(280,56 40x28)
            Position:  QPoint(308,58)
            ---------------------
            Button:  QRect(280,56 40x28)
            Position:  QPoint(308,57)
            ---------------------
            Button:  QRect(280,28 40x28)
            Position:  QPoint(305,29)
            ---------------------
            Button:  QRect(280,0 40x28)
            Position:  QPoint(305,1)
            

            My code part:

            	if(button.contains(position)){
            
            		qDebug() << "---------------------";
            		qDebug() << "Button: " << button;
            		qDebug() << "Position: " << position;
            
            		bool hover = option.state & QStyle::State_MouseOver;
            		if(hover){
            			icon = QIcon(":/icons/trash_red.png");
            			icon.paint(painter, button);
            		}
            	}
            
            Christian EhrlicherC Online
            Christian EhrlicherC Online
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #4

            @Gabber Print the output before your check to see what value it has when it doesn't work and if there is really a paint event at all in this case.
            Maybe override mouseMoveEvent() and call update() in there to force a redraw.

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            ? 1 Reply Last reply
            0
            • Christian EhrlicherC Christian Ehrlicher

              @Gabber Print the output before your check to see what value it has when it doesn't work and if there is really a paint event at all in this case.
              Maybe override mouseMoveEvent() and call update() in there to force a redraw.

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

              @Christian-Ehrlicher

              I put the qDebug() outputs, before the if query. For simplicity, I have only 3 items displayed in the QListView. Below are again the output to the image.

              image3.gif

              The qDebug() output:

              Name:  "722"
              Name:  "5456"
              Name:  "6429"
              ---------------------
              Button:  QRect(294,0 40x28)
              Position:  QPoint(93,-85)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(93,-85)
              ---------------------
              Button:  QRect(294,56 40x28)
              Position:  QPoint(93,-85)
              ---------------------
              Button:  QRect(294,0 40x28)
              Position:  QPoint(313,2)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(313,2)
              ---------------------
              Button:  QRect(294,56 40x28)
              Position:  QPoint(313,2)
              ---------------------
              Button:  QRect(294,0 40x28)
              Position:  QPoint(317,30)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(317,30)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(317,58)
              ---------------------
              Button:  QRect(294,56 40x28)
              Position:  QPoint(317,58)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(317,57)
              ---------------------
              Button:  QRect(294,56 40x28)
              Position:  QPoint(317,57)
              ---------------------
              Button:  QRect(294,0 40x28)
              Position:  QPoint(317,29)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(317,29)
              ---------------------
              Button:  QRect(294,0 40x28)
              Position:  QPoint(329,1)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(329,1)
              ---------------------
              Button:  QRect(294,56 40x28)
              Position:  QPoint(329,1)
              ---------------------
              Button:  QRect(294,0 40x28)
              Position:  QPoint(803,-425)
              ---------------------
              Button:  QRect(294,28 40x28)
              Position:  QPoint(803,-425)
              ---------------------
              Button:  QRect(294,56 40x28)
              Position:  QPoint(803,-425)
              

              Can you see why it doesn't work?

              I am very grateful for your help!

              Christian EhrlicherC 1 Reply Last reply
              0
              • ? A Former User

                @Christian-Ehrlicher

                I put the qDebug() outputs, before the if query. For simplicity, I have only 3 items displayed in the QListView. Below are again the output to the image.

                image3.gif

                The qDebug() output:

                Name:  "722"
                Name:  "5456"
                Name:  "6429"
                ---------------------
                Button:  QRect(294,0 40x28)
                Position:  QPoint(93,-85)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(93,-85)
                ---------------------
                Button:  QRect(294,56 40x28)
                Position:  QPoint(93,-85)
                ---------------------
                Button:  QRect(294,0 40x28)
                Position:  QPoint(313,2)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(313,2)
                ---------------------
                Button:  QRect(294,56 40x28)
                Position:  QPoint(313,2)
                ---------------------
                Button:  QRect(294,0 40x28)
                Position:  QPoint(317,30)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(317,30)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(317,58)
                ---------------------
                Button:  QRect(294,56 40x28)
                Position:  QPoint(317,58)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(317,57)
                ---------------------
                Button:  QRect(294,56 40x28)
                Position:  QPoint(317,57)
                ---------------------
                Button:  QRect(294,0 40x28)
                Position:  QPoint(317,29)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(317,29)
                ---------------------
                Button:  QRect(294,0 40x28)
                Position:  QPoint(329,1)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(329,1)
                ---------------------
                Button:  QRect(294,56 40x28)
                Position:  QPoint(329,1)
                ---------------------
                Button:  QRect(294,0 40x28)
                Position:  QPoint(803,-425)
                ---------------------
                Button:  QRect(294,28 40x28)
                Position:  QPoint(803,-425)
                ---------------------
                Button:  QRect(294,56 40x28)
                Position:  QPoint(803,-425)
                

                Can you see why it doesn't work?

                I am very grateful for your help!

                Christian EhrlicherC Online
                Christian EhrlicherC Online
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #6

                @Gabber said in Mouse hover on QRect not working as expected:

                Position: QPoint(803,-425)

                This looks strange to me. SInce it operates on a QListWidget please cast your widget to it and work on viewport() when you map the coordinate.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                ? 1 Reply Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  @Gabber said in Mouse hover on QRect not working as expected:

                  Position: QPoint(803,-425)

                  This looks strange to me. SInce it operates on a QListWidget please cast your widget to it and work on viewport() when you map the coordinate.

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

                  @Christian-Ehrlicher

                  I tried this with the following:

                  	const auto widget = qobject_cast<QListWidget*>(option.styleObject);
                  
                  	QPoint cursor = QCursor::pos();
                  	QPoint position = widget->viewport()->mapFromGlobal(cursor);
                  

                  But I get a Segmentation fault at QPoint position.

                  Edit:

                  @Christian-Ehrlicher said in Mouse hover on QRect not working as expected:

                  Position: QPoint(803,-425)

                  I think this came about when I stopped my screen recording.

                  JonBJ 1 Reply Last reply
                  0
                  • ? A Former User

                    @Christian-Ehrlicher

                    I tried this with the following:

                    	const auto widget = qobject_cast<QListWidget*>(option.styleObject);
                    
                    	QPoint cursor = QCursor::pos();
                    	QPoint position = widget->viewport()->mapFromGlobal(cursor);
                    

                    But I get a Segmentation fault at QPoint position.

                    Edit:

                    @Christian-Ehrlicher said in Mouse hover on QRect not working as expected:

                    Position: QPoint(803,-425)

                    I think this came about when I stopped my screen recording.

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

                    @Gabber said in Mouse hover on QRect not working as expected:

                    But I get a Segmentation fault at QPoint position.

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

                    Did you verify the return result from the qobject_cast<>()??

                    ? 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @Gabber said in Mouse hover on QRect not working as expected:

                      But I get a Segmentation fault at QPoint position.

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

                      Did you verify the return result from the qobject_cast<>()??

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

                      @JonB @Christian-Ehrlicher
                      I got a little further. Top to bottom and bottom to top now works. For this I have changed the following line from:

                      QPoint position = widget->mapFromGlobal(cursor);
                      

                      to

                      QPoint position = widget->viewport()->mapFromGlobal(cursor);
                      

                      But how do I get this to work when I move from the trash icon to the text and back? Any ideas?

                      1 Reply Last reply
                      0
                      • SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #10

                        Hi,

                        Test whether the point is in the rectangle where the trash icon is drawn.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        ? 1 Reply Last reply
                        0
                        • SGaistS SGaist

                          Hi,

                          Test whether the point is in the rectangle where the trash icon is drawn.

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

                          @SGaist said in Mouse hover on QRect not working as expected:

                          Test whether the point is in the rectangle where the trash icon is drawn.

                          I have colored the whole thing briefly. When I move the mouse from the red rectangle to the yellow rectangle, I want the trash can icon to change back to black. If I move from yellow to red it should become red again.

                          5752699a-1138-4072-88e8-de9629978ede-image.png

                          The Paint method from the delegate is not called again here, if I move from the red to the yellow rectangle. I don't know exactly how this works with the paint stuff. Do I have to overwrite the paintEvent or work with the mouseMoveEvent or something else?

                          Thanks for the help!

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

                            @Christian-Ehrlicher @JonB @SGaist

                            I have found a way how everything works now. Here is my solution.

                            My paint function from custom delegate:

                            void ToggleListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                            {
                            
                            	QString text = index.data(Qt::DisplayRole).toString();
                            	QRect original = option.rect;
                            	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
                            	QRect label = original.adjusted(0,0, -mButtonSize.width(),0);
                            	painter->drawText(label, Qt::AlignLeft, text);
                            
                            	QIcon icon = QIcon(":/icons/trash_black.png");
                            	icon.paint(painter, button);
                            
                            	const auto widget = qobject_cast<ToggleListView*>(option.styleObject);
                            
                            	QPoint cursor = QCursor::pos();
                            	QPoint position = widget->viewport()->mapFromGlobal(cursor);
                            
                            	const bool selected = option.state & QStyle::State_Selected;
                            
                            	if(selected){
                            		painter->fillRect(original, option.palette.highlight());
                            		painter->drawText(label, Qt::AlignLeft, text);
                            		icon.paint(painter, button);
                            	}
                            	
                            	if(button.contains(position)){
                            		const bool hover = option.state & QStyle::State_MouseOver;
                            		if(hover){
                            			icon = QIcon(":/icons/trash_red.png");
                            			icon.paint(painter, button);
                            		}
                            	}
                            	painter->save();
                            	painter->restore();
                            
                            }
                            

                            My custom lisstview:

                            ToggleListView::ToggleListView(QWidget *parent): QListView(parent) {
                            	this->setMouseTracking(true);
                            }
                            
                            void ToggleListView::mouseMoveEvent(QMouseEvent *event)
                            {
                            	QModelIndex index = indexAt(event->pos());
                            	QPoint position = event->pos();
                            	QRect original = visualRect(index);
                            	QRect label = original.adjusted(0,0, -mButtonSize.width(),0);
                            
                            	if(label.contains(position)){
                            		this->viewport()->repaint();
                            	} else {
                            		this->viewport()->repaint();
                            	}
                            }
                            

                            Is it overkill to redraw the whole thing every time? Do you have a better idea or a suggestion for improvement?

                            Thanks for your help!

                            1 Reply Last reply
                            0
                            • jeremy_kJ Offline
                              jeremy_kJ Offline
                              jeremy_k
                              wrote on last edited by jeremy_k
                              #13

                              I think the trick for getting repaints for hover events in a view is to turn on the QA_Hover attribute for the viewport.

                              #include <QApplication>
                              #include <QListView>
                              #include <QStyledItemDelegate>
                              #include <QStringListModel>
                              #include <QDebug>
                              
                              class Delegate: public QStyledItemDelegate {
                                  Q_OBJECT
                              public:
                                  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
                                  {
                                      qDebug() << "paint" << index;
                                      QStyledItemDelegate::paint(painter, option, index);
                                  }
                              };
                              
                              int main(int argc, char *argv[])
                              {
                                  QApplication a(argc, argv);
                                  QListView lv;
                                  lv.viewport()->setAttribute(Qt::WA_Hover);
                                  lv.setItemDelegate(new Delegate);
                                  QStringListModel model({"first", "second", "third"});
                                  lv.setModel(&model);
                                  lv.show();
                                  return a.exec();
                              }
                              
                              #include "main.moc"
                              

                              Asking a question about code? http://eel.is/iso-c++/testcase/

                              jeremy_kJ 1 Reply Last reply
                              0
                              • jeremy_kJ jeremy_k

                                I think the trick for getting repaints for hover events in a view is to turn on the QA_Hover attribute for the viewport.

                                #include <QApplication>
                                #include <QListView>
                                #include <QStyledItemDelegate>
                                #include <QStringListModel>
                                #include <QDebug>
                                
                                class Delegate: public QStyledItemDelegate {
                                    Q_OBJECT
                                public:
                                    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
                                    {
                                        qDebug() << "paint" << index;
                                        QStyledItemDelegate::paint(painter, option, index);
                                    }
                                };
                                
                                int main(int argc, char *argv[])
                                {
                                    QApplication a(argc, argv);
                                    QListView lv;
                                    lv.viewport()->setAttribute(Qt::WA_Hover);
                                    lv.setItemDelegate(new Delegate);
                                    QStringListModel model({"first", "second", "third"});
                                    lv.setModel(&model);
                                    lv.show();
                                    return a.exec();
                                }
                                
                                #include "main.moc"
                                
                                jeremy_kJ Offline
                                jeremy_kJ Offline
                                jeremy_k
                                wrote on last edited by
                                #14

                                @jeremy_k said in Mouse hover on QRect not working as expected:

                                I think the trick for getting repaints for hover events in a view is to turn on the QA_Hover attribute for the viewport.

                                A more straightforward solution may be to use something like:

                                    view->setMouseTracking(true);
                                    QObject::connect(view, &QAbstractItemView::entered, [] (QModelIndex *index) {
                                        // Reset the previous index if any, and then do something with this index
                                        });
                                

                                Asking a question about code? http://eel.is/iso-c++/testcase/

                                ? 1 Reply Last reply
                                0
                                • jeremy_kJ jeremy_k

                                  @jeremy_k said in Mouse hover on QRect not working as expected:

                                  I think the trick for getting repaints for hover events in a view is to turn on the QA_Hover attribute for the viewport.

                                  A more straightforward solution may be to use something like:

                                      view->setMouseTracking(true);
                                      QObject::connect(view, &QAbstractItemView::entered, [] (QModelIndex *index) {
                                          // Reset the previous index if any, and then do something with this index
                                          });
                                  
                                  ? Offline
                                  ? Offline
                                  A Former User
                                  wrote on last edited by
                                  #15

                                  @jeremy_k

                                  Thank you for your reply. I had tried the whole thing with the hover attribute before, but it didn't work. Because as described above I have to change the icon when I go from the red to the yellow area and vice versa. This works with the above solution using mouseMoveEvent.

                                  Thanks for your tip anyway!

                                  jeremy_kJ 1 Reply Last reply
                                  0
                                  • ? A Former User

                                    @jeremy_k

                                    Thank you for your reply. I had tried the whole thing with the hover attribute before, but it didn't work. Because as described above I have to change the icon when I go from the red to the yellow area and vice versa. This works with the above solution using mouseMoveEvent.

                                    Thanks for your tip anyway!

                                    jeremy_kJ Offline
                                    jeremy_kJ Offline
                                    jeremy_k
                                    wrote on last edited by jeremy_k
                                    #16

                                    I missed the problem revision. Thanks for pointing it out.

                                    The mouseMoveEvent() implementation above has a few obvious opportunities for improvement in efficiency. This is going to repaint the entire visible portion of the view on every move, even if the cursor remains in the same portion of the same delegate instance.

                                    	if(label.contains(position)){
                                    		this->viewport()->repaint();
                                    	} else {
                                    		this->viewport()->repaint();
                                    	}
                                    

                                    This is a tautology. If nothing else, the code can be simplified by removing the condition. The QRect::contains() is const, so the compiler may already be optimizing the test out.

                                    Repainting can be limited to the impacted indexes by using QAbstractItemView::update(). Cache the previous index and button highlight state to detect when a repaint isn't necessary at all.

                                    if (currentIndex != this->previousIndex) {
                                        if (this->previousIndex.isValid())
                                            this->update(this->previousIndex);
                                        if (currentIndex.isValid())
                                            this->update(currentIndex);
                                    }
                                    else if (currentButtonState != this->previousButtonState) {
                                        this->update(currentIndex);
                                    }
                                    this->previousIndex = currentIndex;
                                    this->previousButtonState = currentButtonState;
                                    
                                    

                                    Asking a question about code? http://eel.is/iso-c++/testcase/

                                    ? 1 Reply Last reply
                                    0
                                    • jeremy_kJ jeremy_k

                                      I missed the problem revision. Thanks for pointing it out.

                                      The mouseMoveEvent() implementation above has a few obvious opportunities for improvement in efficiency. This is going to repaint the entire visible portion of the view on every move, even if the cursor remains in the same portion of the same delegate instance.

                                      	if(label.contains(position)){
                                      		this->viewport()->repaint();
                                      	} else {
                                      		this->viewport()->repaint();
                                      	}
                                      

                                      This is a tautology. If nothing else, the code can be simplified by removing the condition. The QRect::contains() is const, so the compiler may already be optimizing the test out.

                                      Repainting can be limited to the impacted indexes by using QAbstractItemView::update(). Cache the previous index and button highlight state to detect when a repaint isn't necessary at all.

                                      if (currentIndex != this->previousIndex) {
                                          if (this->previousIndex.isValid())
                                              this->update(this->previousIndex);
                                          if (currentIndex.isValid())
                                              this->update(currentIndex);
                                      }
                                      else if (currentButtonState != this->previousButtonState) {
                                          this->update(currentIndex);
                                      }
                                      this->previousIndex = currentIndex;
                                      this->previousButtonState = currentButtonState;
                                      
                                      
                                      ? Offline
                                      ? Offline
                                      A Former User
                                      wrote on last edited by
                                      #17

                                      @jeremy_k
                                      Thank you for pointing this out. Can you explain your example in more detail? For example, I don't understand how to get the "currentButtonState" or "previousButtonState". I don't have a "real" button, but only two QRects, one representing the "Button" and the other the "Label/Text".

                                      How do I implement this in the mouseMoveEvent function of the custom QListView?

                                      jeremy_kJ 1 Reply Last reply
                                      0
                                      • ? A Former User

                                        @jeremy_k
                                        Thank you for pointing this out. Can you explain your example in more detail? For example, I don't understand how to get the "currentButtonState" or "previousButtonState". I don't have a "real" button, but only two QRects, one representing the "Button" and the other the "Label/Text".

                                        How do I implement this in the mouseMoveEvent function of the custom QListView?

                                        jeremy_kJ Offline
                                        jeremy_kJ Offline
                                        jeremy_k
                                        wrote on last edited by
                                        #18

                                        @Gabber said in Mouse hover on QRect not working as expected:

                                        @jeremy_k
                                        Thank you for pointing this out. Can you explain your example in more detail? For example, I don't understand how to get the "currentButtonState" or "previousButtonState". I don't have a "real" button, but only two QRects, one representing the "Button" and the other the "Label/Text".

                                        How do I implement this in the mouseMoveEvent function of the custom QListView?

                                        Use the logic already present in ToggleListDelegate::paint() and ToggleListView::mouseMoveEvent().
                                        eg: bool currentButtonState = button.contains(viewport->mapFromGlobal(QCursor::pos()))

                                        Asking a question about code? http://eel.is/iso-c++/testcase/

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

                                          A very big thanks goes to @jeremy_k . Your tip and the code example was worth its weight in gold. Thank you!

                                          Now my code looks like this:
                                          Delegate:

                                          void ToggleListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                                          {
                                          	QString text = index.data(Qt::DisplayRole).toString();
                                          	QRect original = option.rect;
                                          	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
                                          	QRect label = original.adjusted(0,0, -mButtonSize.width(),0);
                                          	painter->drawText(label, Qt::AlignLeft, text);
                                          
                                          	QIcon icon = QIcon(":/icons/trash_black.png");
                                          	icon.paint(painter, button);
                                          
                                          	const auto widget = qobject_cast<ToggleListView*>(option.styleObject);
                                          
                                          	QPoint cursor = QCursor::pos();
                                          	QPoint position = widget->viewport()->mapFromGlobal(cursor);
                                          
                                          	if(button.contains(position)){
                                          		const bool hover = option.state & QStyle::State_MouseOver;
                                          		if(hover){
                                          			icon = QIcon(":/icons/trash_red.png");
                                          			icon.paint(painter, button);
                                          		}
                                          	}
                                          	painter->save();
                                          	painter->restore();
                                          }
                                          

                                          mouseMoveEvent:

                                          void ToggleListView::mouseMoveEvent(QMouseEvent *event)
                                          {
                                          	QPoint position = event->pos();
                                          	QModelIndex index = indexAt(position);
                                          	QRect original = visualRect(index);
                                          	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
                                          
                                          	bool currentButtonState = button.contains(position);
                                          
                                          	if(index != mPreviousIndex){
                                          		if(mPreviousIndex.isValid())
                                          			update(mPreviousIndex);
                                          		if(index.isValid())
                                          			update(index);
                                          	} else if(currentButtonState != mPreviousButtonState){
                                          		update(index);
                                          	}
                                          	mPreviousIndex = index;
                                          	mPreviousButtonState = currentButtonState;
                                          }
                                          
                                          jeremy_kJ 1 Reply Last reply
                                          0
                                          • ? A Former User

                                            A very big thanks goes to @jeremy_k . Your tip and the code example was worth its weight in gold. Thank you!

                                            Now my code looks like this:
                                            Delegate:

                                            void ToggleListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                                            {
                                            	QString text = index.data(Qt::DisplayRole).toString();
                                            	QRect original = option.rect;
                                            	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
                                            	QRect label = original.adjusted(0,0, -mButtonSize.width(),0);
                                            	painter->drawText(label, Qt::AlignLeft, text);
                                            
                                            	QIcon icon = QIcon(":/icons/trash_black.png");
                                            	icon.paint(painter, button);
                                            
                                            	const auto widget = qobject_cast<ToggleListView*>(option.styleObject);
                                            
                                            	QPoint cursor = QCursor::pos();
                                            	QPoint position = widget->viewport()->mapFromGlobal(cursor);
                                            
                                            	if(button.contains(position)){
                                            		const bool hover = option.state & QStyle::State_MouseOver;
                                            		if(hover){
                                            			icon = QIcon(":/icons/trash_red.png");
                                            			icon.paint(painter, button);
                                            		}
                                            	}
                                            	painter->save();
                                            	painter->restore();
                                            }
                                            

                                            mouseMoveEvent:

                                            void ToggleListView::mouseMoveEvent(QMouseEvent *event)
                                            {
                                            	QPoint position = event->pos();
                                            	QModelIndex index = indexAt(position);
                                            	QRect original = visualRect(index);
                                            	QRect button = original.adjusted(original.width() - mButtonSize.width(),0,0,0);
                                            
                                            	bool currentButtonState = button.contains(position);
                                            
                                            	if(index != mPreviousIndex){
                                            		if(mPreviousIndex.isValid())
                                            			update(mPreviousIndex);
                                            		if(index.isValid())
                                            			update(index);
                                            	} else if(currentButtonState != mPreviousButtonState){
                                            		update(index);
                                            	}
                                            	mPreviousIndex = index;
                                            	mPreviousButtonState = currentButtonState;
                                            }
                                            
                                            jeremy_kJ Offline
                                            jeremy_kJ Offline
                                            jeremy_k
                                            wrote on last edited by
                                            #20

                                            Happy to help.

                                            @Gabber said in Mouse hover on QRect not working as expected:

                                            Now my code looks like this:
                                            Delegate:

                                            void ToggleListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                                            {
                                                [...]
                                            	painter->save();
                                            	painter->restore();
                                            }
                                            

                                            QPainter::save() and restore are only necessary if the painter's settings are altered and need to be restored later. For example:

                                            painter->save();
                                            painter->setBrush(QBrush(QColorConstant::Green);
                                            painter->drawRect(0, 0, 10, 10);
                                            painter->restore();
                                            

                                            Asking a question about code? http://eel.is/iso-c++/testcase/

                                            1 Reply Last reply
                                            0

                                            • Login

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