How to avoid bringing QMainWindow to the front when clicking on independent QWidget on MacOS
-
Hello all,
I am building an Qt app on MacOS. The app is composed by QMainWindow and independent QWidget.
I want the widget to be always on top so I have added these window flags:
Qt::X11BypassWindowManagerHint;
Qt::FramelessWindowHint;
Qt::WindowStaysOnTopHint;
Qt::CustomizeWindowHint;
Qt::WindowDoesNotAcceptFocus;
And also these attributes
Qt::WA_ShowWithoutActivating
Qt::WA_LayoutUsesWidgetRect
Qt::WA_TranslucentBackground
Qt::WA_OpaquePaintEvent
Qt::WA_PaintUnclipped
On MacOS and only on MacOS I am seeing that when I click on the widget the QMainWindow always comes to the front.
I do not want that to happen. How can I achieve it?
I have tried to intercept mouse click events but that does not seem to work. I have also tried to intercept QWindow activate event but also no success there.
I need help here please. Is that desired behaviour on MacOS? Is it bug on MacOS?
Thanks and regards -
I made it work by removing this flag: Qt::WindowDoesNotAcceptFocus
-
Hi and welcome to devnet,
Which version of Qt ?
On which version of macOS ?
Can you provide a minimal compilable example that shows that behaviour ? -
MacoS version is 10.15.7 Catalina
Regarding Qt versions I have tried using Qt5.9.7 and Qt 5.15. Both have same behaviour
Here is minimal example:
mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); protected: virtual bool eventFilter(QObject *o, QEvent *e) override; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include <QDebug> #include <QEvent> MainWindow::MainWindow() { installEventFilter(this); } bool MainWindow::eventFilter(QObject *o, QEvent *e) { //qCritical() << "MainWindow::eventFilter --> " << e->type(); if (e->type() == QEvent::WindowActivate) { qCritical() << "QEvent::WindowActivate"; //e->setAccepted(false); return true; } return QWidget::eventFilter(o, e); }
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> class Widget : public QWidget { public: explicit Widget(QWidget *parent = Q_NULLPTR); protected: virtual bool eventFilter(QObject *o, QEvent *e) override; virtual void mousePressEvent(QMouseEvent *event) override; }; #endif // WIDGET_H
widget.cpp
#include "Widget.h" #include <QEvent> #include <QMouseEvent> #include <QDebug> namespace { Qt::WindowFlags defaultWindowFlags() { Qt::WindowFlags f = 0; f |= Qt::X11BypassWindowManagerHint; f |= Qt::FramelessWindowHint; f |= Qt::WindowStaysOnTopHint; f |= Qt::CustomizeWindowHint; f |= Qt::WindowDoesNotAcceptFocus; #if defined(Q_OS_WIN) f |= Qt::Tool; #else f |= Qt::Window; #endif // defined(Q_OS_WIN) return f; } } Widget::Widget(QWidget *parent) : QWidget(parent, defaultWindowFlags()) { setFixedSize(100,100); setStyleSheet("background-color:blue;"); move(56,89); setVisible(true); //installEventFilter(this); setAttribute(Qt::WA_TransparentForMouseEvents); } bool Widget::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::WindowActivate) { qCritical() << "Widget QEvent::WindowActivate"; return true; } if (e->type() == QEvent::MouseButtonPress) { qCritical() << "Widget QEvent::MouseButtonPress"; //show(); //activateWindow(); //raise(); // false means it should be send to target also. as in , we dont remove it. // if you return true , you will take the event and widget never sees it so be carefull with that. return true; } return QWidget::eventFilter(o, e); } void Widget::mousePressEvent(QMouseEvent *event) { //event->accept(); qCritical() << "mousePressEvent"; }
And finally main.cpp
#include <QApplication> #include "mainwindow.h" #include "Widget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); //MainWindow w; //w.show(); RegularWindow r; r.show(); Widget mywidget; return app.exec(); }
Just to add more info. I have seen that if I instantiate two main windows only it works as expected. Clicking on one of those mainwindows does not make the other mainwindow to get activated
Thanks -
Hi,
When you do nothing in methods of a subclass you should at least call the base class implementation.
And when you call the base class implementation, you should ensure that you have right base class. In your code you call QWidget::eventFilter rather than QMainWindow.
-
Hello @SGaist,
Yes you're right, but I just created quick and basic example. I don't think these errors affect the goal of my question.
Do you know how to get the behaviour I asked ?
Thanks! -
That's the thing: they might.
The goal of the minimum example is to remove all possible outside influences and concentrate on the issue at hand so having some methods re-implemented in a "quick and dirty" manner might in fact add or even be the issue.
-
Resubmitting example fixed:
main.cpp#include <QApplication> #include "mainwindow.h" #include "Widget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow w; w.show(); Widget mywidget; return app.exec(); }
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> class Widget : public QWidget { public: explicit Widget(QWidget *parent = Q_NULLPTR); }; #endif // WIDGET_H
widget.cpp
#include "Widget.h" #include <QEvent> #include <QMouseEvent> #include <QDebug> namespace { Qt::WindowFlags defaultWindowFlags() { Qt::WindowFlags f = 0; f |= Qt::X11BypassWindowManagerHint; f |= Qt::FramelessWindowHint; f |= Qt::WindowStaysOnTopHint; f |= Qt::CustomizeWindowHint; f |= Qt::WindowDoesNotAcceptFocus; #if defined(Q_OS_WIN) f |= Qt::Tool; #else f |= Qt::Window; #endif // defined(Q_OS_WIN) return f; } } Widget::Widget(QWidget *parent) : QWidget(parent, defaultWindowFlags()) { setFixedSize(100,100); setStyleSheet("background-color:blue;"); move(56,89); setVisible(true); setAttribute(Qt::WA_TransparentForMouseEvents); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); protected: virtual bool eventFilter(QObject *o, QEvent *e) override; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include <QDebug> #include <QEvent> MainWindow::MainWindow() : QMainWindow() { installEventFilter(this); } bool MainWindow::eventFilter(QObject *o, QEvent *e) { //qCritical() << "MainWindow::eventFilter --> " << e->type(); if (e->type() == QEvent::WindowActivate) { qCritical() << "QEvent::WindowActivate"; //e->setAccepted(false); return true; } return QMainWindow::eventFilter(o, e); }
So, basically I have reduced example to be really simple. Still the behaviour is not correct. Could you help me on this?
Thanks in advance -
I made it work by removing this flag: Qt::WindowDoesNotAcceptFocus