开发环境: Qt5.12.3 + MSVC2017
问题背景
视频监控类软件或是视频播放类软件都有一个全屏播放的功能,可以全屏播放视频画面。主窗口可以分别用以下两个接口实现。
void QWindow::showFullScreen()
void QWidget::showFullScreen()
如果用户电脑接了第二块屏幕作为扩展屏,默认情况下,无论软件在哪一个屏幕上,子窗口全屏都只会显示在第一块屏幕上显示,即主窗口和子窗口不在同一个屏幕上显示。
解决方案
简单粗暴,先直接上代码。
class MainWidget : public QWidget
{
Q_OBJECT
public:
explicit MainWidget(QWidget *parent = nullptr);
public slots:
void slotFullScreen();
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
QWidget *subWidget = nullptr;
Qt::WindowState screenState = Qt::WindowNoState;
}
MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
subWidget = new QWidget(this);
subWidget->installEventFilter(this);
}
bool MainWidget::eventFilter(QObject *watched, QEvent *event)
{
/* ESC退出全屏 */
if (watched == subWidget && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = dynamic_cast<QKeyEvent*>(event);
if (Qt::Key_Escape == keyEvent->key() && Qt::WindowFullScreen == screenState)
{
subWidget->setWindowFlags(Qt::Widget);
subWidget->show();
screenState = Qt::WindowNoState;
return true;
}
}
return QObject::eventFilter(watched, event);
}
void MainWidget::slotFullScreen()
{
/* 获取当前子控件的绝对坐标,确定当前窗口所在的屏幕 */
QPoint curPoint = subWidget->mapToGlobal(QPoint(0,0));
QScreen *curScreen = QGuiApplication::screenAt(curPoint);
subWidget->setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
subWidget->setFocus();
/* 先更新子控件的屏幕坐标,然后设置子控件全屏显示 */
subWidget->setGeometry(curScreen->availableGeometry());
subWidget->resize(curScreen->geometry().size());
subWidget->show();
screenState = Qt::WindowFullScreen;
}
关键函数是下面这两个,设置子控件所在的屏幕坐标,然后设置为子窗口的尺寸为屏幕尺寸。这样设置后,子窗口就会根据主窗口所在的屏幕进行全屏。
subWidget->setGeometry(curScreen->availableGeometry());
subWidget->resize(curScreen->geometry().size());
上述设置完成后,子窗口并不会显示,需要我们手动显示子窗口。
subWidget->show();
原因如下:
windowFlags : Qt::WindowFlags
Window flags are a combination of a type (e.g. Qt::Dialog) and zero or more hints to the window system (e.g. Qt::FramelessWindowHint).
If the widget had type Qt::Widget or Qt::SubWindow and becomes a window (Qt::Window, Qt::Dialog, etc.), it is put at position (0, 0) on the desktop. If the widget is a window and becomes a Qt::Widget or Qt::SubWindow, it is put at position (0, 0) relative to its parent widget.
Note: This function calls setParent() when changing the flags for a window, causing the widget to be hidden. You must call show() to make the widget visible again…
所以在slotFullScreen()和eventFilter() 两个函数中设置子窗口的标志后,都需要重新调用show()来显示子窗口。