PDA

View Full Version : White background in window, getting desperate!



dictoon
28th December 2009, 19:34
Hello all,

Sorry in advance if this question has an obvious answer, or if it's already been answered to death on forums. I spent a considerable amount of time and effort trying to find an answer, without luck.

For some reason, the (top level) windows of my application all seem to have a white background. Usually, it isn't noticeable (and isn't a problem, possibly apart from a small performance hit), but there are two situations where it appears and gets annoying:

1. When I resize a window by dragging its top or left borders (and only those), the content of the window is drawn with a slight lag, and the white background appears briefly on the bottom (respectively right) side the window, filling the gap created by the resizing.

2. More annoyingly, when I call show() or showNormal() on a top level window that has been previously hidden, there is a very noticeable and distracting white flash, before the content of the window is rendered. If I delay the program execution a few seconds, right after the call to show() or showNormal(), I can confirm that the window first appears completely white, and only after that its content gets rendered on top (when a paint event gets processed?). Note that this white background *does not* appear when a window is show()'ed for the first time after it was created, it only shows when the window was first hidden (using hide() or close()) and then showed again (using show() or showNormal()).

Two additional notes: (1) the entire app is styled using stylesheets (and only stylesheets); (2) all my windows inherit from QWidget.

I have tried many things (and possibly many nonsensical ones, in despair) to either get rid of the white background altogether, or make it transparent, or hide the double draw, but none of them worked:

- calling setAttribute(Qt::WA_NoSystemBackground) in the constructor of my window
- calling setAutoFillBackground(false) (but IIRC this is the default) in the window ctor
- wrapping the window->showNormal() call with setUpdatesEnabled(false) and setUpdatesEnabled(true)
- replacing window->showNormal() by window->showMinimized() followed by window->raise()
- moving the window to (-10000, -10000) before calling showNormal(), then moving it back to its original position
- etc.

I'm using Qt 4.5.2 on Windows Vista SP1.

Thanks for your help.

Cheers,
Franz

high_flyer
29th December 2009, 10:12
why don't you just set the desired background in the stylesheet?

dictoon
29th December 2009, 12:38
why don't you just set the desired background in the stylesheet?

Sorry if I wasn't clear: my stylesheet *does* set the background color for the widgets (and for the windows in particular). As I said, everything is working properly: my application is properly styled, has the right colors, is correctly rendered, etc.

BUT, it seems that when a hidden window is showed again using show() or showNormal(), FIRST the window is brought to the screen with a completely white background (and nowhere in my stylesheet do I ask for that), and only THEN the white background is completely replaced by the actual content of my window (which isn't white).

It looks to me like calling show() on a window triggers two distinct events (distinct in time, leaving a gap for visible flickering): (1) show the window on screen, (2) render the content of the window.

I would expect that event (1) either:
- show a window with its content fully rendered (obviously the best solution)
- OR show a window with the background set to my background color (dark gray)
- OR show a window with a completely transparent background

Thanks for the help.

Cheers,
Franz

squidge
29th December 2009, 14:29
What is probably happening is that the Window is getting a 'Erase Background' message followed by a 'Redraw' message, so it erases the background to the default color, and then the renderer kicks in and draws it how you want it. Since the contents of the window have been invalidated, it doesn't know the contents, so has to erase first to ensure consistency. This will sometimes cause a slight flicker.

dictoon
29th December 2009, 14:57
What is probably happening is that the Window is getting a 'Erase Background' message followed by a 'Redraw' message, so it erases the background to the default color, and then the renderer kicks in and draws it how you want it. Since the contents of the window have been invalidated, it doesn't know the contents, so has to erase first to ensure consistency. This will sometimes cause a slight flicker.

Hey, thanks for your input.

I'm not sure this is really what is happening; in particular, I'm not sure there is an Erase Background message being sent at all. As I said in my original post, I'm able to see the window being brought to screen with a white background (I don't think any event gets processed, the window already has a white background, somehow). Then there's definitely a Redraw event being fired and processed, that cause the window content to appear and overwrite the white background.

Given a window 'window' that was previously hidden using window.hide(), if I do the following:

window.show();
sleep(3 seconds);

Then the following things happen:

1. A window appears on screen, with its border, its title bar, and a fully white background, and stays visible like that for 3 seconds.
2. The contents of the window appears and overwrite the white background.

I don't think any events is processed between window.show() and sleep(3 seconds). Note that sleep is just pausing the execution of the current and only thread of my application.

On the other hand, if I do the following:

MyWindow window;
window.show();
sleep(3 seconds);

Then the following happens:

1. A window appears on screen, with its border, its title bar, and NO BACKGROUND (or a fully transparent background). Things stay like that for 3 seconds.
2. The contents of the window appears and fills the void space.

Cheers,
Franz

squidge
29th December 2009, 16:24
This is correct behavior on Windows, nothing will be drawn until the window gets a draw event, which can't occur until the sleep function has completed and the event loop continued. Qt will not attempt any drawing event (which includes the window background) until it gets such an event.

dictoon
29th December 2009, 16:40
This is correct behavior on Windows, nothing will be drawn until the window gets a draw event, which can't occur until the sleep function has completed and the event loop continued. Qt will not attempt any drawing event (which includes the window background) until it gets such an event.

Indeed. So this (some kind of Erase Background event being fired & processed) is not the reason for my window to have a white background beneath its real content. Which is the problem I'm trying to solve.

Any idea?

Cheers,
Franz

squidge
29th December 2009, 20:32
If you double buffered the window (Not sure how you do this in Qt, as I've only done it in MFC), then Windows keeps an entire copy of your window in memory. Therefore when the window is shown, it will have the old contents until it's redrawn rather than being white.

Or, perhaps a hack/trick: you could resize the window to 1x1, show the window, let Qt kick it's redraw event, then resize it again and maybe it'll be invalidated and resized in the same paint event?

Other than that, I've no idea. It's not something I've come across in Qt, as all my Window backgrounds are white.

dictoon
30th December 2009, 09:15
If you double buffered the window (Not sure how you do this in Qt, as I've only done it in MFC), then Windows keeps an entire copy of your window in memory. Therefore when the window is shown, it will have the old contents until it's redrawn rather than being white.

As far as I know, in recent versions of Qt (I'm using Qt 4.5.2), all windows are double-buffered. Or are you talking about another form of double buffering?


Or, perhaps a hack/trick: you could resize the window to 1x1, show the window, let Qt kick it's redraw event, then resize it again and maybe it'll be invalidated and resized in the same paint event?

Hm, I'd rather avoid having to do that :) But it could be interesting, as an experiment to figure out what is really happening.


Other than that, I've no idea. It's not something I've come across in Qt, as all my Window backgrounds are white.

Well, thanks for your input so far.

I'm definitely looking for a solution for this problem. It basically surfaces every time a window is supposed to have a non-white background: for some reason there is still a white background being rendered underneath the real window contents, and it gets visible in some situations.

I believe I need to demonstrate the effect with a small sample and post the binary here, in order to show how bad it can occasionally get.

In any case: Qt experts, please shed some light on this issue :)

Cheers,
Franz

dictoon
30th December 2009, 10:46
Here (http://appleseedhq.net/stuff/WhiteBackgroundProblem.zip) is a Win32 executable that demonstrates the problem. The file is somewhat large (5 MB) because I included all the required DLL.

Clicking the button "Hide And Show This Window At Normal Speed" executes this code:



void MainWindow::hide_show()
{
hide();
show();
}


Clicking the button "Hide And Show This Window In Slow Motion" executes this one:



void MainWindow::hide_show_slow()
{
hide();
Sleep(1000);

show();
Sleep(1000); // Here you'll have one second to see the white background of the window, before the paint event kicks in and display the gray background on top of it.
}


The application is styled using this stylesheet:



QWidget
{
background-color: rgb(50, 50, 50);
}

QPushButton
{
background-color: rgb(150, 150, 150);
}


Cheers,
Franz

faldzip
30th December 2009, 12:11
can you share the source code of this example?
I ran it on my Windows7 x64 and there is no white background even with slow motion button.
Later I'll try it on WinXP.

dictoon
30th December 2009, 12:58
can you share the source code of this example?

Sure, here (http://appleseedhq.net/stuff/WhiteBackgroundProblemSources.zip) we go.


I ran it on my Windows7 x64 and there is no white background even with slow motion button.
Later I'll try it on WinXP.

That's very interesting, thanks. I'd be curious to know if maybe the problem is specific to Vista x64, or even to my machine (Dell Latitude E6500 with some Intel GPU).

Cheers,
Franz

Lesiok
30th December 2009, 14:08
Calling Sleep() You are blocking a thread and event loop. Window is repainted in more when one event. Just replace Sleep() with mySleep like this :

void MainWindow::mySleep( int ms )
{
QEventLoop loop;

QTimer::singleShot(ms,&loop,SLOT(quit()));
loop.exec();
}

dictoon
30th December 2009, 14:19
Calling Sleep() You are blocking a thread and event loop. Window is repainted in more when one event. Just replace Sleep() with mySleep like this :

void MainWindow::mySleep( int ms )
{
QEventLoop loop;

QTimer::singleShot(ms,&loop,SLOT(quit()));
loop.exec();
}


Hi, thanks for your answer. However, please read the thread from the beginning. I'm blocking the thread (and the event loop) on purpose, in order to demonstrate a problem (bug?) that I have hit with Qt.

By the way, just to gather some more stats: have you tried the application demonstrating the problem? If so, do you see the window's background being filled to white before the window's content gets rendered? What's your operating system?

Cheers,
Franz

squidge
30th December 2009, 15:35
I don't get it white. I get the window drawn with no background (or a completely transparent background, depending on how you want to describe it) until the event loop draws the window.

I really don't think this is a Qt problem, but more like how the OS handles Windows.

[This is under WinXP 32-bit]

dictoon
30th December 2009, 16:05
I don't get it white. I get the window drawn with no background (or a completely transparent background, depending on how you want to describe it) until the event loop draws the window.

I really don't think this is a Qt problem, but more like how the OS handles Windows.

[This is under WinXP 32-bit]

Interesting, thanks for the input.

So, it does seem to be platform-specific and even Windows-version specific. I'd be interested to know if it's Vista x64 only. I doubt that it is worth spending more time on this issue if the problem is limited to this platform.

Cheers,
Franz

Lesiok
30th December 2009, 17:50
Hi, thanks for your answer. However, please read the thread from the beginning. I'm blocking the thread (and the event loop) on purpose, in order to demonstrate a problem (bug?) that I have hit with Qt.

By the way, just to gather some more stats: have you tried the application demonstrating the problem? If so, do you see the window's background being filled to white before the window's content gets rendered? What's your operating system?

Cheers,
Franz

Yes, I have tried this demo and have this same behaviour as fatjuicymole. After changing sleep method all is working perfect.
On Windows VISTA with AERO background is white, without AERO window have no background. This is a problem with Windows not with Qt.
And in Yours real application You must blocking event loop with some long process.

dictoon
30th December 2009, 18:09
Yes, I have tried this demo and have this same behaviour as fatjuicymole. After changing sleep method all is working perfect.
On Windows VISTA with AERO background is white, without AERO window have no background. This is a problem with Windows not with Qt.
And in Yours real application You must blocking event loop with some long process.

About the sleep method: again, I inserted calls to Sleep() in order to block the current thread and prevent messages from being processed, *intentionally*. This is just a test app to demonstrate the problem, and make it obvious.

About Aero: that's very interesting, I didn't think of trying with Aero disabled. So this seems to confirm that it's a Windows bug, and that's it's specific to Vista+Aero. Would love to find a workaround on this platform. Good to know that the problem does not seem to be reproducible on Windows 7.

Thanks for your input.

Cheers,
Franz

Lesiok
31st December 2009, 07:13
About the sleep method: again, I inserted calls to Sleep() in order to block the current thread and prevent messages from being processed, *intentionally*. This is just a test app to demonstrate the problem, and make it obvious....

I know this. Therefore I wrote in my last clause And in Yours real application You must blocking event loop with some long process (called after showing window).

dictoon
31st December 2009, 08:35
I know this. Therefore I wrote in my last clause And in Yours real application You must blocking event loop with some long process (called after showing window).

Of course in my real app I don't have any sleep(), nor do I have any long process running :) I just have a very basic window, with half a dozen very basic controls. It's just that this window (like all windows of my application) has a dark gray background, and when I bring it to the screen -- by calling show() on it -- there's a very noticeable, very disturbing white flash due to the fact that the window first appears with a completely white background, leaving a small delay until the real window contents gets rendered.

Cheers,
Franz