PDA

View Full Version : Qt application won't repaint until first resize



ComServant
10th January 2015, 03:56
Recently, my Qt application has stopped repainting widgets when they are hovered over, so no visual changes occur to buttons or other widgets when they are hovered. I don't think the buttons even know they are getting hovered at all, but they are receiving mouse clicks, which is triggering the proper signals and reaching the connected slots. This behavior changes the first time the window gets resized - suddenly, even widget can be hovered with visual changes again, for the rest of the application's lifetime.

Since it's a relatively large application, and it wasn't happening a week or so ago, likely I'm just overriding some virtual event func and forgetting to propagate it, but I've double-checked some of the likelier culprits (like the main window) to make sure they are forwarding the events to its base class.

Not only are they not getting hover events, but they aren't receiving paint events - even when calling repaint()!
Based on the behavior, it seems like there is an invisible pop-up window that has focus, until the window is resized and regains focus. Clicks "outside" of the popup are received by the application, but mouse movement is stolen by the popup, and the widgets in the background don't get repainted because of the popup (just using their cached appearances).

I've printed out the objectnames of all these, but I'm not seeing anything odd.

//These two are the same: The main window
QWidget *activeWindow = qApp->activeWindow();
QWindow *focusWindow = qApp->focusWindow();

//Basically the most recent interactive widget I clicked on.
QWidget *focusWidget = qApp->focusWidget();

//These four are null.
QWidget *mouseGrabber = QWidget::mouseGrabber();
QWidget *keyboardGrabber = QWidget::keyboardGrabber();
QWidget *activePopup = qApp->activePopupWidget();
QWidget *activeModal = qApp->activeModalWidget();

So to recap: Buttons and other widgets are receiving clicks, but not mouse-movement events (even widgets that have mouse-tracking enabled). They are drawing once, but not repainting themselves when they are supposed to.

Tomorrow I'll be checking my diffs over the past few repository commits to try to figure out what changes I've made, but if anyone has any thoughts or tips for debugging this, I'd really really appreciate it.

I'm using Qt5.4.

wysota
10th January 2015, 12:17
Recently, my Qt application has stopped repainting widgets when they are hovered over

Did you enable hover events for them?

ComServant
11th January 2015, 00:15
I'm talking about every widget, including QPushButtons / QToolButtons, custom widgets (with mouseTracking enabled) receiving mouse presses but not repainting, even after explicit calls to repaint() in the mousePressEvent() override. When they finally do repaint (after the first window resize, and then they behave normally after that) I can see that the previous mouse presses were received but the widgets appearances weren't updated. Breakpoints also tell me the same thing - their paintEvents weren't getting called, but their mousePressEvents were. Their mouse hovers only seem to take effect when the mouse was pressed ontop of them and is still being held down (as if mouseTracking is disabled), but their rpaintEvents still aren't being called. It really seems there's an invisible pop-up that has focus.

It's most likely not a borked Qt install, because it was working fine a week or two ago (I didn't notice exactly when it started), so it's most likely something in my large code project. I was hoping someone might've encountered a similar problem before and could provide some debugging tips.

For debugging Win32 programs, there are applications you can use to query the state of the application you are debugging. Has anyone written anything like that for Qt?

Even though these four a null:

QWidget *mouseGrabber = QWidget::mouseGrabber();
QWidget *keyboardGrabber = QWidget::keyboardGrabber();
QWidget *activePopup = qApp->activePopupWidget();
QWidget *activeModal = qApp->activeModalWidget();

...I'm only printing them out in response to a button being pressed (a button that doesn't redraw itself, but still reacts to the press just in a non-animated way), so it probably temporarily hides the active popup or whatever, giving me (possibly) misleading results. I'll try outputting it using a timer, to see if something is active.

wysota
11th January 2015, 00:59
It would be easier if you provided a minimal compilable example reproducing the problem.

ComServant
11th January 2015, 18:56
Knew someone was going to say that. =)
But if I could produce an example reproducing the problem, then I can fix it. My question is, how can I, in a complex project, isolate where the problem is? This step must be done before a minimal compilable can be created. Minimal compilable programs are usually for demonstrating flaws in Qt, where here I'm almost positive the flaw is in my own code.

This is partly a, "Does anyone recognize this particular problem, and can you point me at possible causes to save me dozens of hours of work?", and it's partly a question of, how do you debug large event-driven and signal-and-slot driven applications?

Normally, with single-threaded (hobbyist) videogame development, program execution is much more linear and easier for me to isolate the general area where the problem is. With widget-based applications, program flow is significantly more complex - jumping all over the place - and I don't have as much experience debugging that.

I was busy yesterday with other tasks, but today I'm starting to compare the diffs to find when (and hopefully where!) I introduced the problem. But if anyone has any advice of what to look for, or possible guesses at the cause, I'd greatly appreciate it.

wysota
11th January 2015, 23:43
But if I could produce an example reproducing the problem, then I can fix it.
Therefore you expect us to fix it just by knowing that "it doesn't work"?


My question is, how can I, in a complex project, isolate where the problem is?
There are two ways -- either start removing code from your non-working program until it starts working or start adding code to an empty program until it stops working.


Minimal compilable programs are usually for demonstrating flaws in Qt, where here I'm almost positive the flaw is in my own code.
No, minimal compilable examples are usually for finding flaws in your code by isolating code relevant to the issue. "Once you eliminate the impossible, whatever remains.. bla bla.. must be the truth".


Normally, with single-threaded (hobbyist) videogame development, program execution is much more linear and easier for me to isolate the general area where the problem is. With widget-based applications, program flow is significantly more complex - jumping all over the place - and I don't have as much experience debugging that.
Unless you introduced some threads yourself your program is still single-threaded. And since UI can operate only in the main thread, you can remove all your multi-threaded code and the problem will remain.

ComServant
12th January 2015, 00:44
I stand corrected; it is something within Qt (possibly). If I don't have Qt::FramelessWindowHint set on my main window, there isn't a problem. I can't reproduce it in a minimlistic program though - Qt::FramelessWindowHint alone isn't triggering it.

To hack around the problem, during startup I call this after an explicit call to QMainWindow's show() function:

this->setGeometry(this->geometry().adjusted(-1,-1,1,1));

This "fixes" my problem (hides it, more like). I'm not sure what the origin of the problem is. I don't know what part of my code, in combination with Qt::FramelessWindowHint, is triggering the behavior.

wysota
12th January 2015, 06:00
I really suggest you post some code. Without that there isn't much we can do. Right now I can only suggest installing an event filter on the application object and check whether paint events and other events you need are generated at all.