Stworzenie widgeta pełnoekranowego w Qt4 niby jest proste, ale… okazuje się, że po drodze czyha na nas kilka pułapek. Postaram się was przez nie przeprowadzić…
W moim przypadku, mam aplikację, która wyświetla strumień video (akurat ze specjalnej karty, ale to kompletnie nieważne – może Ty chcesz oglądać np. film z pliku). Idąc za niepisanym standardem, postanowiłem opcję przejścia do fullscreen położyć na klawiszu <F11>.
QAction *theFullscreenAction = new QAction(this); theFullscreenAction->setShortcut(QKeySequence(Qt::Key_F11)); theFullscreenAction->setCheckable(true); connect(theFullscreenAction, SIGNAL(toggled(bool)), this, SLOT(toggleFullscreen(bool))); addAction(theFullscreenAction);
Aby przełączyć widget, trzeba zapamiętać kilka jego właściwości, aby było do czego wracać a następnie go przełączyć. Przy powrocie, oczywiście należy odtworzyć wszystkie właściwości.
QWidget *videoFrameParent; QLayout *videoFrameParentLayout; Qt::WindowFlags videoFrameFlags; QSize videoFrameSize;
void myApp::toggleFullscreen(bool bFullscreen) { if (bFullscreen) { videoFrameParent = ui.videoFrame->parentWidget(); videoFrameParentLayout = ui.videoFrame->parentWidget()->layout(); videoFrameFlags = ui.videoFrame->windowFlags(); videoFrameSize = ui.videoFrame->size(); // untie it... ui.videoFrame->setParent(NULL); ui.videoFrame->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); ui.videoFrame->showMaximized(); } else { // bring it back! ui.videoFrame->resize(videoFrameSize); ui.videoFrame->overrideWindowFlags(videoFrameFlags); ui.videoFrame->setParent(videoFrameParent); videoFrameParentLayout>addWidget(ui.videoFrame); ui.videoFrame->show(); } }
Odpalamy aplikację i testujemy… pierwsze, co się rzuca, to nie działa klawisz powrotu. Chwila zabawy i – działa, ale trzeba Alt-Tabem przejść do osieroconego okna aplikacji głównej. Rozwiązanie jest dość proste: wystarczy naszą akcję dodać również do naszego widgetu. Dlaczego? Dlatego, że po jego wydziedziczeniu (setParent(NULL);) aplikacja główna przestaje otrzymywać zdarzenia klawiatury, gdy nasz widget ma fokus.
ui.videoFrame->addAction(theFullscreenAction);
Kolejny problem objawia się w momencie, gdy mamy konfigurację wielomonitorową i wywołamy akcję w momencie, gdy aplikacja będzie na monitorze innym, niż główny. Okaże się, że nasz fullscreen włączy się na ekranie głównym, pozostawiając osieroconą i ogołoconą aplikację główną tam, gdzie była.
Tu niestety musimy kilka linijek kodu spędzić na rozwiązanie tego problemu… sprawdzimy najpierw, gdzie nasza aplikacja się znajduje, a następnie (po wydziedziczeniu!) przesuniemy okno tam ręcznie, po czym dopiero uruchomimy showMaximized().
// untie it... ui.videoFrame->setParent(NULL); ui.videoFrame->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); // hack for showing it on a screen, where the app is (in a multimonitor setup) QDesktopWidget *dw = QApplication::desktop(); QRect drect = dw->screenGeometry(dw->screenNumber(QCursor::pos())); int desk_x = drect.width(); int desk_y = drect.height(); int x = ui.videoFrame->width(); int y = ui.videoFrame->height(); ui.videoFrame->move(desk_x / 2 - x / 2 + drect.left(), desk_y / 2 - y / 2 + drect.top()); // yeah! ui.videoFrame->showMaximized();
Kolejny test i… działa! 🙂 Poniżej kod w komplecie:
QWidget *videoFrameParent; QLayout *videoFrameParentLayout; Qt::WindowFlags videoFrameFlags; QSize videoFrameSize;
QAction *theFullscreenAction = new QAction(this); theFullscreenAction->setShortcut(QKeySequence(Qt::Key_F11)); theFullscreenAction->setCheckable(true); connect(theFullscreenAction, SIGNAL(toggled(bool)), this, SLOT(toggleFullscreen(bool))); addAction(theFullscreenAction); ui.videoFrame->addAction(theFullscreenAction);
void myApp::toggleFullscreen(bool bFullscreen) { if (bFullscreen) { videoFrameParent = ui.videoFrame->parentWidget(); videoFrameParentLayout = ui.videoFrame->parentWidget()->layout(); videoFrameFlags = ui.videoFrame->windowFlags(); videoFrameSize = ui.videoFrame->size(); // untie it... ui.videoFrame->setParent(NULL); ui.videoFrame->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); // hack for showing it on a screen, where the app is (in a multimonitor setup) QDesktopWidget *dw = QApplication::desktop(); QRect drect = dw->screenGeometry(dw->screenNumber(QCursor::pos())); int desk_x = drect.width(); int desk_y = drect.height(); int x = ui.videoFrame->width(); int y = ui.videoFrame->height(); ui.videoFrame->move(desk_x / 2 - x / 2 + drect.left(), desk_y / 2 - y / 2 + drect.top()); // yeah! ui.videoFrame->showMaximized(); } else { // bring it back! ui.videoFrame->resize(videoFrameSize); ui.videoFrame->overrideWindowFlags(videoFrameFlags); ui.videoFrame->setParent(videoFrameParent); videoFrameParentLayout->addWidget(ui.videoFrame); ui.videoFrame->show(); } }
Miłego oglądania! 😉