Home > Blockchain >  QTableView: How to hide dotted line border when no items are selected
QTableView: How to hide dotted line border when no items are selected

Time:12-28

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.

enter image description here

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)

CodePudding user response:

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:

  • An item has been selected.
  • You clicked in e.g. another view after selecting an item.
  • You clicked somewhere in the view where there is no item (= your case above)

Item is selected / The view has the focus Item is selected / Another view was clicked Item is not selected / The view does not have the focus

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:

  1. The view is set to display no outline, although it has no effect if not combined with the next lines.
  2. This corresponds to my first screenshot (:selected and :focus are true).
    You have to force the background for the outline to actually be removed, even if the value you force is the same as what the style originally has (do not ask me why, I do not know...).
    Note: if you want the second screenshot (:selected is true, :focus is false) to look like the first, you need to remove the :focus pseudo-state to merge both cases.
  3. This corresponds to my third screenshot (:selected is false, :focus is true).
    Same reason as point 2.

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.

  • Related