views:

500

answers:

2
void MainWindow::on_actionAlways_on_Top_triggered(bool checked)
{
    Qt::WindowFlags flags = this->windowFlags();
    if (checked)
    {
        this->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
        this->show();
    }
    else
    {
        this->setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
        this->show();
    }
}

The above solution works but because setWindowFlags hides the window, it needs to be re-shown and of course that doesn't look very elegant. So how do I toggle "always on top" for a QMainWindow without that "flashing" side effect?

+4  A: 

Nokia says no:

It is not possible to make changes to the window flags once the window has been created without causing flicker. Flicker is unavoidable since the window needs to be recreated.

But sometimes if you're stuck with a flashing effect that's kind of ugly like this, you can intentionally drag it out to make it seem like something "cool" just happened.

Maybe pop up a little progress bar that's not in the window, say "Adjusting Window Properties!"...fade the window out of existence and then back in, and close the progress bar popup.

Hostile Fork
+1: For the nice "workaround" idea ;)
ereOn
For an "always on top" feature, this must be possible. Plenty of applications do it without flicker; perhaps I'll just need to use some native Windows functions?
Jake Petroules
If you want to go beneath or sidestep the Qt implementation (of destroying the window and making it again) then possibly. But at least some of these things are properties of the "Window Class" IIRC and not the HWND ; and you may not be able to change a window's class after it has been created. Either way, I think the value of coming up with an answer you can accept without breaking the Qt abstraction layer is better than getting mired in Win32 hacks. That's the joy of Qt in the first place...
Hostile Fork
@ereOn: Yeah, I have some stuff that puts up a progress bar and (regardless of task completion) won't take it down unless a minimum flicker period has passed since the bar was put up. So the computer is "slowing you down" in a sense but the experience is better because it didn't make an alarming blip that went right away. Lots of progress bar psychology out there. :) http://www.scribd.com/doc/2226848/Rethinking-The-Progress-Bar
Hostile Fork
@HostileFork I'm actually going to accept your answer rather than my own, since I asked for a *Qt* solution, to which you gave the correct answer.
Jake Petroules
Thanks Jake! Well, both the answers are still here, so people can make their own choice. Good luck with submitting the patch! ;)
Hostile Fork
+1  A: 

Well, for a solution I figured I'd look in the Mono sources, since I know the .NET Form class (System.Windows.Forms) has a TopMost property.

The solution I found for my Qt program was:

void MainWindow::on_actionAlways_on_Top_triggered(bool checked)
{
#ifdef Q_OS_WIN
    // #include <windows.h>
    if (checked)
    {
        SetWindowPos(this->winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    }
    else
    {
        SetWindowPos(this->winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    }
#else
    Qt::WindowFlags flags = this->windowFlags();
    if (checked)
    {
        this->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
        this->show();
    }
    else
    {
        this->setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
        this->show();
    }
#endif
}
Jake Petroules
If you really think it's worth it (!) But I would suggest at least breaking it out as a separate method, e.g. *void setWindowStaysOnTopHint(bool windowStaysOnTopHint)*. Then your ifdef wouldn't be spanning your button and it would more accurately reflect the routine that you "wanted", which Nokia may add someday if you submitted a patch for all platforms. In that routine I'd also make sure to leave a link behind to this SO question so someone wondering why it's there will be able to find out...
Hostile Fork
I already did that, there's a few methods in a separate class to handle it. I just posted it this way on here for convenience if anyone else ever looked at this question.Interesting idea on submitting it to Nokia, though, I'll definitely consider that once I implement working Carbon and X11 solutions.
Jake Petroules