QDialog::move() 不考虑多屏幕 Ubuntu 上的任务栏
QDialog::move() not considering taskbar on Ubuntu with multiple screens
通常,使用 QDialog::move() 移动 QDialog 会将对话框置于任务栏之外。
但是,在带有两个显示器的 Ubuntu 20.04 上,无框对话框并非如此:
如果对话框不是无框的,则不会发生这种情况:
已在 Ubuntu 20.04 上观察到此行为。它也仅在某些配置下发生:
- 主显示器需要在右侧,任务栏在左侧(两个显示器之间)
- 左显示器的分辨率需要低于右显示器
- 需要禁用分数缩放
以下是屏幕截图中使用的最小可重现示例的代码:
#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);
}
主要 window 没那么有趣,它只创建子 window 控制它的 WindowFlags 属性 :
#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");
}
这看起来像是 Qt 中的错误。有谁知道这是否是预期的行为?或者如何解决这个问题?
对于这个问题我没有找到合适的解决方案或令人满意的解决方法,但找到了一个部分令人满意的解决方案:
- 在对话框中的每个
move()
之前,将其标志设置为 Qt::Window(无框架)并隐藏它。
- 覆盖
moveEvent()
处理程序,将 window 标志设置为 Qt::FramelessWindowHint 并显示它。
以下是我对这个示例所做的两个更改:
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();
});
}
我也试过改变对话绘画。这个想法是将 window 标志设置为“framefull”对话框,但将对话框绘制为好像它具有 FramelessWindowHint 标志。我没有找到 acceptable/affordable 这个想法的解决方案。
通常,使用 QDialog::move() 移动 QDialog 会将对话框置于任务栏之外。 但是,在带有两个显示器的 Ubuntu 20.04 上,无框对话框并非如此:
如果对话框不是无框的,则不会发生这种情况:
已在 Ubuntu 20.04 上观察到此行为。它也仅在某些配置下发生:
- 主显示器需要在右侧,任务栏在左侧(两个显示器之间)
- 左显示器的分辨率需要低于右显示器
- 需要禁用分数缩放
以下是屏幕截图中使用的最小可重现示例的代码:
#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);
}
主要 window 没那么有趣,它只创建子 window 控制它的 WindowFlags 属性 :
#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");
}
这看起来像是 Qt 中的错误。有谁知道这是否是预期的行为?或者如何解决这个问题?
对于这个问题我没有找到合适的解决方案或令人满意的解决方法,但找到了一个部分令人满意的解决方案:
- 在对话框中的每个
move()
之前,将其标志设置为 Qt::Window(无框架)并隐藏它。 - 覆盖
moveEvent()
处理程序,将 window 标志设置为 Qt::FramelessWindowHint 并显示它。
以下是我对这个示例所做的两个更改:
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();
});
}
我也试过改变对话绘画。这个想法是将 window 标志设置为“framefull”对话框,但将对话框绘制为好像它具有 FramelessWindowHint 标志。我没有找到 acceptable/affordable 这个想法的解决方案。