PDA

View Full Version : Changing QPalette doesn't affect to its QWidget



Binary91
3rd December 2016, 10:06
Hello everybody,

I try to create a window with multiple QLineEdits and QPushbuttons that are grouped. Each group has a different background color, like, QLineEdits 1-5 are green and its corresponding QPushButton is also green, QLineEdits 6-10 are red and so does its corresponding QPushButton.

What I try to achieve now is updating each group by clicking its corresponding QPushButton.
From start, hence build and first display of the window, all QLineEdits should appear with classic white background. After clicking its corresponding QPushButton, they all should update its background color to green/red.

I could now create a new palette for each QLineEdit, but this would result in much work. An easier solution would be a single QPalette.
I noticed that QLineEdit::setPalette() accepts a reference to the QPalette. So afaik changing the palette should affect to every QLineEdit. Unfortunatelly, it doesn't...

Example:

QLineEdit *edit1 = new QLineEdit;
QLineEdit *edit2 = new QLineEdit;
QPalette palette;

palette.setColor(QPalette::Base, QColor(0,255,0);
edit1->setPalette(palette);
palette.setColor(QPalette::Base, QColor(255,0,0);
edit2->setPalette(palette);The result is that edit1 has a green background and edit2 has a red background. Why changing palette from green to red doesn't affect to edit1?
Could the problem be that QLineEdit::setPalette() accepts a CONST reference? I thought that references are always const, because once initialized, they can't be re-initialized...

Maybe someone can help me with that:)

Kind regards,
Binary

anda_skoa
3rd December 2016, 12:18
I could now create a new palette for each QLineEdit, but this would result in much work. An easier solution would be a single QPalette.

You can pass the same palette object for any number of widgets.



I noticed that QLineEdit::setPalette() accepts a reference to the QPalette

No, it does not.



Why changing palette from green to red doesn't affect to edit1?

Each line edit has its own copy of the palette you passed in



Could the problem be that QLineEdit::setPalette() accepts a CONST reference?

Exactly.



I thought that references are always const, because once initialized, they can't be re-initialized...

A normal reference argument can be changed in the function it is passed to, a const reference argument cannot.
E.g. a non-const reference argument is often used as an output or input/output argument, a const reference is always just an input argument.

A reference member variable can only be initialized once but the object it reference can still be modified.
The initialization needs to happen in the constructor's initialization list, it cannot be done through assignment.

A setter function can never store a reference argument in a reference member.

So even if QWidget had a reference member for its palette and even if setPalette would pass the object by reference, it could not change the object the member references.

Cheers,
_

Binary91
3rd December 2016, 12:55
A reference member variable can only be initialized once but the object it reference can still be modified.
The initialization needs to happen in the constructor's initialization list, it cannot be done through assignment.

A setter function can never store a reference argument in a reference member.So does that mean the setter function just compares the object to which the ref argument points to with its "own" object and changes this instead of "replacing" it?

If yes, how could I realize my purpose? Do I really have to manually change each QLineEdits palette?

d_stranz
3rd December 2016, 18:40
Do I really have to manually change each QLineEdits palette?

Yes, if you want each QLineEdit to have a different set of palette properties. If you use Qt Designer to lay out your form, you can create one QLineEdit, change its properties, then copy and paste it into other places in your form. The copies will have the same properties as the original one. This is not the same as making the change at run time, of course.

anda_skoa
3rd December 2016, 21:53
So does that mean the setter function just compares the object to which the ref argument points to with its "own" object and changes this instead of "replacing" it?

I don't think that the setter compares the old and new value, it is more likely that it will just replace the old value.
But we can check that, can't we? :)

https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#_ZN7QWidget10setPaletteERK8QPalet te
Looks a bit more complicated then just replacing.



If yes, how could I realize my purpose? Do I really have to manually change each QLineEdits palette?

Well, even if you do it manually, you can easily do that with a loop if you put all the line edits into a vector or list.
Or you create a subclass and make setPalette a slot and connect all to the same signal.
Or you use a global stylesheet, etc.

Cheers,
_

Binary91
4th December 2016, 08:31
Well, even if you do it manually, you can easily do that with a loop if you put all the line edits into a vector or list.Yap, that is how I did it (till) now.


Or you create a subclass and make setPalette a slot and connect all to the same signal.
Or you use a global stylesheet, etc.Both sound interesting, but I neighter know how to create own Signals in Qt, nor do I have advanced skills with stylesheets. Maybe I have to take a look at Qt's documentation again.

EDIT:
Well, I see that I can declare a signal like a regular function that is called when I set an "emit mysignal()". I'm asking myself what could be the benefit by using "emit signal()" instead of simply calling the function? Also I do not know how to automate this to avoid work. For my purposes I need something like every QLineEdit recognizes when one single QLineEdit changes its QPalette and they automatically do the same.


Cheers,
Binary

anda_skoa
5th December 2016, 09:29
Well, I see that I can declare a signal like a regular function that is called when I set an "emit mysignal()".

It also needs to be declared in a "signals:" section of the class.



I'm asking myself what could be the benefit by using "emit signal()" instead of simply calling the function?

No difference, the "emit" is "syntactic sugar" to make it obvious to the reader that this is a signal emit, not a normal function call.



Also I do not know how to automate this to avoid work.

You would only need to emit the signal if all your line edits are conncted to it.

Cheers,
_

Binary91
7th December 2016, 08:59
You would only need to emit the signal if all your line edits are conncted to it.I don't understand this. Let's say I have a signal colorChanged(QColor(int,int,int)) which I declare in every of my QLineEdits. Now I subclass the QLineEdit's setPalette function and like this (no correct syntax, just to display the idea):

myQLineEdit::setPalette(QPalette())
{
QLineEdit::setPalette(QPalette());
emit colorChanged();
return;
}Now, changing background color of ONE QLineEdit with setPalette(..) should emit the signal for THIS QLineEdit. But why should all QLineEdits react on this? I mean, if I have 3 QPushButtons and each connected to the signal clicked(), then not all three buttons are clicked when I click one button, right? So in that situation, only the corresponding (clicked) QPushButton emits the signal clicked().

Can you explain what you mean with "all your line edits" react on one signal?:confused:

d_stranz
7th December 2016, 15:32
I think you have the logic a little inside-out. It is the line edits that should react to the signal sent from somewhere else. In your MainWindow class (or whoever owns the line edits), you implement both the slot for setting the new palette on all of the line edits as well as the signal that gets emitted when a new palette should be set on a line edit.



// constructor
MainWindow::MainWindow( QWidget * parent ) : QMainWindow( parent )
{
// usual setup stuff here

connect( this, &MainWindow::paletteChanged, this, &MainWindow::onPaletteChanged );
}

// slot pseudocode; slot declared in "slots" section of class definition
void MainWindow::onChooseColor()
{
QColor newColor = QColorDialog::getColor( ... );
if ( newColor.isValid() )
{
QPalette newPalette;
palette.setColor( QPalette::Window, newColor );
emit paletteChanged( newPalette ); // Your signal, defined in "signals" section of MainWindow class definition
}
}

// slot pseudocode; slot declared in "slots" section of class definition
void MainWindow::onPaletteChanged( const QPalette & newPalette )
{
foreach( QLineEdit * pEdit in ui )
{
if ( pEdit->palette() != newPalette )
pEdit->setPalette( newPalette );
}
}


One way to do it, assuming you want all of the line edits to have the same color. Why you'd want to do that, I don't know. Usually color changes are used to indicate specific things about specific items in a UI, like a red background to indicate an error in a line edit entry. You don't change all of them to red, just the bad ones. One the other hand, if you are providing an app that has custom skinning, then this would make sense in that context.

You cannot avoid looping through the line edits to set each one's palette. If you derive from QLineEdit and implement a custom signal / slot combination on the derived class to do this, you still, at some point, have to loop over all of the line edit instances to hook up the signal and slot for all of them. Nothing is going to make a QWidget magically respond to some external change unless you tell it to, and that's by way of a signal / slot connection or event handler.

Binary91
7th December 2016, 17:22
You cannot avoid looping through the line edits to set each one's palette. If you derive from QLineEdit and implement a custom signal / slot combination on the derived class to do this, you still, at some point, have to loop over all of the line edit instances to hook up the signal and slot for all of them. Nothing is going to make a QWidget magically respond to some external change unless you tell it to, and that's by way of a signal / slot connection or event handler.Aaah, then I really misunderstood him. But this is what my "logic" was about. I was just wondering how any other QLineEdit could react on a signal of a specific QLineEdit... Well, then I don't need to create own signals.


Why you'd want to do that, I don't know. Usually color changes are used to indicate specific things about specific items in a UI, like a red background to indicate an error in a line edit entry. You don't change all of them to red, just the bad ones.Exactly what I'm doing. I have groups of QLineEdits within QVectors. Each group is connected to a QPushButton (Button Step1, Step2 and so on). When the button is clicked, I loop through the corresponding QVector list and change its QLineEdits to mark them as "active".

Ok, thank you guys for your help.

Kind regards,
Binary

anda_skoa
8th December 2016, 15:25
Let's say I have a signal colorChanged(QColor(int,int,int)) which I declare in every of my QLineEdits.

No. The signal would be on the class that triggers the change.

The line edits would have a matching slot.

E.g. a changePalette(const QPalette&) signal and a "setPalette(const QPalette&)" slot in your line edit class.

Cheers,
_