c++ - Using the effect causes the background to turn black - Stack Overflow

admin2025-04-20  0

When I was using Qt, I applied a blur effect to a QWidget that is a window. The code looks like this:

#include <QGraphicsBlurEffect>
#include <QApplication>
#include <QWidget>
int main(int argc, char** argv) {
    QApplication app(argc,argv);
    QWidget window;
    auto blur = new QGraphicsBlurEffect;
    window.setGraphicsEffect(blur);
    window.show();
    return app.exec();
}

However, the result was that the window's background turned completely black:

I have gone through the official documentation, but I still don't understand why this happened. The official documentation doesn't mention that it can't be used on such a QWidget.

I thought it might be a platform issue, so I cross-compiled the program and had my friend run it. However, this did not change the result.

Note: My system is Ubuntu ARM64 with X11, while my friend's is Windows x86.

The issue remains the same even when I tried using the latest version 6.8.2. My current Qt version is 6.5.4.

I used the sourcePixmap member function of QGraphicsEffect to inspect the source pixmap that was drawn, and displayed it in an additional window. To prevent the background color of the previous window from interfering with the observation, I set the background color of this window to green.

At the same time, I added a QLabel to the original window to display the text "Hello World." Since the window background had turned black, I set the text color to white. Here is the screenshot of the running program:

Note: I have tried this on other platforms, and the following issues have not been replicated on other platforms.

However, when I resized the window, a rendering error occurred, and green appeared (I didn't set the background color of all windows to green):

Even though I used setAutoFillBackground(true), there was still a hint of green around the window edges:

I think this may be the BUG of Qt. Or some other reason.

When I was using Qt, I applied a blur effect to a QWidget that is a window. The code looks like this:

#include <QGraphicsBlurEffect>
#include <QApplication>
#include <QWidget>
int main(int argc, char** argv) {
    QApplication app(argc,argv);
    QWidget window;
    auto blur = new QGraphicsBlurEffect;
    window.setGraphicsEffect(blur);
    window.show();
    return app.exec();
}

However, the result was that the window's background turned completely black:

I have gone through the official documentation, but I still don't understand why this happened. The official documentation doesn't mention that it can't be used on such a QWidget.

I thought it might be a platform issue, so I cross-compiled the program and had my friend run it. However, this did not change the result.

Note: My system is Ubuntu ARM64 with X11, while my friend's is Windows x86.

The issue remains the same even when I tried using the latest version 6.8.2. My current Qt version is 6.5.4.

I used the sourcePixmap member function of QGraphicsEffect to inspect the source pixmap that was drawn, and displayed it in an additional window. To prevent the background color of the previous window from interfering with the observation, I set the background color of this window to green.

At the same time, I added a QLabel to the original window to display the text "Hello World." Since the window background had turned black, I set the text color to white. Here is the screenshot of the running program:

Note: I have tried this on other platforms, and the following issues have not been replicated on other platforms.

However, when I resized the window, a rendering error occurred, and green appeared (I didn't set the background color of all windows to green):

Even though I used setAutoFillBackground(true), there was still a hint of green around the window edges:

I think this may be the BUG of Qt. Or some other reason.

Share Improve this question edited Mar 5 at 2:45 YuXin asked Mar 2 at 11:44 YuXinYuXin 717 bronze badges 18
  • Please read How to Ask. All code etc. should provided as correctly formatted text in the question. – G.M. Commented Mar 2 at 11:51
  • 1 What happens if you add a child widget and set the graphics effect on that instead? Note that the painting of a widget has a slightly different behavior when the widget is the top level window. – musicamante Commented Mar 2 at 17:09
  • 1 @musicamante Might be not theircase, lately I found that comments are broken right after they added this stupid "say thank you" option. If I write comment from mobile device (literally mobile, I don't mean just phone) long enough and my netweork environment changed , comments error-out. I looks like something times out. – Swift - Friday Pie Commented Mar 4 at 8:08
  • 1 @Swift-FridayPie I just checked, and I'm completely able to edit a comment on the same mobile device when changing to a different network. Maybe there was an underlying change when the OP did all that, but considering their rep, I'd still stick with an educated guess and assume they just deleted/reposted. That said, I cannot agree more: the revival of that "thank you" option is yet another stupid feature nobody asked for, but, as usual, they keep ignoring actual user input, even though almost everybody told them it's pointless and there are more important issues that should be cared about... – musicamante Commented Mar 12 at 3:48
  • 1 @Swift-FridayPie It seems strange the new editor could affect comments, but nothing's impossible. In any case, you can opt out the editor in your SO user settings to keep using the old one. – musicamante Commented Mar 12 at 19:20
 |  Show 13 more comments

1 Answer 1

Reset to default 5

tl;dr

Just add the following line before showing:

    window::setAutoFillBackground(true);

Explanation

This is technically a bug, caused by a simplification of the QWidget painting system probably done to let the developer assume that the painting behavior of a top level widget is identical to that of a child one.

Your doubts about the QWidget specificity are also mislead: all widgets in Qt derive from QWidget, so there is actually no difference in applying a graphics effect to any other widget type, as they all are QWidgets.

The difference, in reality, is in the fact that your window is a top level widget: a window.

Widget painting basics

When a QWidget is being drawn, its paintEvent() creates as QPainter object that, most of the times, draws over an existing painting surface, which normally is the parent, and that parent can also be the window.

The concept is similar to physical painting, where you always draw above something: a canvas, or anything else that was previously drawn on it. Similarly, child painting works by drawing above the background.

By default, widgets are always transparent and eventually draw on the background their contents.
The problem comes when drawing a widget that is also a top level one: a window.

In that case, Qt needs to draw a background, and eventually tell that widget to draw on that. For top level widgets, it therefore queries the widget style and palette and draws that background on its own, then calls the widget's paintEvent().

Also remember that Qt painting is a relatively high abstraction API: the generic QPainter class allows us to virtually draw on anything, even though we're actually drawing onto very different surface types: functions like QPainter::drawRect() make our lives easy, but what those functions do is often very different depending on "what" we're drawing onto.

This is why using a Qt Style Sheet that sets basic painting rules for widgets only works for top level windows but not for child widgets (which would require setting the Qt::WA_StyledBackground attribute for the instance, or overriding the paintEvent() of the class as the docs suggest).

The same widget will therefore be painted (possibly) differently whether it's a top level one or a child of another, and the autoFillBackground property is actually important on that matter, as it may be implied for top level widgets.

The palette usage

Similarly to the physical drawing explained above, the "palette" is exactly as a physical palette; it is just a start reference, what and how it's used is up to the widget or its usage of QStyle, exactly as an actual painter would do: the fact that they have a palette made of black and white doesn't prevent them to blend those color, possibly never using neither white or black at all.

By default, the "background" of a widget is never drawn: just like other palette colors, it's just a "color rule". The behavior is similar to that of QWidget subclasses when using QSS.
Each widget (or style) may use that color for specific parts of the widget, or even completely ignore it.

That said, if the widget is a top level, Qt then must set a background no matter what.

Draw on something

The first step is to clear the window background (actually, the paint buffer) to a completely black color, or, to be precise, to a "black transparent" color. The assumption is that the the final background of the window will eventually completely draw upon that color (if the window is opaque) or eventually composite-draw on a partially transparent window.
Then, Qt will assume the widget's background as the window background, even though it's not expected to draw its background. If the window is not actually transparent, that "black transparent" will just become a full opaque black.

Some Qt graphics effects actually involve an alpha channel that blends the contents of the target with the background. This is specifically the case of QGraphicsBlurEffect, which must be able to blend its blurred contents with the background. This is achieved by capturing the widget contents, using the render() function of QWidget, onto a theoretically transparent QPixmap.

Now, since the effect draws on a previously set background (the "full opaque black" above assumed for the top level widget) the resulting effect blends the blurred contents using that color as reference, thus resulting in a completely black background, because the widget does not auto fill its own background in the render() function.

To clarify the above, you can see a quite similar effect by setting the Window role of the QApplication palette() with a color having an alpha value less than 255 and showing a simple QWidget:

    ...
    QPalette pal = QApplication::palette();
    pal.setColor(QPalette::Window, QColor(255, 0, 0, 127));
    QApplication::setPalette(pal)
    QWidget window;
    window.show();
    ...

Note: I'm not a C++ developer, so the above syntax is probably wrong; still, the code logic should be clear enough.

The above will show a window with a dark red background, because the 127 (half) transparency of the full red is blended on top of the black background originally cleared for the opaque window. On some styles it may even result in a gradient.

This means that the blur graphics effect will always try to blend the output of the widget's paintEvent() (and/or its background palette, also considering the style) with the black background.

A simple solution, and further considerations

Considering all the above, as long as the color for the background role of the widget is opaque, using setAutoFillBackground(true); should be enough to ensure that the top level widget will have an appropriate color, and the blur effect will eventually work with that.

Note that using QSS that affect the top level widget may also have unexpected results on graphics effects. In that case, especially if the QSS is applied on widgets and not on the whole QApplication (or the parents), it may be necessary to explicitly call the effect's update() call whenever repainting is required, which should be whenever any of the following events happen either on the target of the effect or its children (possibly using an event filter in that case):

  • QEvent::Resize
  • QEvent::StyleChange
  • QEvent::PaletteChange
  • QEvent::ParentChange

Finally, although "technically a bug", all the above shows that it's also partially by design, and working around it may be more (unnecessarily) difficult than required.
Due to the complexity of widget drawing, considering the cross-platform nature of Qt and everything involved with composite managers and different display aspects on *nix platforms, it may be better to report this as a suggestion for the documentation instead of an "actual" bug.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745123648a286297.html

最新回复(0)