【问题标题】:In Qt 5, what's the right way to show multi-monitor full screen QWidget windows?在 Qt 5 中,显示多显示器全屏 QWidget 窗口的正确方法是什么?
【发布时间】:2023-12-12 10:28:01
【问题描述】:

我有一个 Windows 和 Mac 程序,可以在多台显示器上切换到全屏模式。在 Qt 4 中,似乎(我找不到有关如何执行此操作的明确文档)喜欢解决此问题的“正确”方法是为机器上的 N 个监视器创建 N 个 QMainWindow,调用 @987654323 @ 到 N 监视器的左上角 x,y 坐标,然后调用 QWidget::setWindowState(Qt::WindowFullScreen)。我不知道这是否是正确的做法——同样,我在 Qt 中的任何地方都找不到任何文档或示例。

在 Qt 5.4.1 中,尤其是在 Windows 7 上,这似乎被“破坏”了(如果它首先是正确的事情)。我仍在尝试隔离问题,但它似乎QMainWindows 正在退出全屏模式。

我很清楚这一点,正确的方法是什么?我发现this 论坛帖子似乎建议我应该在QMainWindows 持有的底层QWindow 对象上设置QScreen,但这似乎在我的测试中不起作用。这是我编写的示例程序:

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);
}

当我在 OS X 上运行这个程序时,“Windows Go To Screens”功能什么也不做——没有一个窗口移动。 “Windows Go To Primary Screen”也没有(名字不好 - 应该是 0 屏幕?)。在 N 窗口 Mac 上创建多个窗口很有趣 - 在这种情况下,多次调用“Windows 全屏”实际上会一次将 QMainWindows 切换到全屏模式?!

更有趣的是,当您执行以下操作时,在多显示器 OS X 机器上会发生什么:“添加窗口”,直到您拥有与显示器一样多的窗口。 “Windows Go To Screens(旧方法)”会将每个窗口发送到每个监视器的左上角。 “Windows 全屏”将使所有窗口在所有显示器上全屏显示。 “删除窗口”,直到您只剩下 1 个窗口。然后是“Windows Non-FullScreen”,你会得到一个有趣的惊喜。进入任务控制中心看看发生了什么。

谁能告诉我这样做的正确方法是什么?我查看了 Qt5 示例 - 播放器应用程序似乎被彻底破坏(它可以在全屏模式下播放一次视频,然后在单独的桌面窗口中播放),子游戏只能最大化到单个显示器,其他示例似乎都没有使用全屏模式,当然也没有在多个显示器上。

【问题讨论】:

    标签: c++ qt qt5 fullscreen


    【解决方案1】:

    在 Qt5 中这样做的一种方法是使用QWindow::setScreen 来设置应显示窗口的屏幕。 QWidget 有一个 windowHandle(),它返回指向 QWindow 的指针。因此,您可以为每个窗口获取该指针并设置不同的屏幕。

    以下是如何在最后一个屏幕中以全屏模式显示小部件:

    QWidget * widget = new QWidget();
    widget->show();
    widget->windowHandle()->setScreen(qApp->screens().last());
    widget->showFullScreen();
    

    或者在第二个屏幕中:

    QWidget * widget = new QWidget();
    widget->show();
    widget->windowHandle()->setScreen(qApp->screens()[1]);
    widget->showFullScreen();
    

    【讨论】: