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. [SOLVED] Mousehover entire row selection in QTableView
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] Mousehover entire row selection in QTableView

Scheduled Pinned Locked Moved General and Desktop
8 Posts 1 Posters 9.8k Views 1 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.
  • M Offline
    M Offline
    maximus
    wrote on last edited by
    #1

    Hi guys,

    I would like to do a simple thing, when I hover an item in my custom QTableView, make the entire row have a different background color.
    Unfortunately I cannot do this with stylesheet, as item are considered to be a row and a column, not an entire row.
    @QTableView::item:hover{ /* not working for entire row */
    }@

    I found a good thread convering this "here":http://qt-project.org/forums/viewthread/13099 but my problem is somewhat different because i'm not using a QStandardItemModel, I have my own model.

    I think i'm 90% there but I just have problem settting the background color on the entire row. I can already monitor when the user hover a new row, and print a message, but not change the color.
    The line : _modelSource->setData(inn, QBrush(QColor(Qt::yellow), Qt::SolidPattern), Qt::BackgroundRole); //CHANGE FOR THIS BACKGROUND COLOR
    Should change the color but it doesn't do anything right now.

    Thanks if you can give me some help!

    1- MyTableView.cpp (custom QTableView)
    @#include "mytableview.h"
    #include <QDebug>
    #include <sortfilterproxymodel.h>
    #include <workouttablemodel.h>

    MyTableView::MyTableView(QWidget *parent) : QTableView(parent) {

    this->setMouseTracking(true);
    currHovered = -1;
    

    }

    //-------------------------------------------------------------------------------------------------------
    void MyTableView::mouseMoveEvent(QMouseEvent* event) {

    QPoint pos = event->pos();
    
    QModelIndex index = indexAt(pos);
    int row = index.row();
    
    if (index.isValid()) {
    
         qDebug() << "MOUSE MOVED VALID INDEX! x:" <<pos.x() << " y:" << pos.y() << " ROW: " << row;
    
        if ( row == currHovered) return; //early exit
    
        SortFilterProxyModel *_model = static_cast<SortFilterProxyModel*>(model());
        WorkoutTableModel *_modelSource = static_cast<WorkoutTableModel*>(_model->sourceModel());
    
        for ( int col = 0; col < _modelSource->columnCount(); col++ ) {
    
            QModelIndex inn = _modelSource->index(row, col);
    
    
            QVariant dta = inn.data(Qt::BackgroundRole);   // CURRENT BACKGROUND COLOR
            qDebug() << "VARIANT: " << dta;
    
            // SET DATA NOT WORKING ?
            _modelSource->setData(inn, QBrush(QColor(Qt::yellow), Qt::SolidPattern), Qt::BackgroundRole);  //CHANGE FOR THIS BACKGROUND COLOR
            qDebug() << "changing color for row:" << row << " col:" << col;
    
        }
        currHovered = row;
    }
    

    }

    //------------------------------------------------------------------------------------------------------
    void MyTableView::mousePressEvent(QMouseEvent* event) {

    QTableView::mousePressEvent(event);
    
    if (event->buttons() == Qt::RightButton) {
        // TODO: Contextual menu on right click for item removal
        qDebug() << "Right BUTT";
    }
    

    }@

    //----------------- LOG EXAMPLE
    MOUSE MOVED VALID INDEX! x: 311 y: 58 ROW: 0
    VARIANT: QVariant(QBrush, QBrush(QColor(Invalid) , LinearGradientPattern ) )
    changing color for row: 0 col: 0
    VARIANT: QVariant(QBrush, QBrush(QColor(ARGB 1, 1, 1, 0) , SolidPattern ) )
    changing color for row: 0 col: 1
    VARIANT: QVariant(Invalid)
    changing color for row: 0 col: 2
    VARIANT: QVariant(Invalid)
    changing color for row: 0 col: 3
    VARIANT: QVariant(Invalid)
    changing color for row: 0 col: 4
    VARIANT: QVariant(Invalid)
    changing color for row: 0 col: 5


    Free Indoor Cycling Software - https://maximumtrainer.com

    1 Reply Last reply
    0
    • M Offline
      M Offline
      maximus
      wrote on last edited by
      #2

      Turn out I need to implement the function
      @bool QAbstractItemModel::setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) [virtual]@
      in my custom model for it to work, will post code when it does


      Free Indoor Cycling Software - https://maximumtrainer.com

      1 Reply Last reply
      0
      • M Offline
        M Offline
        maximus
        wrote on last edited by
        #3

        I found a better solution with Delegate

        Added this function "mouseMoveEvent" below in my custom QTableView:
        The only problem I have now is that this rowDelegate overwrite one of my column delegate

        MyTableView.cpp
        @#include "mytableview.h"
        #include <QDebug>
        #include <sortfilterproxymodel.h>
        #include <workouttablemodel.h>
        #include "delegaterowhover.h"

        MyTableView::MyTableView(QWidget *parent) : QTableView(parent) {

        this->setMouseTracking(true);
        
        m_background_delegate = new delegateRowHover(this);
        myDelegate = new MyDelegate(this);
        
        setItemDelegateForColumn(5, myDelegate);
        

        }

        //-------------------------------------------------------------------------------------------------------
        void MyTableView::mouseMoveEvent(QMouseEvent* event) {

        QPoint pos = event->pos();
        QModelIndex index = indexAt(pos);
        int row = index.row();
        qDebug() << "ROW TO CHANGE COLOR: " << row;
        
        if (index.isValid()) {
        
            //        qDebug() << "MOUSE MOVED VALID INDEX! x:" <<pos.x() << " y:" << pos.y() << " ROW: " << row;
        
            SortFilterProxyModel *_model = static_cast<SortFilterProxyModel*>(model());
        
            for (int i=0; i<_model->rowCount(); i++) {
                for (int j=0; j<_model->columnCount(); j++) {
        
                    if (i == row) {
                        QModelIndex inn = _model->index(i, j);
                        setItemDelegateForRow(inn.row(), m_background_delegate);
        
                    }
                    else {
                        QModelIndex inn = _model->index(i, j);
                        setItemDelegateForRow(inn.row(), new QStyledItemDelegate);
                    }
                }
            }
        
        // TO FIX, row delegate remove my colum 5 delegate..
        

        // setItemDelegateForColumn(5, myDelegate);

        }
        

        }

        //------------------------------------------------------------------------------------------------------
        void MyTableView::mousePressEvent(QMouseEvent* event) {

        QTableView::mousePressEvent(event);
        
        if (event->buttons() == Qt::RightButton) {
            // TODO: Contextual menu on right click for item removal
            qDebug() << "Right BUTT";
        }
        

        }
        @


        Free Indoor Cycling Software - https://maximumtrainer.com

        1 Reply Last reply
        0
        • M Offline
          M Offline
          maximus
          wrote on last edited by
          #4

          turn out I had to put all delegate in the same delegate class to fix that


          Free Indoor Cycling Software - https://maximumtrainer.com

          1 Reply Last reply
          0
          • M Offline
            M Offline
            maximus
            wrote on last edited by
            #5

            While learning Qt I found a less complicated way to emulate row hovering.

            1- set mouse tracking to your QTableView and connect this slot:
            @ ui->tableView_workout->setMouseTracking(true);
            connect(ui->tableView_workout, SIGNAL(entered(QModelIndex)), this, SLOT(drawHoverWidget(QModelIndex)) );
            @

            2- Draw a QRubberBand whenever the selection change, will produce the same effect like a row hovering.
            @void Main_WorkoutPage::drawHoverWidget(QModelIndex index) {

            qDebug() << "drawHoverWidget"  << index.row();
            
            
            /// Dont redraw widget if row selection is the same
            if (index.row() == currentRowHovered)
                return;
            
            
            /// Hide last rubberBand
            rubberBandHover->hide();
            
            /// Change index column to first one (selection behavior: select row)
            QModelIndex newIndex =  ui->tableView_workout->model()->index(index.row(), 0,  QModelIndex() );
            QRect recIndex(ui->tableView_workout->visualRect(newIndex));
            
            rubberBandHover->move(recIndex.topLeft());
            rubberBandHover->resize(ui->tableView_workout->width(), recIndex.size().height());
            rubberBandHover->show();
            

            }@

            Seems to work well for now, only problem is you need to erase the widget when the mouse is no longer on a row, you can create a new signal "NoSelection" (on leaveEvent(QEvent *event) inside your QTableView, and emit the the "No Selection" signal when the row is invalid


            Free Indoor Cycling Software - https://maximumtrainer.com

            1 Reply Last reply
            0
            • M Offline
              M Offline
              maximus
              wrote on last edited by
              #6

              DON'T use the above code, I found it was getting too complex, so i found this way on the web:
              http://qt-project.org/forums/viewthread/13099

              google > me
              Good luck


              Free Indoor Cycling Software - https://maximumtrainer.com

              1 Reply Last reply
              0
              • M Offline
                M Offline
                maximus
                wrote on last edited by
                #7

                I got tired of all thoses complex solution and coded all of it directly in the delegate!
                Your delegate needs a pointer to it's QTableView for it to work..
                Here is what I have now:
                https://www.dropbox.com/s/7d5k499xh7e3t3r/selectHoverHell.png

                I must say this is a hell of a nightmare to code, just for a simple functionality, make me a sad panda sometimes that I chosse QT for the UI!! grr

                @void delegateRowHover::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {

                QStyleOptionViewItemV4 opt = option;
                initStyleOption(&opt, index);
                
                int hoveredRow = -1;
                if(option.state & QStyle::State_MouseOver) {
                    hoveredRow = index.row();
                }
                
                if (hoveredRow != -1)
                {
                    /// Get most left index to get good QRect coords (row selection behavior)
                    QModelIndex leftIndex = index.model()->index(hoveredRow, 0, QModelIndex());
                    QRect recTopLeft(tableView->visualRect(leftIndex));
                    recTopLeft.setWidth(tableView->width());
                
                    painter->fillRect(recTopLeft, QBrush(Qt::red));
                }@
                

                Free Indoor Cycling Software - https://maximumtrainer.com

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  maximus
                  wrote on last edited by
                  #8

                  There you go, working solution after 1000x trial and error :

                  That being said, really bad and not reusable, I have to modify the QRect size because the original is too big.

                  @
                  void delegateRowHover::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {

                  QStyleOptionViewItemV4 opt = option;
                  initStyleOption(&opt, index);
                  
                  
                  int hoveredRow = -1;
                  if(option.state & QStyle::State_MouseOver) {
                      hoveredRow = index.row();
                  }
                  
                  
                  
                  if (hoveredRow != -1)
                  {
                      if(option.state & QStyle::State_Selected) {
                      }
                      else {
                          /// Get most left index to get good QRect coords (row selection behavior)
                          QModelIndex leftIndex = index.model()->index(hoveredRow, 0, QModelIndex());
                          QRect recTopLeft(tableView->visualRect(leftIndex));
                          recTopLeft.setWidth(tableView->width()-1);
                          recTopLeft.setHeight(68);
                          painter->drawText(recTopLeft, "123");
                          painter->drawRect(recTopLeft);
                          qDebug() << recTopLeft;
                      }
                  }@
                  

                  Free Indoor Cycling Software - https://maximumtrainer.com

                  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