Switching to `QWidget::activateWindow()` from the deprecated `QApplication::setActiveWindow` yields null widget for `QApplication::activeWindow`
-
When switching away from the deprecated API: QApplication::setActiveWindow to the recommended QWidget::activateWindow, the widget/window never gets set as the
active window
. QApplication::activeWindow returns anullptr
.Is there an alternate API for fetching the active widget as set by QWidget::activateWindow?
Here's a small representative example:
#include <QApplication> #include <QDebug> #include <QMainWindow> int main(int argc, char* argv[]) { QApplication app(argc, argv); Q_ASSERT(QApplication::activeWindow() == nullptr); QMainWindow w; w.show(); w.raise(); w.activateWindow(); // QApplication::setActiveWindow(&w); Deprecated API qDebug() << QApplication::activeWindow() << w.isActiveWindow(); Q_ASSERT(QApplication::activeWindow() != nullptr); if (!QApplication::activeWindow()) { // in case if this is not a debug build qCritical() << "Couldn't activate window."; } return app.exec(); }
The output is
$ ./QtActiveWindow QWidget(0x0) false ASSERT: "QApplication::activeWindow() != nullptr" in file /home/sankhesh/Projects/TestProjects/QtActiveWindow/QtActiveWindow/QtActiveWindow.cxx, line 16 [1] 256514 IOT instruction (core dumped) ./QtActiveWindow
-
Hi and welcome to devnet,
You are calling that function way too early.
Check it's documentation again. The key word is: visible. Calling show on a widget does not make it instantly visible. It schedules its appearance at the earliest possible time when the event loop is running.
-
Thank you for the quick response, @SGaist. Your answer helped me understand the issue.
It appears that
QApplication::setActiveWindow
updates the internal cachedactive_window
pointer to the specified widget here: https://codebrowser.dev/qt6/qtbase/src/widgets/kernel/qapplication.cpp.html#1848. This enables subsequent code to callQApplication::activeWindow
immediately afterward, successfully.However,
QWidget::activateWindow
schedules this action on the platform window (https://codebrowser.dev/qt6/qtbase/src/gui/kernel/qwindow.cpp.html#1292), which means that the activeWindow will not be available until the underlying windowing event system has processed that request.So, in my case, I could do something like:
w.show(); QTimer::singleShot(100, [&w](){w.activateWindow(); qDebug() << QApplication::activeWindow();});
which gives the native windowing system a chance to process the event. And it works indeed.
-
@Sankhesh-Jhaveri
I have not tested but you may find the activation first takes place (rather than waiting on a timer), andactiveWindow()
becomes valid, if you subclass your widget and override theshowEvent()
-
Thanks @JonB. Is there a signal I can connect to, for when the window is actually activated?
FWIW, this issue is for the ParaView client where the window is already visible but not the active one. The
showEvent
override wouldn't help there. -
@Sankhesh-Jhaveri
Heave a read through https://stackoverflow.com/questions/16721557/how-to-detect-if-a-window-has-been-activated from 11 years ago :) Does anything there likeQEvent::WindowActivate
help your situation? -
The
QWindow::activeChanged
signal allows me to call the delegate function when the window is actually activated. -