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. QTableWidget hover entire row without hard-coding background color
QtWS25 Last Chance

QTableWidget hover entire row without hard-coding background color

Scheduled Pinned Locked Moved Solved General and Desktop
6 Posts 3 Posters 5.1k Views
  • 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.
  • L Offline
    L Offline
    linly
    wrote on 20 Jul 2016, 01:00 last edited by
    #1

    I've got a QTableWidget, and I want the entire row to be highlighted when mouse hovers on an item.
    All the solutions I read from other questions hard code the background color in code, which is not what I want.
    I'm using Qt stylesheet to set the background color of the hovered item:

    QTableWidget::item:hover {
    	background-color: #27292b;
    }
    

    And I tried to trick the items in a row into hovered state using a delegate:

    #include <QStyledItemDelegate>
    class RowHoverDelegate: public QStyledItemDelegate
    {
        Q_OBJECT
    public:
        RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
        void paint(QPainter *painter, const QStyleOptionViewItem &option,
                   const QModelIndex &index) const;
    private:
        QTableWidget *m_tableWdt;
    };
    
    
    // in the implementation file:
    
    RowHoverDelegate::RowHoverDelegate(QTableWidget *tableWidget, QObject *parent)
        : QStyledItemDelegate(parent), m_tableWdt(tableWidget)
    {}
    
    void RowHoverDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                 const QModelIndex &index) const
    {
        if (option.state & QStyle::State_MouseOver)
        {
            QTableWidgetItem *hovItem = m_tableWdt->item(index.row(), index.column());
            if (hovItem)
            {
                int row = hovItem->row();
                int columnCount = m_tableWdt->columnCount();
    
                for (int col = 0; col < columnCount; ++col)
                {
                    QTableWidgetItem *item = m_tableWdt->item(row, col);
                    if (item)
                    {
                        QModelIndex idx = m_tableWdt->model()->index(row, col);
                        // copy option from the hovered item (opt is in State_MouseOver state)
                        QStyleOptionViewItem opt = option;
                        // update index and rect
                        opt.index = idx;
                        opt.rect = m_tableWdt->visualItemRect(item);
                        QStyledItemDelegate::paint(painter, opt, idx);  // paint the item
                    }
                }
                return;
            }
        }
        QStyledItemDelegate::paint(painter, option, index);
    }
    

    In the caller:

        m_tableWdt = new QTableWidget();
        // ...
        RowHoverDelegate *delegate = new RowHoverDelegate(m_tableWdt, m_tableWdt);
        m_tableWdt->setItemDelegate(delegate);
    

    This delegate causes the hovered item and items on the left hand side of it change background, the right hand side items remains unchanged, strange. Can anyone explain this ?

    1 Reply Last reply
    2
    • L Offline
      L Offline
      linly
      wrote on 20 Jul 2016, 04:34 last edited by
      #2

      OK, I solved it. The key is to update the viewport of the QTableWidget as stated here by Steffen

      Here is the impoved delegate:

      class RowHoverDelegate : public QStyledItemDelegate
      {
          Q_OBJECT
      public:
          RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
          void paint(QPainter *painter, const QStyleOptionViewItem &option,
                     const QModelIndex &index) const;
      
      protected slots:
          void onItemEntered(QTableWidgetItem *item);
      
      private:
          QTableWidget *m_tableWdt;
          int m_hoveredRow;
      };
      

      Implementation:

      RowHoverDelegate::RowHoverDelegate(QTableWidget *tableWidget, QObject *parent)
      	: QStyledItemDelegate(parent), m_tableWdt(tableWidget), m_hoveredRow(-1)
      {
          // mouse tracking have to be true, otherwise itemEntered won't emit
      	m_tableWdt->setMouseTracking(true);
      	connect(m_tableWdt, SIGNAL(itemEntered(QTableWidgetItem *)), this, SLOT(onItemEntered(QTableWidgetItem *)));
      }
      
      void RowHoverDelegate::onItemEntered(QTableWidgetItem *item)
      {
      	m_hoveredRow = item->row();
      	m_tableWdt->viewport()->update();  // force update
      }
      
      void RowHoverDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                   const QModelIndex &index) const
      {
      	QStyleOptionViewItem opt = option;
      	if (index.row() == m_hoveredRow)
      	{
      		opt.state |= QStyle::State_MouseOver;
      	}
      	QStyledItemDelegate::paint(painter, opt, index);
      }
      
      J 1 Reply Last reply 3 Apr 2023, 14:25
      3
      • L linly
        20 Jul 2016, 04:34

        OK, I solved it. The key is to update the viewport of the QTableWidget as stated here by Steffen

        Here is the impoved delegate:

        class RowHoverDelegate : public QStyledItemDelegate
        {
            Q_OBJECT
        public:
            RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
            void paint(QPainter *painter, const QStyleOptionViewItem &option,
                       const QModelIndex &index) const;
        
        protected slots:
            void onItemEntered(QTableWidgetItem *item);
        
        private:
            QTableWidget *m_tableWdt;
            int m_hoveredRow;
        };
        

        Implementation:

        RowHoverDelegate::RowHoverDelegate(QTableWidget *tableWidget, QObject *parent)
        	: QStyledItemDelegate(parent), m_tableWdt(tableWidget), m_hoveredRow(-1)
        {
            // mouse tracking have to be true, otherwise itemEntered won't emit
        	m_tableWdt->setMouseTracking(true);
        	connect(m_tableWdt, SIGNAL(itemEntered(QTableWidgetItem *)), this, SLOT(onItemEntered(QTableWidgetItem *)));
        }
        
        void RowHoverDelegate::onItemEntered(QTableWidgetItem *item)
        {
        	m_hoveredRow = item->row();
        	m_tableWdt->viewport()->update();  // force update
        }
        
        void RowHoverDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                     const QModelIndex &index) const
        {
        	QStyleOptionViewItem opt = option;
        	if (index.row() == m_hoveredRow)
        	{
        		opt.state |= QStyle::State_MouseOver;
        	}
        	QStyledItemDelegate::paint(painter, opt, index);
        }
        
        J Offline
        J Offline
        JoeCFD
        wrote on 3 Apr 2023, 14:25 last edited by JoeCFD 4 Mar 2023, 14:58
        #3

        @linly said in QTableWidget hover entire row without hard-coding background color:

        class RowHoverDelegate : public QStyledItemDelegate
        {
        Q_OBJECT
        public:
        RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
        void paint(QPainter *painter, const QStyleOptionViewItem &option,
        const QModelIndex &index) const;

        protected slots:
        void onItemEntered(QTableWidgetItem *item);

        private:
        QTableWidget *m_tableWdt;
        int m_hoveredRow;
        };

        class RowHoverDelegate : public QStyledItemDelegate
        {
            Q_OBJECT
        public:
            RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
            void paint(QPainter *painter, const QStyleOptionViewItem &option,
                       const QModelIndex &index) const override; /* better to have override here  */
        
        protected slots:
            void onItemEntered(QTableWidgetItem *item);
        
        private:
            QTableWidget *m_tableWdt;
            int m_hoveredRow;
        };
        
        JonBJ 1 Reply Last reply 3 Apr 2023, 14:28
        0
        • J JoeCFD
          3 Apr 2023, 14:25

          @linly said in QTableWidget hover entire row without hard-coding background color:

          class RowHoverDelegate : public QStyledItemDelegate
          {
          Q_OBJECT
          public:
          RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
          void paint(QPainter *painter, const QStyleOptionViewItem &option,
          const QModelIndex &index) const;

          protected slots:
          void onItemEntered(QTableWidgetItem *item);

          private:
          QTableWidget *m_tableWdt;
          int m_hoveredRow;
          };

          class RowHoverDelegate : public QStyledItemDelegate
          {
              Q_OBJECT
          public:
              RowHoverDelegate(QTableWidget *tableWidget, QObject *parent = 0);
              void paint(QPainter *painter, const QStyleOptionViewItem &option,
                         const QModelIndex &index) const override; /* better to have override here  */
          
          protected slots:
              void onItemEntered(QTableWidgetItem *item);
          
          private:
              QTableWidget *m_tableWdt;
              int m_hoveredRow;
          };
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on 3 Apr 2023, 14:28 last edited by
          #4

          @JoeCFD said in QTableWidget hover entire row without hard-coding background color:

          override; /* override is needed here */

          Hi Joe. Are you claiming this fixes anything? Although specifying override is desirable (I always do), it's not compulsory for anything, other than telling you if you've made a mistake.

          J 2 Replies Last reply 3 Apr 2023, 14:57
          0
          • JonBJ JonB
            3 Apr 2023, 14:28

            @JoeCFD said in QTableWidget hover entire row without hard-coding background color:

            override; /* override is needed here */

            Hi Joe. Are you claiming this fixes anything? Although specifying override is desirable (I always do), it's not compulsory for anything, other than telling you if you've made a mistake.

            J Offline
            J Offline
            JoeCFD
            wrote on 3 Apr 2023, 14:57 last edited by
            #5

            @JonB Sorry. Not a fix. it is better to have. I changed it.

            1 Reply Last reply
            1
            • JonBJ JonB
              3 Apr 2023, 14:28

              @JoeCFD said in QTableWidget hover entire row without hard-coding background color:

              override; /* override is needed here */

              Hi Joe. Are you claiming this fixes anything? Although specifying override is desirable (I always do), it's not compulsory for anything, other than telling you if you've made a mistake.

              J Offline
              J Offline
              JoeCFD
              wrote on 4 Apr 2023, 13:52 last edited by JoeCFD 4 Apr 2023, 13:53
              #6

              @JonB this piece of code will not work well when rows are selected. It is better to have a setting in QTableWidget/View:
              something like: enableRowHovering( bool value = false ); I will send a request in the developer's mailing list.

              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