QTableView How can I highlight the entire row for mouse hover?
Asked Answered
G

3

1

The selection behavior is set to select rows, but only the hovered cell is highlighted. Is there any way to highlight the entire row?

Graphy answered 13/12, 2013 at 11:56 Comment(0)
T
2

There are 2 ways..

1) You can use delegates to draw the row background...
You will need to set the row to highlight in the delegate and based on that, do the highlighting.

2) Catch the signal of current row. Iterate over the items in that row and set background for each item.

Hope, It will usefull to you guys.

Tellurate answered 16/4, 2014 at 13:39 Comment(2)
.Could you please give some more explain on first approachTripletail
Not very helpful. Why don't you give an example?Loess
T
10

First, you subclass QTableWidget/QTableView and reimplement mouseMoveEvent and leaveEvent.

In custom_table_widget.cpp, you should have:

...
CustomTableWidget::CustomTableWidget(QWidget *parent) :
  QTableWidget(parent)
{
  setMouseTracking(true);  // receives mouse move events even if no buttons are pressed.
}

void CustomTableWidget::mouseMoveEvent(QMouseEvent *event)
{
  // detect where the mouse cursor is relative to our custom table widget
  QModelIndex index = indexAt(event->pos());
  emit hoverIndexChanged(index);
}

void CustomTableWidget::leaveEvent(QEvent *event)
{
  // detect when the mouse cursor leaves our custom table widget
  emit leaveTableEvent();
  viewport()->update();
}
...

Next, you subclass QStyledItemDelegate. Reimplement paint method and add two slots to modify the hovered row. In row_hover_delegate.cpp, you should have:

...
void RowHoverDelegate::onHoverIndexChanged(const QModelIndex& item) {
  hovered_row_ = item.row();
}

void RowHoverDelegate::onLeaveTableEvent() {
  hovered_row_ = -1;
}

void RowHoverDelegate::paint(QPainter *painter,
                                  const QStyleOptionViewItem &option,
                                  const QModelIndex &index) const {
  QStyleOptionViewItem opt = option;
  if(index.row() == hovered_row_) {
    opt.state |= QStyle::State_MouseOver;
  } else {
    opt.state &= ~QStyle::State_MouseOver;
  }
  QStyledItemDelegate::paint(painter, opt, index);
}
...

Finally, connect the the signals/slots and set the item delegate:

connect(my_custom_table_widget, 
        &CustomTableWidget::hoverIndexChanged,
        my_row_hover_delegate,
        &RowHoverDelegate::onHoverIndexChanged);
connect(my_custom_table_widget, 
        &CustomTableWidget::leaveTableEvent,
        my_row_hover_delegate,
        &RowHoverDelegate::onLeaveTableEvent);

my_custom_table_widget->setItemDelegate(my_row_hover_delegate);
Terat answered 2/2, 2018 at 15:59 Comment(1)
Thanks for the code, but it wasn't really necessary.Graphy
T
2

There are 2 ways..

1) You can use delegates to draw the row background...
You will need to set the row to highlight in the delegate and based on that, do the highlighting.

2) Catch the signal of current row. Iterate over the items in that row and set background for each item.

Hope, It will usefull to you guys.

Tellurate answered 16/4, 2014 at 13:39 Comment(2)
.Could you please give some more explain on first approachTripletail
Not very helpful. Why don't you give an example?Loess
W
2

An old question but as I managed to solve it using only the delegate, here my solution for anybody stumbling across the same problem. This is in PyQt5, but should be easy to convert to c++.

class HoverDelegate(QStyledItemDelegate):

    def __init__(self, parent=None):
        super().__init__(parent)
        # Define the hover colour
        self.hoverBackground = QBrush(QColor('#F5F5F5'))
        # Initiate variables to invalid model indices
        self.currentHovered = QModelIndex()
        self.previousHovered = QModelIndex()

    def initStyleOption(self, option, modelIndex):
        super().initStyleOption(option, modelIndex)

        # Cache model indices
        if option.state & QStyle.State_MouseOver:
            if modelIndex.row() != self.currentHovered.row():
                self.previousHovered = self.currentHovered
                self.currentHovered = modelIndex

        # Set background brush if we're on a hover row
        if modelIndex.row() == self.currentHovered.row():
            option.backgroundBrush = self.hoverBackground


    def paint(self, painter, option, modelIndex):
        # Standard paint event takes care of painting the hover background
        # if defined in initStyleOption 
        super().paint(painter, option, modelIndex)

        # Remove the hover background from the previously hovered row
        # by requesting update of all cells of the previously hovered row
        if self.previousHovered.isValid():
            view = self.parent()
            col = 0
            index = self.previousHovered.siblingAtColumn(col)

            while index.isValid():
                view.update(index)
                col += 1
                index = index.siblingAtColumn(col)

            # Reset to an invalid index
            self.previousHovered = QModelIndex()
Wawro answered 6/5, 2022 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.