[SOLVED] Mousehover entire row selection in QTableView
-
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 -
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 -
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 delegateMyTableView.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"; }
}
@ -
turn out I had to put all delegate in the same delegate class to fix that
-
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
-
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/13099google > me
Good luck -
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.pngI 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)); }@
-
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; } }@