Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When the main window remains at the top, the child Windows are occluded - MacOS

Tags:

c++

qt

qt5

Usually, the tools window is always at the top of the main window, even if it loses focus. However.

On MacOS, when the main window sets the window flag Qt::WindowStaysOnTopHint, the Tool window is below it.

On a Windows system, the Tool window is at the top of the main window as expected.

Is there a way to keep the main window at the top while the Tool window is above it?

enter image description here

My current Qt versions are 5.9.6 and 5.12.1. The MacOS version is 10.13.4.

This is my test code

#include <QtGui>
#include <QtWidgets>

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);

    QDialog* mw = new QDialog(0, Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
    mw->setWindowTitle(QLatin1String("Main"));
    mw->resize(400, 300);
    mw->move(100, 100);

    QWidget* d = new QWidget(mw, Qt::Tool);
    d->setWindowTitle(QLatin1String("Tool"));
    d->resize(200, 100);
    d->show();
    mw->exec();
    return app.exec();
}
like image 378
Degang Guo Avatar asked Jan 31 '19 03:01

Degang Guo


2 Answers

Sorry, I have no MacOS system, however, I could reproduce and fix your problem under Ubuntu. Hopefully, it will work the same under MacOS.

First, bnaecker is right, you should call show() rather than exec() for your main window. Would be nice if it was a QMainWidget rather than a QDialog, but that's not the problem here.

According to the doc:

Qt::Tool: Indicates that the widget is a tool window. A tool window is often a small window with a smaller than usual title bar and decoration, typically used for collections of tool buttons. It there is a parent, the tool window will always be kept on top of it. If there isn't a parent, you may consider using Qt::WindowStaysOnTopHint as well. If the window system supports it, a tool window can be decorated with a somewhat lighter frame. It can also be combined with Qt::FramelessWindowHint.

Your tool widget, has a parent, so that should work. However, by testing, I can see that the tool's window should be shown when the tool itself is shown for it to remain on top as expected...that's strange, but that's what I observe.

Also, I noticed that Qt::X11BypassWindowManagerHint messes things up...

Finally, by combining those observations + bnaecker reply, the code is:

#include <QtGui>
#include <QApplication>

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);

    // don't set Qt::X11BypassWindowManagerHint if you want the tool to stay on top!
    QDialog* mw = new QDialog(0, Qt::WindowStaysOnTopHint);// | Qt::X11BypassWindowManagerHint);
    mw->setWindowTitle(QLatin1String("Main"));
    mw->resize(400, 300);
    mw->move(100, 100);

    // show main window before tool is shown
    mw->show();

    QWidget* d = new QWidget(mw, Qt::Tool);
    d->setWindowTitle(QLatin1String("Tool"));
    d->resize(200, 100);
    d->show();

    return app.exec();
}

Now, "Tool" window is on top of "Main" dialog and there's no way for it to be hidden by its parent.

Note that this work regardless if you specify or not Qt::WindowStaysOnTopHint flag for the "Main" window. This flag has no effect on the fact that "Tool" remains on top of "Main". This makes "Main" (and so "Tool") be on top of any other application's window.

like image 88
jpo38 Avatar answered Nov 18 '22 13:11

jpo38


The problem is that you're calling QDialog::exec, rather than directly about the window hints. The exec method for a dialog shows it as a modal dialog, which means interaction with any other window in the application is not allowed until the user closes the dialog. Changing mw->exec() into mw->show() will demonstrate that the tool window can indeed be brought on top of the main window, regardless of the window hint.

You might consider using a main window that is not a QDialog (which is an uncommon situation). Dialogs are intended to block the user from continuing with the normal use of the application until answering a question or acknowledging something (such as an error). They are not usually thought of as the main window through which a user interacts with an application. Using another subclass of QWidget, such as QMainWindow or even just a plain QWidget with the Qt::Window flag set, might be more appropriate.

like image 43
bnaecker Avatar answered Nov 18 '22 13:11

bnaecker