Qt Styling QTreeWidget : Remove Focus on Icons
-
I have a problem while I was trying to apply a QSS Stylesheet to my QTreeWidget on my Qt project. When I click on an item the icon of the item inside the QTreeWidget change color and goes blue.
Here's my code :
#ifndef FILESIDEBARWIDGET_H #define FILESIDEBARWIDGET_H #include <QWidget> #include <QTreeView> #include <QFileSystemModel> #include <QVBoxLayout> #include <QDir> #include <QHeaderView> #include <QFile> #include <QTextStream> #include <QDebug> #include <QIcon> class CustomFileSystemModel : public QFileSystemModel { Q_OBJECT public: explicit CustomFileSystemModel(QObject *parent = nullptr) : QFileSystemModel(parent) {} QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { if (role == Qt::DecorationRole && index.column() == 0) { QFileInfo info = fileInfo(index); QIcon icon; if (info.isDir()) { icon = QIcon(":/images/icons/directory.png"); } else if (info.isFile()) { QString name = info.fileName(); if (hasMatchingExtension(name, QStringList{"png", "jpg", "jpeg", "gif", "bmp"})) { icon = QIcon(":/images/icons/fileImg.png"); } else if (hasMatchingExtension(name, QStringList{"bin", "o", "exe", "dll", "so"})) { icon = QIcon(":/images/icons/fileBin.png"); } else { icon = QIcon(":/images/icons/fileText.png"); } } return icon.pixmap(16, 16); } return QFileSystemModel::data(index, role); } private: bool hasMatchingExtension(const QString &fileName, const QStringList &extensions) const { QString lowerFileName = fileName.toLower(); for (const QString &ext : extensions) { QString lowerExt = ext.toLower(); if (lowerFileName.endsWith("." + lowerExt)) { return true; } else if (lowerFileName.contains("." + lowerExt)) { return true; } } return false; } }; class FileSidebarWidget : public QWidget { Q_OBJECT public: explicit FileSidebarWidget(QWidget *parent = nullptr) : QWidget(parent) { fileModel = new CustomFileSystemModel(this); fileModel->setRootPath(QDir::currentPath()); fileModel->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); treeView = new QTreeView(this); treeView->setModel(fileModel); treeView->setRootIndex(fileModel->index(QDir::currentPath())); treeView->setHeaderHidden(true); treeView->setColumnHidden(1, true); treeView->setColumnHidden(2, true); treeView->setColumnHidden(3, true); treeView->setAnimated(false); treeView->setIndentation(20); treeView->setSortingEnabled(false); treeView->setFocusPolicy(Qt::NoFocus); treeView->setStyleSheet(R"( QTreeView { background-color: #21252b; border: none; color: #d3d3d3; } QTreeView::item { padding: 2px; color: #d3d3d3; border: none; outline: none; } QTreeView::item:selected { background-color: #4d78cc; color: white; } )"); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(treeView); setLayout(layout); connect(treeView, &QTreeView::doubleClicked, this, &FileSidebarWidget::onFileSelected); } signals: void fileSelected(const QString &filePath); private slots: void onFileSelected(const QModelIndex &index) { QString path = fileModel->filePath(index); if (QFileInfo(path).isFile()) emit fileSelected(path); } private: QTreeView *treeView; CustomFileSystemModel *fileModel; }; #endif // FILESIDEBARWIDGET_H
Here is a minimal reproducible example that shows that even with the focus disabled the icon still appears with a blue tint when you click on it:
#include <QApplication> #include <QTreeView> #include <QFileSystemModel> #include <QFileInfo> #include <QDir> #include <QIcon> int main(int argc, char *argv[]) { QApplication app(argc, argv); QFileSystemModel *model = new QFileSystemModel; model->setRootPath(QDir::currentPath()); model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); QTreeView *view = new QTreeView; view->setModel(model); view->setRootIndex(model->index(QDir::currentPath())); view->setHeaderHidden(true); view->setFocusPolicy(Qt::NoFocus); view->setStyleSheet(R"( QTreeView { background-color: #2b2b2b; color: #dcdcdc; border: none; } QTreeView::item:selected { background: transparent; color: #dcdcdc; } QTreeView::item:focus { outline: none; } )"); view->resize(600, 400); view->show(); return app.exec(); }
Hope someone can help :)
Good Bye,
-
Hi,
I can't confirm that on Qt 6.9 / macOS.
The tree view of the reproducer looks as expected.
Which Qt version are you using? -
Hello, thank you for your answer!
I'm using Qt 6.9.0 on linux (Xubuntu).
My problem is that I can't remove the blue focus on the QTreeWidget items icon when I click on one of them.
Have a nice day -
I see what you mean and I can also reproduce it on Linux (openSuSE).
The QSS styling of a tree view basically starts at thebranch
subcontrol.
Everything that happens before, falls back to the base style.
The line corresponding to the currently selected item will be rendered inview->palette().color(QPalette::Highlight)
.
This can be overridden by a style sheet for thebranch
and theitem
subcontrols, but not for the beginning of the line where icons are placed (if they exist).You can achieve the effect you are looking for by adding this code, before setting the style sheet.
QPalette p = view->palette(); p.setColor(QPalette::Highlight, p.window().color()); view->setPalette(p);
-
Hello, thank you for your help!
I tried your solution and added your lines of code before the setStyleSheet, but the problem doesn't change, there's still this blue focus on an item when I click on it.
Have a nice day -
That could be because XUbuntu is Gnome based.
Please try a bit, e.g. adding the code after the style sheet. -
Hello,
I tried a bit and I found the solution
class NoTintIconDelegate : public QStyledItemDelegate { public: explicit NoTintIconDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); // Prepare the painter painter->save(); // Draw the background and selection if (opt.state & QStyle::State_Selected) { painter->fillRect(opt.rect, QColor("#4d78cc")); painter->setPen(opt.palette.highlightedText().color()); } else { painter->fillRect(opt.rect, QColor("#21252b")); painter->setPen(opt.palette.text().color()); } // Draw the text QString text = index.data(Qt::DisplayRole).toString(); QRect textRect = opt.rect.adjusted(20, 0, 0, 0); // Adjust for icon space painter->drawText(textRect, Qt::AlignVCenter | Qt::TextSingleLine, text); // Draw the icon manually without tinting QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole)); if (!icon.isNull()) { QPixmap pixmap = icon.pixmap(opt.decorationSize); painter->drawPixmap(opt.rect.left() + 2, opt.rect.top() + (opt.rect.height() - opt.decorationSize.height()) / 2, pixmap); } painter->restore(); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override { QSize size = QStyledItemDelegate::sizeHint(option, index); size.setWidth(size.width() + 20); // Add space for icon return size; } };
and then :
treeView->setItemDelegate(new NoTintIconDelegate(this));
Have a nice day !
-