Qt - CSS: Decoration on Focus

QT - CSS: decoration on focus

The highlighted rectangle may be the QStyle::PE_FrameFocusRect styling. The only way to get rid of it is by implementing a custom style. Fortunately, Qt provides a way to implement just a proxy, which uses another style in the general case. For the focus rectangle you'd implement:

class Style_tweaks : public QProxyStyle
{
public:

void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
/* do not draw focus rectangles - this permits modern styling */
if (element == QStyle::PE_FrameFocusRect)
return;

QProxyStyle::drawPrimitive(element, option, painter, widget);
}
};

qApp->setStyle(new Style_tweaks);

How to change the Focus color(Highlight color) in Qt pushbuttons?

Use stylesheets:

QPushButton:focus:pressed{ background-color: some_colour; }
QPushButton:focus{ background-color: some_other_colour; }

You can either use the Qt Creator to add the styles to your button or load them inside your code by calling setStyleSheet("...") on your button.

Qt4 Stylesheets and Focus Rect

The focus rect around the QTreeView widget itself turns out to be a Mac styling feature. This turns it off per widget:

tree.setAttribute(Qt.WA_MacShowFocusRect, 0)

Style QtComboBox, QListViewItem - Set text padding

It is possible to remove the dotter border using only CSS by setting undocumented property outline:

QComboBox QAbstractItemView {
outline: none;
}

QListView also can be used in this selector. QAbstractItemView is used in this example, since it is a base class of QListView. Note that this property is set not per item but for the external container of items.

There are other ways to remove the dotted border using coding, for example QT - CSS: decoration on focus


It looks that it is needed to change the code to have better flexibility with padding. QComboBox uses its own private implementation of QAbstractItemDelegate based on QItemDelegate. However, other controls use QStyledItemDelegate
(QStyledItemDelegate vs. QItemDelegate). That is why CSS selectors for items (QListView::item) does not have an effect on QComboBox items.

There is the following comment with explanation in the source code:

Note that this class is intentionally not using QStyledItemDelegate

Vista does not use the new theme for combo boxes and there might be
other side effects from using the new class

If the above comment is not a problem, it is possible to set QStyledItemDelegate to QComboBox objects:

QComboBox *combobox = new QComboBox;
combobox->setItemDelegate(new QStyledItemDelegate(combobox));

Now, the property selection-background-color is not needed anymore. It is possible to customize ::item:

QComboBox QAbstractItemView::item {
border: none;
padding-left: 5px;
}

QComboBox QAbstractItemView::item:selected {
background: rgb(47, 175, 178);
padding-left: 5px;
}

Note that to set padding it is also needed to provide, for example, at least border or background property together with padding. Otherwise the padding property is not taken into account.

The selector ::item:selected is used instead of :hover, since items can be also selected by keyboard.


Although it is documented that it is possible to set custom view for QComboBox it is not so simple. QComboBox can also have separator items. The above solution works fine if there are no separator items in QComboBox. To handle separators the item delegate should also know about them.

It is possible to subclass QStyledItemDelegate and copy required functions from Qt private implementation of QComboBoxDelegate. That solution is not very nice. It may be non-portable with new Qt versions. The implementation of QComboBoxDelegate in Qt5 is not compatible with Qt4. However, Qt5 can work with Qt4 implementation, so this class can be taken from Qt4. The QItemDelegate base class is replaced by QStyledItemDelegate:

class ComboBoxDelegateStyled : public QStyledItemDelegate
{
Q_OBJECT
public:
ComboBoxDelegateStyled(QObject *parent, QComboBox *cmb) :
QStyledItemDelegate(parent), mCombo(cmb) {}

static bool isSeparator(const QModelIndex &index) {
return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");
}

protected:
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
if (isSeparator(index)) {
QRect rect = option.rect;
if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*>(&option))
if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(v3->widget))
rect.setWidth(view->viewport()->width());
QStyleOption opt;
opt.rect = rect;
mCombo->style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, painter, mCombo);
} else {
QStyledItemDelegate::paint(painter, option, index);
}
}

QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const {
if (isSeparator(index)) {
int pm = mCombo->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, mCombo);
return QSize(pm, pm);
}
return QStyledItemDelegate::sizeHint(option, index);
}
private:
QComboBox *mCombo;
};

It makes sense to subclass QComboBox to use ComboBoxDelegateStyled:

class ComboBoxStyled : public QComboBox
{
public:
explicit ComboBoxStyled(QWidget *parent = 0) : QComboBox(parent) {
setItemDelegate(new ComboBoxDelegateStyled(this, this));
}
};

Now the class ComboBoxStyled can be used instead of QComboBox. It supports combo box separator drawing and also it supports CSS for ::item.

Similar solution for customizing QComboBox separator: how to add stylesheet for separator in QCombobox


PyQt

The above behavior is valid for PyQt. It is possible to remove dotted border using outline and to set styled item delegate to customize CSS ::item:

styledComboBox = QtGui.QComboBox()
delegate = QtGui.QStyledItemDelegate()
styledComboBox.setItemDelegate(delegate)

In such case the combo box separator is displayed as a regular item without text.
It is also possible to create custom delegate to handle separators.

QPushButton visual issue

Found the solution. It turned out to be very simple.

The issue was indeed caused by the button receiving focus. All I needed to do is set the button's focusPolicy attribute to NoFocus. It can be done either in QtDesigner:

Sample Image

or in the code:

ui.okButton->setFocusPolicy(Qt::NoFocus);

After it's done, the clicks on the button will not cause it to get focus, and the appearance will not change.



Related Topics



Leave a reply



Submit