Unsolved QSpinBox cannot set its QLineEdit background colour under Linux
-
I'm amending my code snippet above so that it works properly with scroll areas and tree views. The row of the
QModelIndex
won't tell you the row needed for accurate alternate coloring. i.e. you need the row relative to the top of the scroll area and, for item views, the data above you might also be in various states of expand/collapse.In digging through the Qt code, I notice that the
QStyleOptionViewItem
delivered to delegate'screateEditor
does not carry the featureQStyleOptionViewItem::Alternate
. That bit is added by the tree view indrawRow
. This is too bad since that bit could directly tell us whether or not we're on an alternate row. That bit is sent into the delegate'spaint
function however, so you could play with it there.QWidget *SpinboxDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { QSpinBox *editor = new QSpinBox(parent); editor->setAlignment(Qt::AlignRight); editor->setAutoFillBackground(true); const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(option.widget); if (view) { // determine row that the index is sitting on relative to top of scroll area const QRect rect = view->visualRect(index); const int pos = view->verticalScrollBar()->value(); const int row = pos + (rect.top() / rect.height()); // hack to grab protected QLineEdit from QSpinBox parent auto line_editors = editor->findChildren<QLineEdit*>(); QLineEdit *line_editor = !line_editors.empty() ? line_editors.front() : nullptr; if (line_editor && index.isValid()) { // line editor background color set to current row background color const QPalette app_palette = qApp->palette(); QPalette palette = line_editor->palette(); palette.setColor(QPalette::Base, row % 2 ? app_palette.color(QPalette::AlternateBase) : app_palette.color(QPalette::Base)); line_editor->setPalette(palette); } } editor->setFrame(false); editor->setMinimum(-100000); editor->setMaximum(100000); return editor;
-
Hi,
I currently wonder whether it's something that should be available there. Did you check the bug report system to see if there's something related ? If not, you could open a feature request.
-
@SGaist In the context of delegates, the editor is created by the
QAbstractItemView
on this line of code and if you trace it back, you can see thatopenEditor
is not adding the option features thatdrawRow
adds in theQTreeView
derivation for thepaint
calls. Not sure it would be easy to add that style feature on that abstract class. Perhaps. -
@SGaist
Are you addressing this to @Phil-K or to myself?I wrote earlier that I reported this bug as https://bugreports.qt.io/browse/QTBUG-83961 9 months ago, but haven't had any takers :) [Other than 2 non-expert replies, to which I responded as both were wrong!]
I can't say for @Phil-K's response now. But, at least in my non-edit case, one should not need to write some set of code. There is just something fundamentally wrong in Qt's internal code for handling the
QLineEdit
part of aQSpinBox
, at least so far as my coloring via stylesheet is concerned. -
At @Phil-K but somehow I managed to miss the link to the existing report... vertical scrolling is sometimes treacherous.
The current answers are indeed inadequate.
-
I necro'd the thread and went off on a tangent. Scrolling is not relevant to the original problem. The style painter is painting that
QSpinBox
with a call frompaintEvent
todrawComplexControl
so you would need to trace the drawing code through the style machinery to see what's happening. As a workaround you can set the stylesheet for theQSpinBox
instead of the editor, but you'll have to adjust the buttons using theQSpinBox::up-button/::down-button
subcontrol selectors. Too bad there isn't a subcontrol css selector for the QLineEdit itself. That would help. Also, I note that the css selectors for children (#qt_spinbox_lineedit or QSpinBox > QLineEdit) indeed don't seem to work in this context, so the drawing code is probably using the spinbox style settings and ignoring the rest. -
@JonB Here's a fast workaround that you may like. Give the parent widget an object name and set its stylesheet using the #id selector. That will prevent the problematic propagation to the QLineEdit of the QSpinBox. Cheers.
#include <QApplication> #include <QLineEdit> #include <QSpinBox> #include <QVBoxLayout> #include <QWidget> int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w; QVBoxLayout layout; w.setGeometry(100, 100, 200, 200); w.setLayout(&layout); // Use #id selector to prevent propagation w.setObjectName("my_widget"); w.setStyleSheet("#my_widget {background-color: yellow; color: green;}"); QLineEdit *lineEdit = new QLineEdit; layout.addWidget(lineEdit); lineEdit->setText("50"); lineEdit->setStyleSheet("background-color: cyan; color: red;"); QSpinBox *spinBox = new QSpinBox; layout.addWidget(spinBox); QLineEdit *spinLineEdit = spinBox->findChild<QLineEdit *>(); spinBox->setMaximum(100); spinBox->setMinimum(-100); spinBox->setValue(50); spinLineEdit->setStyleSheet("background-color: blue; color: red;"); w.show(); return a.exec(); }
-
@Phil-K
Hi Phil. Yes, I realize what you are doing here, but unfortunately this does not do the job correctly enough for my requirements.Firstly, the result of yours is:
Compare that to the correct one I show earlier above. Not surprisingly, while the line edit itself is now correct colors, the spinbox "furniture" around it has now lost the desired background yellow of the whole form and is shown in the default "grey".
Secondly, I had to cut mine down to a minimal example. In practice I have a top-level background-colored widget, whose color I want inherited everywhere except when overridden, then I have a potentially-unknown hierarchy of further sub-widgets, and at the bottom I have a
QSpinBox
. Colored-widget -> widget -> widget -> ... -> spinbox. And I have loads of theseQSpinBoxes
. Setting the color on the top-level widget by id will limit it to that widget only, and there is no chance of picking out all the direct parent widgets of the child spinboxes for application of some distant, top-level color which may have been specified.The problem, it seems to me, must be addressed on the
QSpinBox
itself, not higher up the hierarchy. And the issue is that somewhere in the Qt code there is some "unusal" handling of theQSpinBox::lineEdit()
such that you cannot get it to respect its own stylesheet rule iff some ancestor does specify colors. Tackling this somehow at a "top-level" widget cannot be the solution. I refer you again to my example which shows that a standaloneQLineEdit
does behave correctly in this situation, while theQLineEdit
internal to aQSpinBox
does not in the same situation. This is aQSpinBox
-alone issue. Which is what I need resolved or at least explained! -
@JonB Well my suggestion is to read the Qt code and find the exact areas where the problem exists and propose a patch on your bug report. I had an old boss many years ago who said "Don't come to me with a problem. Come to me with a problem, three solutions and a recommendation." Good luck.
-
@Phil-K
Yes the solution to any question Qt can be read the code and find out for yourself. Difficult when I have never compiled Qt, can't step through the code, and am looking to try to find out why some stylesheet rule is or is not overridden by some inheritance elsewhere, which I'm pretty sure will be convoluted/a minefield to work out. Which is why I raised it as a bug at bugreports, in the hope that someone who maintains that code might post an answer. But not. Thank you for your interest.