c++ - En Qt 5, ¿cuál es la forma correcta de mostrar ventanas QWidget de pantalla completa en varios monitores?
qt5 fullscreen (1)
Tengo un programa de Windows y Mac que cambia al modo de pantalla completa en varios monitores. En Qt 4, parece (no puedo encontrar documentación explícita sobre cómo hacer esto) que la forma "correcta" de hacerlo es mediante la creación de N QMainWindow
para los monitores N en la máquina, llamando a QWidget::move()
a las coordenadas x, y superiores izquierda del monitor N, y luego llamando a QWidget::setWindowState(Qt::WindowFullScreen)
. No sé si esto es lo que hay que hacer; de nuevo, no puedo encontrar ninguna documentación o ejemplo en cualquier lugar que haga esto en Qt.
Esto parece estar ''roto'' (si alguna vez fue lo correcto en primer lugar) en Qt 5.4.1, especialmente en Windows 7. Todavía estoy tratando de aislar el problema, pero parece que la QMainWindow
s están abandonando el modo de pantalla completa.
Solo para que quede claro, ¿cuál es la forma correcta de hacerlo? Encontré this publicación en el foro que parece sugerir que debería configurar QScreen
en los objetos QWindow
subyacentes que están en poder de QMainWindow
, pero esto no parece funcionar en mis pruebas. Aquí hay un programa de ejemplo que escribí:
app.h:
#include <vector>
#include <QObject>
class QMainWindow;
class app : public QObject
{
Q_OBJECT
public:
int run(int argc, char** argv);
public slots:
void add_window();
void remove_window();
void windows_go_to_screens();
void windows_go_to_screens_old();
void windows_go_to_primary_screen();
void windows_fullscreen();
void windows_nonfullscreen();
private:
QMainWindow * create_window(const char * id);
void init_menus( QMainWindow * w );
std::vector<QMainWindow *> m_windows;
};
app.cpp:
#include <assert.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <QObject>
#include <QMainWindow>
#include <QApplication>
#include <QMenubar>
#include <QAction>
#include <QScreen>
#include <QWindow>
#include <QLayout>
#include <QLabel>
#include <QStyle>
#include "app.h"
using namespace std;
int app::run(int argc, char** argv)
{
QApplication a(argc, argv);
QMainWindow * w = create_window("0");
m_windows.push_back(w);
w->show();
return a.exec();
}
void app::add_window()
{
static const char * nums[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
m_windows.push_back(create_window(nums[m_windows.size()]));
m_windows.back()->show();
}
void app::remove_window()
{
if (m_windows.size() > 1)
{
QMainWindow * w = m_windows.back();
m_windows.pop_back();
w->close();
w->deleteLater();
}
}
void app::windows_go_to_screens()
{
QList<QScreen*> screens = qApp->screens();
for (unsigned i = 0; i < std::min((unsigned)m_windows.size(), (unsigned)screens.size()); ++i)
{
QMainWindow * mw = m_windows[i];
QScreen * screen = screens[i];
QWindow * wh = mw->windowHandle();
wh->setScreen(screen);
}
}
void app::windows_go_to_screens_old()
{
QList<QScreen*> screens = qApp->screens();
for (unsigned i = 0; i < std::min((unsigned)m_windows.size(), (unsigned)screens.size()); ++i)
{
QMainWindow * mw = m_windows[i];
QScreen * screen = screens[i];
mw->move(screen->geometry().left(), screen->geometry().top());
}
}
void app::windows_go_to_primary_screen()
{
QList<QScreen*> screens = qApp->screens();
for (unsigned i = 0; i < std::min((unsigned)m_windows.size(), (unsigned)screens.size()); ++i)
{
QMainWindow * mw = m_windows[i];
QScreen * screen = screens[0];
QWindow * wh = mw->windowHandle();
wh->setScreen(screen);
}
}
void app::windows_fullscreen()
{
for (unsigned i = 0; i < m_windows.size(); ++i)
{
QMainWindow * mw = m_windows[i];
mw->showFullScreen();
}
}
void app::windows_nonfullscreen()
{
for (unsigned i = 0; i < m_windows.size(); ++i)
{
QMainWindow * mw = m_windows[i];
mw->showNormal();
}
}
QMainWindow * app::create_window(const char * id)
{
QMainWindow * w = new QMainWindow(NULL);
init_menus(w);
QWidget * cw = new QWidget(w);
w->setCentralWidget(cw);
QHBoxLayout * l = new QHBoxLayout(cw);
cw->setLayout(l);
QLabel * lab = new QLabel(id, cw);
QPalette pal(lab->palette());
pal.setColor(QPalette::Background, Qt::red);
lab->setAutoFillBackground(true);
lab->setPalette(pal);
lab->setScaledContents(true);
lab->setAlignment(Qt::AlignCenter);
l->addWidget( lab );
return w;
}
void app::init_menus( QMainWindow * w )
{
QMenuBar * menubar = w->menuBar();
QMenu * view_menu = new QMenu(tr("View"), w);
view_menu->addAction("Add Window", this, SLOT(add_window()));
view_menu->addAction("Remove Window", this, SLOT(remove_window()));
view_menu->addAction("Windows Go To Screens", this, SLOT(windows_go_to_screens()));
view_menu->addAction("Windows Go To Screens (old method)", this, SLOT(windows_go_to_screens_old()));
view_menu->addAction("Windows Go To Primary Screen", this, SLOT(windows_go_to_primary_screen()));
view_menu->addAction("Windows Fullscreen", this, SLOT(windows_fullscreen()));
view_menu->addAction("Windows Non-Fullscreen", this, SLOT(windows_nonfullscreen()));
menubar->addMenu(view_menu);
}
main.cpp:
#include "app.h"
int main(int argc, char** argv)
{
app a;
return a.run(argc, argv);
}
Cuando ejecuto este programa en OS X, la función "Ir a pantallas de Windows" no hace nada, ninguna de las ventanas se mueve. Tampoco la "Pantalla principal de Windows ir" (mal nombre: ¿debería ser una pantalla 0?). ¿Es interesante crear más de N ventanas en una ventana N? En este caso, si se llama "Pantalla completa de Windows" varias veces, ¿¿QWainWindows cambiará a modo de pantalla completa de una en una?
Aún más interesante es lo que sucede en una máquina OS X con múltiples monitores cuando haces esto: "Agregar ventana" hasta que tengas tantas ventanas como pantallas. "Windows Go To Screens (método antiguo)" enviará cada ventana a la parte superior izquierda de cada monitor. "Pantalla completa de Windows" hará que todas las ventanas se muestren en pantalla completa en todos los monitores. "Eliminar ventana" hasta que solo te quede 1 ventana. Luego "Windows Non-FullScreen", y obtendrás una interesante sorpresa. Entra en el Control de la Misión para ver qué está pasando.
¿Alguien puede decirme cuál es la forma CORRECTA de hacer esto? He examinado los ejemplos de Qt5: hay una aplicación del reproductor que parece estar completamente dañada (puede reproducir un video en modo de pantalla completa una vez, y luego las jugadas subsiguientes están en una ventana de escritorio separada), el juego secundario solo se maximiza para una sola pantalla, y ninguno de los otros ejemplos parece utilizar el modo de pantalla completa, y ciertamente no en varios monitores.
Una forma de hacerlo en Qt5 es usar QWindow::setScreen
para configurar la pantalla en la que se debe mostrar la ventana. QWidget
tiene un windowHandle()
que devuelve el puntero a la QWindow
. Para que pueda obtener ese puntero para cada ventana y configurar una pantalla diferente.
Aquí se muestra cómo mostrar su widget en la última pantalla en modo de pantalla completa:
QWidget * widget = new QWidget();
widget->show();
widget->windowHandle()->setScreen(qApp->screens().last());
widget->showFullScreen();
O en la segunda pantalla:
QWidget * widget = new QWidget();
widget->show();
widget->windowHandle()->setScreen(qApp->screens()[1]);
widget->showFullScreen();