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 中的错误。有谁知道这是否是预期的行为?或者如何解决这个问题?

对于这个问题我没有找到合适的解决方案或令人满意的解决方法,但找到了一个部分令人满意的解决方案:

  1. 在对话框中的每个 move() 之前,将其标志设置为 Qt::Window(无框架)并隐藏它。
  2. 覆盖 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 这个想法的解决方案。