How to set background color to currently selected row in QTableView using QStyledItemDelegate
-
@dheerajshenoy said in How to set background color to currently selected row in QTableView using QStyledItemDelegate:
QTableView
Please show how you install the delegate, as well as a minimal version of the delegate class that reproduces the issue.
-
@dheerajshenoy
Is the row actually selected? If it is you could use Qt CSS on QTableView:The color and background of the selected item is styled using
selection-color
andselection-background-color
respectively.Otherwise the
paint()
method is only called on what Qt decides needs repainting. For whatever reason it may be that it only thinks a single cell needs repainting where you actually want the whole row. You may need to raise thedataChanged()
signal with role asQt::BackgroundRole
for the whole row when current/selection changes to make it redraw the whole row.It still would not do any harm to show your current code per @IgKh's post.
-
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { if (!index.isValid()) return; QStyleOptionViewItem opt = option; initStyleOption(&opt, index); // Get the text and icon QString fileName = index.data(static_cast<int>(FileSystemModel::Role::FileName)).toString(); QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole)); // Draw the background QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); // This draws only for the first column if (index.row() == m_cursor_row) { painter->save(); painter->fillRect(opt.rect, QColor(Qt::red)); painter->restore(); } // Calculate rectangles QRect iconRect = opt.rect; iconRect.setWidth(opt.decorationSize.width()); QRect textRect = opt.rect; textRect.setLeft(iconRect.right() + 4); // Add some padding after icon // Draw the icon if enabled in model if (!icon.isNull()) { icon.paint(painter, iconRect, Qt::AlignCenter, QIcon::Normal, QIcon::Off); } QString symlinkTargetName = index.data(static_cast<int>(FileSystemModel::Role::Symlink)).toString(); if (!symlinkTargetName.isEmpty()) { // Draw filename painter->setPen(opt.palette.color(QPalette::Text)); painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, fileName); // Draw separator int fileNameWidth = painter->fontMetrics().horizontalAdvance(fileName); painter->drawText(textRect.adjusted(fileNameWidth, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, m_symlink_separator); painter->save(); // Draw target path in the model's symlink color painter->setFont(m_symlink_font); int sepWidth = painter->fontMetrics().horizontalAdvance(m_symlink_separator); int targetTextWidth = painter->fontMetrics().horizontalAdvance(symlinkTargetName); int targetStartX = textRect.left() + fileNameWidth + sepWidth + 4; QRect targetRect(targetStartX, textRect.top(), targetTextWidth, textRect.height()); if (!m_symlink_background.isEmpty()) { painter->fillRect(targetRect, QColor(m_symlink_background)); } painter->setPen(QPen(QColor(m_symlink_foreground))); painter->drawText(textRect.adjusted(fileNameWidth + sepWidth + 4, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, symlinkTargetName); painter->restore(); } else { // For non-symlink items, draw the full text painter->setPen(opt.palette.color(QPalette::Text)); painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, fileName); } }
-
@dheerajshenoy said in How to set background color to currently selected row in QTableView using QStyledItemDelegate:
// This draws only for the first column
So I would suggest as per my previous that Qt is only calling for a single column in the row to be redrawn while you wish the whole row to change background, and what it looks like you need to do about that.
You did not even even comment on
Is the row actually selected? If it is you could use Qt CSS on QTableView:
I can only guess not from no response.
-
@JonB Sorry I missed on the detail of the selection. Yes it is selected. I am working on a keyboard driven file manager (similar ranger, yazi etc.). The current row is always selected. When the user goes to select multiple rows I want the current cursor row to be in a particular color to let the user know which row they are currently on.
-
I see the problem now, I have set the delegate for column using
setItemDelegateForColumn
. Changing this would solve my problem. -
-
-
if (index.row() == m_cursor_row) { // Custom color for the cursor row painter->fillRect(opt.rect, QColor("#ADD8E6")); // Light blue } else if (option.state & QStyle::State_Selected) { // Default selection color QPalette::ColorRole selectionRole = QPalette::Highlight; QColor selectionColor = opt.palette.color(selectionRole); painter->fillRect(opt.rect, selectionColor); }
The background is applied correctly now to the current cursor position, but the other rows are not highlighted completely.
The light blue color is the current row and the rest are selected items. You can see that the other columns are not redrawn correctly. But when the application loses focuses the other columns are drawn correctly.
-
@dheerajshenoy
Like for your discovery aboutsetItemDelegateForColumn()
, start by verifying how you select and what your QAbstractItemView::SelectionBehavior is set to: looks like the default is QAbstractItemView::SelectItems "Selecting single items.", have you setQAbstractItemView::SelectRows
? -
The last 'column' does not look like a column but empty space --> setStretchLastSection(true)
-
@Christian-Ehrlicher
Fair enough, but because OP ends up with light blue there but not darker blue that implies that theopt.rect
passed into his code forfillRect()
are not covering the same area? Why not? Why should he need/have to stretch last section? -
@JonB said in How to set background color to currently selected row in QTableView using QStyledItemDelegate:
Why should he need/have to stretch last section?
As you can see the last 'section' has no header title so I assume it's no column at all but empty space.
-
@Christian-Ehrlicher
Yes. And my point is that was done via previously making that the current row via the code above at https://forum.qt.io/post/818550. Which is also used for coloring the selected row. And they both get passed anopt.rect
forfillrect()
. So presumably the rect for the selection is wider than the rect for his cursor row to produce the result. But why are they different widths or cover different cells?