Issue
Normally, moving a QDialog using QDialog::move() positions the dialog outside of taskbars. However, on Ubuntu 20.04 with two monitors it is not the case with frameless Dialogs :
href="https://i.stack.imgur.com/Eu6bW.png" rel="nofollow noreferrer">
This does not happen if the dialog is not frameless :
This behaviour has been observed on Ubuntu 20.04. It also happens only under some configurations :
- Main monitor needs to be on the right side, with task bar on the left (between the two monitors)
- Left monitor needs to have a lower resolution than the right one
- Fractional scaling needs to be disabled
Here is the code for a minimally reproducible example used in the screenshots:
#ifndef BUGDIALOG_H
#define BUGDIALOG_H
#include <QDialog>
namespace Ui {
class BugDialog;
}
class BugDialog : public QDialog
{
Q_OBJECT
public:
explicit BugDialog(QWidget *parent = nullptr);
~BugDialog();
private slots:
void on_moveButton_clicked();
private:
Ui::BugDialog *ui;
};
#endif // BUGDIALOG_H
#include "bugdialog.h"
#include "ui_bugdialog.h"
BugDialog::BugDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::BugDialog)
{
ui->setupUi(this);
ui->xPosEdit->setText("3200");
ui->yPosEdit->setText("1000");
}
BugDialog::~BugDialog()
{
delete ui;
}
void BugDialog::on_moveButton_clicked()
{
int x = ui->xPosEdit->text().toInt();
int y = ui->yPosEdit->text().toInt();
if (x > -1 && x > -1)
move(x, y);
}
The main window is less interesting, it only creates the child window controlling its WindowFlags property :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "bugdialog.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_framelessBox_stateChanged(int arg1);
private:
void hideDialog();
Ui::MainWindow *ui;
BugDialog* dialog;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
dialog = new BugDialog(nullptr);
dialog->hide();
}
MainWindow::~MainWindow()
{
delete ui;
delete dialog;
}
void MainWindow::on_pushButton_clicked()
{
if (dialog->isHidden())
{
dialog->show();
ui->pushButton->setText("Hide dialog");
}
else
{
hideDialog();
}
}
void MainWindow::on_framelessBox_stateChanged(int)
{
auto windowType = ui->framelessBox->isChecked() ? Qt::FramelessWindowHint : Qt::Dialog;
dialog->setWindowFlags(windowType);
hideDialog();
}
void MainWindow::hideDialog()
{
dialog->hide();
ui->pushButton->setText("Show dialog");
}
This looks like a bug in Qt. Does anyone know if it is expected behaviour? Or how to get around this?
Solution
I didn't find a proper solution or satisfying workaround for this issue, but found a partial solution that is half satisfying :
- Before each
move()
on the dialog, set its flag to Qt::Window (no frameless) and hide it. - Override the
moveEvent()
handler, set the window flag to Qt::FramelessWindowHint and show it.
Here are the two changes I made on this example :
void BugDialog::on_moveButton_clicked()
{
int x = ui->xPosEdit->text().toInt();
int y = ui->yPosEdit->text().toInt();
if (x > -1 && x > -1)
{
hide();
setWindowFlags(Qt::Window);
move(x, y);
}
}
void BugDialog::moveEvent(QMoveEvent *)
{
QTimer::singleShot(500, this, [this](){
this->setWindowFlags(Qt::FramelessWindowHint);
this->show();
});
}
I also tried changing the dialog painting. The idea was to set window flags as a "framefull" dialog but paint the dialog as if it had the FramelessWindowHint flag. I found no acceptable/affordable solution with this idea.
Answered By - Mickaël C. Guimarães Answer Checked By - Katrina (WPSolving Volunteer)