I'm working on a custom QTableView, use it to show a list of reomte files.
This is the configuration of the QTableView:
this->verticalHeader()->hide();
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->setShowGrid(false);
this->setEditTriggers(QAbstractItemView::NoEditTriggers);
When I selected a row, it highlight the row without any issue. But when I clicked other area which don't have any items, the selected row becomes unselected, the dotted line border shows.
It there any way to hide the border in this case?
My Qt version:
Qt Creator 8.0.1
Based on Qt6.3.1 (MSVC 2019,x86_64)
What you are seeing is the focus outline. There are several solutions to get rid of it, none of which is easy and straightforward.
Before I dive into it, notice there can be 3 states:
There is a 4th state which, obviously, is items you have not selected at any point; they look the same no matter what view is the active widget and I am going to ignore them.
I assume you want to keep all 3 states as is, except for the outline in the first and third screenshots.
Solution 1: Stylesheet (recommended):
Assuming you have exactly the same colors as me, set the following stylesheet on your table view or directly on the instance of QApplication
.
QTableView { outline:none; }
QTableView::item:selected:focus { background:#0078D7; }
QTableView::item:!selected:focus { background:transparent; }
Line-by-line explanation:
:selected
and :focus
are true).:selected
is true, :focus
is false) to look like the first, you need to remove the :focus
pseudo-state to merge both cases.:selected
is false, :focus
is true).Solution 2: Subclassing QProxyStyle:
Alternatively, you can subclass a style to completely ignore the primitive element QStyle::PE_FrameFocusRect
:
class NoFocusOutlineStyle : public QProxyStyle
{
public:
void drawPrimitive(PrimitiveElement element,
const QStyleOption* option,
QPainter* painter,
const QWidget* widget) const override
{
if (element == QStyle::PE_FrameFocusRect)
return;
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
};
To be added to you application, for example qtApp.setStyle(new NoFocusOutlineStyle);
Solution 3: Subclassing QStyledItemDelegate:
Last, you can instead create your own delegate to alter the style option before the item is painted on screen. All you need to do is override the paint
method. Skipping the header file and just looking at the implementation, this gives you:
void aQSNoFocusItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QStyleOptionViewItem opt = option;
if (opt.state & QStyle::State_HasFocus && !(opt.state & QStyle::State_Selected))
opt.state &= ~QStyle::State_HasFocus;
QStyledItemDelegate::paint(painter, opt, index);
}
This solution requires you to call QAbstractItemView::setItemDelegate
, QAbstractItemView::setItemDelegateForColumn
or QAbstractItemView::setItemDelegateForRow
every time but allows fine-tuning.