引言
常见的子控件方法如下:
setWindowFlags (Qt::Window);
showFullScreen ();
setWindowFlags (Qt::SubWindow);
showNormal ();
由于showFullScreen()只对顶级窗口有效果,对子窗口无效。全屏前需要设置windowsFlags为Qt::Window,退出全屏需要设置为Qt::SubWindow。
以上能够满足windows的常规使用,但在linux和mac下无法满足,对复杂应用也会出现不能适配的情况。
由此打算自己实现一个通用的方法,也避免对不同平台进行过多适配,简化代码。
实现思路
上述方法中,设置windowFlags就是为了让子窗体变成弹窗,借以调用全屏函数。但退出全屏使用showNormal将弹窗还原为子控件,总觉得是瞎猫碰到死耗子,实际showNormal的原意并非如此。
所以按照之前的逻辑,同时为了避免设置windowFlags,可以设置一个专用来展示全屏的弹窗,将需要全屏的控件移动至全屏弹窗布局中,继而实现全屏。
主要逻辑如下:
1.全屏则将“目标控件”加入“全屏弹窗”布局,并通过setGeometry使弹窗占满当前屏幕,移动到顶层显示
2.退出全屏则将“目标控件”恢复布局,隐藏“全屏弹窗”
3.为保证退出全屏后“目标控件”能恢复原样,需要“占位控件”作为恢复原布局的指引,即找到替换位置
4.控件布局的替换通过QLayout::replaceWidget实现
5.上述方法基于“目标控件”原本已经存在布局中,所以应增加容错判断
实现效果如下:
代码
class FullScreenDlg : public QDialog
{
Q_OBJECT
public:
FullScreenDlg(QWidget *parent = nullptr);
~FullScreenDlg();
bool moveFullScreen(QWidget* tmpWidget);
bool moveNormal();
protected:
void keyPressEvent(QKeyEvent *ev) Q_DECL_OVERRIDE;
private:
QWidget* m_placeholderWidget;
QWidget* m_contextWidget;
};
FullScreenDlg::FullScreenDlg(QWidget *parent)
: QDialog(parent, Qt::WindowFlags() | Qt::FramelessWindowHint)
, m_contextWidget(nullptr)
{
m_placeholderWidget = new QWidget(this);
auto mainLayout = new QHBoxLayout(this);
mainLayout->setMargin(0);
mainLayout->addWidget(m_placeholderWidget);
}
FullScreenDlg::~FullScreenDlg()
{
}
bool FullScreenDlg::moveFullScreen(QWidget *tmpWidget)
{
if(tmpWidget->parentWidget() == nullptr || tmpWidget->parentWidget()->layout() == nullptr)
return false;
if(tmpWidget->parentWidget()->layout()->replaceWidget(tmpWidget, m_placeholderWidget)){
m_contextWidget = tmpWidget;
layout()->addWidget(m_contextWidget);
auto tmpGeometry = qApp->desktop()->availableGeometry(QCursor::pos());
setGeometry(tmpGeometry);
show();
raise();
return true;
}
return false;
}
bool FullScreenDlg::moveNormal()
{
if(m_contextWidget == nullptr)
return false;
if(m_placeholderWidget->parentWidget()->layout()->replaceWidget(m_placeholderWidget, m_contextWidget)){
m_contextWidget = nullptr;
layout()->addWidget(m_placeholderWidget);
hide();
return true;
}
return false;
}
void FullScreenDlg::keyPressEvent(QKeyEvent *ev)
{
if(ev->key() == Qt::Key_Escape){
moveNormal();
}
return QDialog::keyPressEvent(ev);
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_dlg = new FullScreenDlg(this);
auto contentWidget = new QLabel(this);
contentWidget->setStyleSheet("QLabel{background-color:yellow;}");
contentWidget->setText("to be continue...");
auto fullBtn = new QPushButton("switch", contentWidget);
fullBtn->setCheckable(true);
connect(fullBtn, &QPushButton::clicked, this, [=]{
if(fullBtn->isChecked()){
m_dlg->moveFullScreen(contentWidget);
}
else{
m_dlg->moveNormal();
}
});
auto mainWidget = new QWidget(this);
setCentralWidget(mainWidget);
auto mainLayout = new QHBoxLayout(mainWidget);
mainLayout->addWidget(contentWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
遮挡任务栏
auto tmpGeometry = qApp->desktop()->screenGeometry(QCursor::pos());
setGeometry(tmpGeometry);