PDA

View Full Version : Retrieve the colours used by Qt to render a frame of StyledPanel shape



agarny
28th March 2012, 19:52
I have a widget of my own and I would like to ensure that the colours I use are consistent with the rest of the widgets I use in my Qt application. For what I am doing, I would need to retrieve the colours used by a frame which shape is set to QFrame::StyledPanel. On my copy of Windows 7, Qt renders the border of such a frame using a colour which RGB value is (130, 135, 144). Now, in my widget, I would like to use that colour, but I can't seem to be able to get it. I tried to get the colour from my widget's palette by using the color() function and passing to it different colour roles (QPalette::Window, QPalette::WindowText, etc.), but none of them gave me the RGB value used by Qt to render the frame above. So, what am I missing?...

Cheers, Alan.

ChiliPalmer
28th March 2012, 22:27
Hi,

depending on the style, not everything is drawn by Qt itself, but by the native style engine. So some Colors etc. are impossible to get.
I had the same issue as you and tried just letting the style draw the frame, which worked fine. But as I only needed part of a frame, I just used the color you mentioned to draw the frame myself.
I guess those are your two options as well ;)

agarny
28th March 2012, 22:39
Well, at this stage, I just need to use the colour I mentioned (even though I would like a more general approach to my problem, if possible), so how did you get it in the end?

ChiliPalmer
28th March 2012, 23:30
I just took a look at the code, as I still would like to get that color as well. But as I said, the frame is drawn by the windows style engine. So no chance getting the color.
As I said, I just draw the frame with the color you mentionend myself.

Lykurg
29th March 2012, 06:08
I don't know what you want to do with that color exactly, but with QStylePainter (or QStyle direct) you can draw frames etc. according to the current style.

agarny
29th March 2012, 07:13
As I said, I just draw the frame with the color you mentionend myself.Ah, so you are really using (130, 135, 144)...?! Ok, that's not something I want to do. I want my applicaiton to be able to respond to a change of system colour theme, if needed.


I don't know what you want to do with that color exactly, but with QStylePainter (or QStyle direct) you can draw frames etc. according to the current style.I just want to be able to use the colour used by Qt to render other widgets, so that it's all consistent colour wise. Anyway, I have never tried QStylePainter, so I will have a look at it, thanks.

agarny
29th March 2012, 12:13
Ok, for those interested, I have 'solved' my problem by doing the following:


static bool firstTime = true;
static QColor borderColor = QColor();

if (firstTime) {
QFrame frame;
QImage image = QImage(widget->size(),
QImage::Format_ARGB32_Premultiplied);

frame.setFrameShape(QFrame::StyledPanel);
frame.render(&image);

borderColor = QColor(image.pixel(0, 0));

firstTime = false;
}

wysota
29th March 2012, 12:23
What if the pixel happens to be transparent in this particular theme? What if the user changes the theme during the life of the program? What if...?

agarny
29th March 2012, 12:38
What if the pixel happens to be transparent in this particular theme? What if the user changes the theme during the life of the program? What if...?I complete agree that this is not perfect, hence my use of single quotes around my use of "solved". So, if anyone has a better solution, then please feel free to share it with me. :) In fact, I just wish that Qt would provide us with more information about the colour scheme used to render various widgets.

wysota
29th March 2012, 12:46
Qt doesn't have anything to do with this. It's not Qt that renders the theme on Windows Vista and up. You can probably use the native API to ask for that colour if the theming API supports it. Qt reports all it can in QPalette. If the colour you are looking for is not there then all that is left is Windows theming API.

agarny
29th March 2012, 12:52
I appreciate that Qt has nothing to do with it, but all I am trying to do is to have my widget using colours that are consistent with the other widgets that are (indirectly) rendered by Qt. Also, I want this to work on Windows, Linux and Mac OS X. So, for now, the solution I have is far from perfect, but it's still better than nothing (I could however improve it to at least address the change of theme during the life of the application).

wysota
29th March 2012, 13:29
I appreciate that Qt has nothing to do with it, but all I am trying to do is to have my widget using colours that are consistent with the other widgets that are (indirectly) rendered by Qt. Also, I want this to work on Windows, Linux and Mac OS X. So, for now, the solution I have is far from perfect, but it's still better than nothing (I could however improve it to at least address the change of theme during the life of the application).

The solution you currently have will fail on Mac and some of the other desktop environments in their default or personalized configurations. Mac draws most of things with rounded corners so at best you will likely hit a transparent area. There are also widget styles that don't draw a border at all or draw a gradient border or do one of the numerous other things that will make your approach fail. Using stylesheets will also make your approach fail on pretty much every possible configuration. As I understand it, you have tested your solution on Windows 7. Did you consider other systems too? You should either assume your code to be unportable and focus on a particular plartform configuration or you should accept the fact that your solution is not a solution at all (not even a "solution") and just do the drawing using QStyle API and QPalette. Especially considering the fact that a border is really a trivial issue. Think about drawing highlights or opaque areas the theme draws as a gradient. You can't possibly emulate that without reverting to the API that originally drew those elements. The final result can be even worse than if you had used a standard approach which works on most systems (which is all excluding Vista+ and MacOSX) out of the box.

agarny
29th March 2012, 15:03
The solution you currently have will fail on Mac and some of the other desktop environments in their default or personalized configurations. Mac draws most of things with rounded corners so at best you will likely hit a transparent area. There are also widget styles that don't draw a border at all or draw a gradient border or do one of the numerous other things that will make your approach fail. Using stylesheets will also make your approach fail on pretty much every possible configuration. As I understand it, you have tested your solution on Windows 7. Did you consider other systems too? You should either assume your code to be unportable and focus on a particular plartform configuration or you should accept the fact that your solution is not a solution at all (not even a "solution") and just do the drawing using QStyle API and QPalette. Especially considering the fact that a border is really a trivial issue. Think about drawing highlights or opaque areas the theme draws as a gradient. You can't possibly emulate that without reverting to the API that originally drew those elements. The final result can be even worse than if you had used a standard approach which works on most systems (which is all excluding Vista+ and MacOSX) out of the box.
Ok, what I am after is drawing a border (or part of a border, e.g. only the top part of a border) around a widget using a colour which is consistent with those used by other widgets.

I have indeed tested my current approach on Windows 7, but also on Mac OS X (Lion) and Ubuntu (11.10), and it all works as expected. Now, I agree that there is no guarantee whatsoever that it would work in some other random settings, and I have never claimed that it would.

Regarding QStyle (and QStylePainter), I have looked into it and it would work fine for a full border (I have tried it), but what about the case where I only need part of a border?...

ChiliPalmer
29th March 2012, 16:50
What if you would let the QStyle draw a frame onto a QPixmap with the same dimensions as your widget, cut of the part you don't need, and draw the pixmap as your frame? If you can't just draw the rest of your widget over the part of the border you don't need.

wysota
29th March 2012, 17:05
Ok, what I am after is drawing a border (or part of a border, e.g. only the top part of a border) around a widget using a colour which is consistent with those used by other widgets.
Why don't you use QStylePainter::drawPrimitive() with QStyle::PE_Frame (or similar) then?


Regarding QStyle (and QStylePainter), I have looked into it and it would work fine for a full border (I have tried it), but what about the case where I only need part of a border?...
What exactly do you mean with "part of a border"? You can probably still do it for most cases as the style should report the width of a frame through QStyle API (probably as a pixel metric). If you have that size, you can introduce clipping to draw only the part you need. However I can't think of a case where you'd only want to draw one side of a frame, that wouldn't be a frame anymore, would it?

agarny
29th March 2012, 17:48
What exactly do you mean with "part of a border"? You can probably still do it for most cases as the style should report the width of a frame through QStyle API (probably as a pixel metric). If you have that size, you can introduce clipping to draw only the part you need. However I can't think of a case where you'd only want to draw one side of a frame, that wouldn't be a frame anymore, would it?Well if you consider that a border consists of a top, left, bottom and right edges, then a full border would have all four edges rendered, and yes it works fine using QStylePainter::drawPrimitive() with QStyle::PE_Frame. However, I am not sure I could use something similar just to render, say, the top edge alone (i.e. no left, bottom or right edge). Then again, I haven't tried, so who knows it might be possible...?

wysota
29th March 2012, 21:11
Ok but what for do you need just the top part of a "3D" frame?

agarny
29th March 2012, 21:50
Ok but what for do you need just the top part of a "3D" frame?First, an edge consists of a one-pixel wide line in my case. Otherwise, I have a QWebView-based widget which I use in a window which can either be docked or not. When it's docked, that widget doesn't look good (to me, at least), so I add a full frame around it, this on Windows and Linux while only a top edge on Mac OS X. Then, when the window isn't docked, I have only a top edge on all three platforms. So, that's it, it's purely for aesthetics.

wysota
29th March 2012, 22:28
So basically you have a one pixel wide line and not a part of a frame which is usually at least two pixel wide (see QStyle::pixelMetric for PM_DefaultFrameWidth) :) Why don't you just use one of QPalette's Light, Midlight, Dark, Mid or Shadow values?

agarny
29th March 2012, 23:04
So basically you have a one pixel wide line and not a part of a frame which is usually at least two pixel wide (see QStyle::pixelMetric for PM_DefaultFrameWidth) :) Why don't you just use one of QPalette's Light, Midlight, Dark, Mid or Shadow values?Yes, a one-pixel wide line. I honestly can't remember of wide the frame was when I tried QStylePainter::drawPrimitive(). I just know that it worked for the full frame. Anyway, I did succesfully use QPalette's Light, Midlight, etc. values before, but none of them corresponds to the actual colour used by the theme to render a frame, hence my original message. :)

wysota
29th March 2012, 23:32
My main point is that you can't get an OS agnostic consistent look (I don't think the theme draws such one pixel lines anywhere), so there is a question if it is worth trying at all.

agarny
30th March 2012, 10:14
My main point is that you can't get an OS agnostic consistent look (I don't think the theme draws such one pixel lines anywhere), so there is a question if it is worth trying at all.I agree with your statement in general, but it happens that what I did looks good on Windows, Linux and Mac OS X, so...

Otherwise, the theme does draw one pixel lines (or frames rather). This is, in fact, the reason I decided to do the same for my derived widget.

wysota
30th March 2012, 10:25
I agree with your statement in general, but it happens that what I did looks good on Windows, Linux and Mac OS X, so...
On your Windows, your Linux, your MacOS X configurations.

If that's fine with you then ok just bear in mind people have different configurations of their systems and something that looks good on your system doesn't have to look good on mine.

agarny
30th March 2012, 10:44
On your Windows, your Linux, your MacOS X configurations.

If that's fine with you then ok just bear in mind people have different configurations of their systems and something that looks good on your system doesn't have to look good on mine.Very true and this is why I am ready to revert things, if ever needed.