QT5.15.2版本使用QDockWidget 的setFloating无效

程序从qt 4.8.5升级 qt 5.15.2时原程序中涉及的QDockWidget的函数setFloating() 不起作用(setFloating(true)->setFloating(false) 不起作用,反之亦然,即在Widget的构造中设置完是否浮动后,在showWidget中修改无效)
在qt 5.15.2下新建一个demo效果相同,问题描述:在一个Widget中有一个DockWidget,如果在mian函数中直接使用Widget的show此时setFloating没有问题,如果在MianWidget中使用StackWidget,将使用addWidget将Widget添加进来此时使用setFloating无效,其他的流程相同

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
 
Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea);
    ui->dockWidget->setFeatures(QDockWidget::DockWidgetFloatable);
    ui->dockWidget->setFloating(true);
    ui->dockWidget->hide();
 
    ui->widgetEnterSolu->installWidget(ui->dockWidget, NULL);
    connect(ui->widgetEnterSolu, SIGNAL(signal_widgetVisible(bool)), this, SLOT(slot_widgetVisible(bool)));
}
 
Widget::~Widget()
{
    delete ui;
}
 
void Widget::slot_widgetVisible(bool visible)
{
    QWidget* lockWidget = dynamic_cast<QWidget*>(sender());
    if(NULL == lockWidget)
        return;
    qDebug() << "##cc## slot widget visible " << visible;
    if(visible)
        showWidget(lockWidget);
    else if(ui->widgetEnterSolu == lockWidget)
        hideWidget(ui->dockWidget);
}
 
void Widget::showWidget(const QWidget* widget)
{
    if(widget == ui->widgetEnterSolu)
    {
        if((!ui->widgetEnterSolu->isLocked()) && (!ui->dockWidget->isFloating()))
        {
            ui->dockWidget->setFloating(!ui->widgetEnterSolu->isLocked());
            qDebug() << "0:" << ui->dockWidget->isFloating();
        }
        else if(ui->widgetEnterSolu->isLocked())
        {
            ui->dockWidget->setParent(this);
            ui->dockWidget->setFloating(false);
            qDebug() << "1:" << ui->dockWidget->isFloating();
        }
 
        if(!ui->widgetEnterSolu->isLocked())
        {
 
            const QRect& lRect = ui->widgetEnter->geometry();
            const QPoint& lGPoint = ui->widgetEnter->mapToGlobal(QPoint(0, 0));
            ui->dockWidget->move(lGPoint.x() + lRect.width() + 30, lGPoint.y());
            ui->dockWidget->setFixedHeight(lRect.height()/*-10*/);
        }
 
        ui->dockWidget->show();
        qDebug() << "##cc## show widget " << ui->dockWidget->geometry() << ui->dockWidget->isVisible();
    }
}
 
 
void Widget::hideWidget(const QWidget* widget)
{
    if((widget == ui->dockWidget) && (!ui->widgetEnterSolu->isLocked()))
    {
        ui->dockWidget->hide();
        qDebug() << "##cc## hide widget " << ui->dockWidget->isVisible();
    }
}
 
CLockOpWidget::CLockOpWidget(QWidget* parent)
    : QWidget(parent), leave_widget_(NULL)
    , is_locked_(false)
{
    QPalette p(palette());
    p.setColor(QPalette::Background, Qt::black);
    setAutoFillBackground(true);
    setPalette(p);
}
 
void CLockOpWidget::installWidget(QWidget* leaveWidget, QWidget* resizeWidget)
{
    if(leaveWidget != NULL)
    {
        leave_widget_ = leaveWidget;
        leave_widget_->installEventFilter(this);
    }
}
 
void CLockOpWidget::enterEvent(QEvent* event)
{
    emit signal_widgetVisible(true);
    QWidget::enterEvent(event);
}
 
void CLockOpWidget::mousePressEvent(QMouseEvent* event)
{
    is_locked_ = !is_locked_;
    qDebug() << "CLockOpWidget::mousePressEvent:" << is_locked_;
    emit signal_widgetVisible(true);
    QWidget::mousePressEvent(event);
}
 
bool CLockOpWidget::eventFilter(QObject* watched, QEvent* event)
{
    const QWidget* widget = qobject_cast<QWidget*>(watched);
    if((widget == leave_widget_) && (QEvent::Leave == event->type()))
        emit signal_widgetVisible(false);
 
    return QWidget::eventFilter(watched, event);
}
 

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    Widget(QWidget *parent = NULL);
    ~Widget();
 
    void showWidget(const QWidget *widget);
    void hideWidget(const QWidget *widget);
 
private slots:
    void slot_widgetVisible(bool bVisible);
 
private:
    Ui::Widget *ui;
};
 
 
class CLockOpWidget : public QWidget
{
    Q_OBJECT
public:
    CLockOpWidget(QWidget* parent = 0);
    ~CLockOpWidget() {}
 
    void installWidget(QWidget *leaveWidget, QWidget *resizeWidget);
    /// true:locking
    const bool isLocked() const
    { return is_locked_; }
 
signals:
    void signal_widgetVisible(const bool &visible);
protected:
    void enterEvent(QEvent *event);
    void mousePressEvent(QMouseEvent *event); 
    bool eventFilter(QObject *watched, QEvent *event);
 
private:
    QWidget *leave_widget_, *resize_widget_;
    bool is_locked_;
};
#endif // WIDGET_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
 
class Widget;
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = NULL);
    ~MainWindow();
 
private slots:
 
private:
    Ui::MainWindow *ui;
    Widget* m_pWidget;
};
 
#endif // MAINWINDOW_H
 
 
 
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "widget.h"
MainWindow::MainWindow(QWidget* parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_pWidget = new Widget();
    int nIndex = ui->stackedWidget->addWidget(m_pWidget);
    ui->stackedWidget->setCurrentIndex(nIndex);
}
 
MainWindow::~MainWindow()
{
    delete ui;
}

#include "widget.h"
#include <QApplication>
#include "mainwindow.h"
 
int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    // 方法1
//    Widget w;
//    w.showMaximized();
 
    // 方法2
    MainWindow w2;
    w2.showMaximized();
    return a.exec();
}

在main函数中使用方法1时setFloating()没有问题,使用方法2时有问题,不知道到是QT版本升级对QDockWidget进行某些修改,还是本人代码存在问题,请各位不吝赐教

这可能是由于Qt版本升级导致的行为变化。在你的代码中,你正在尝试在构造函数中设置QDockWidget为浮动状态。然而,在构造函数中设置QDockWidget为浮动可能会在某些情况下无效,因为QWidget的显示状态在构造函数被调用时可能还未被完全初始化。

你可以尝试在构造函数之后,例如在showEvent()或者其他适当的地方设置QDockWidget为浮动。例如:

void Widget::showEvent(QShowEvent *event) {
    QWidget::showEvent(event);
    ui->dockWidget->setFloating(true);
}

这样可以确保在QWidget的状态被完全初始化后再设置QDockWidget为浮动。

另一种可能的解决方案是使用QTimer::singleShot()在事件循环开始后设置QDockWidget为浮动:

QTimer::singleShot(0, [this](){ ui->dockWidget->setFloating(true); });

这样可以确保setFloating()在所有构造和初始化代码执行完毕后被调用。
试试吧

可能布局管理器的影响。

在StackedWidget中,可以尝试使用setLayout()函数将QDockWidget添加到特定的QWidget,然后将该QWidget添加到StackedWidget中。
如果setLayout()函数不起作用,可以考虑使用QDockWidget的setParent()函数将其独立成为MianWidget的直接子部件,而不是添加到StackedWidget中。

  • 给你找了一篇非常好的博客,你可以看看是否有帮助,链接:QT 之 QDockWidget -设置QDockWidget的初始大小
  • 除此之外, 这篇博客: QT之 QDockWidget 应用总结中的 1.2 可停靠类 QDockWidget: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • QDockWidget(const QString & title, QWidget * parent = 0, Qt::WindowFlags flags = 0)
    QDockWidget(QWidget * parent = 0, Qt::WindowFlags flags = 0)

    QDockWidget是QWidget的子类,它生成那些可以停靠到视窗边缘并自适应大小的widget,这个类应用很广泛,因为它可以让用户在使用UI的过程中更加的轻松,灵活,提高用户体验,大家最熟悉的dock效果,应该就是window针对桌面的dock效果了,你可以把浏览器页面当成DockWidget,整个桌面当成MainWindow,拖动浏览器到桌面边缘,就会有停靠效果,DockWidget的效果和这个是一样的道理。

     

    当你生成一个DockWidget后,你还需要对他进行一些配置,Qt为Dock准备了一些功能属性,可以在几个区域中移动,或者是悬浮。该类提供的API允许程序员限制dock widgets的移动,悬浮和关闭,以及它可以被放置的区域。

    设置方法是:

    void setFeatures(DockWidgetFeatures features)

    参数见下表:

    常量描述
    QDockWidget::DockWidgetClosable可关闭
    QDockWidget::DockWidgetMovable可移动
    QDockWidget::DockWidgetFloatable可漂浮
    QDockWidget::DockWidgetVerticalTitleBar在左边显示垂直的标签栏
    QDockWidget::AllDockWidgetFeatures具有1,2,3的所有功能
    QDockWidget::NoDockWidgetFeatures无法关闭,不能移动,不能漂浮

    QDockWidget虽然继承了Widget类,但是他们在add的方式上却有很大的不同。

    Qt添加widget的方式,需要先铺上一层layout,然后再通过这个layout添加widget或者其他layout,如此循环。

    但是DockWidget特殊的地方就在于,系统已经专门为他准备好了layout,DockWidget只能放入这个layout里面才能正常工作,而这个layout貌似只能存在于QMainWidow下面,这就是为什么只有QMainWindow类才有addDockWidget方法的原因。

    QMainWidow默认的Layout:

                                                             

    å¨è¿éæå¥å¾çæè¿°

    换言之,DockWidget只能放到QMainWindow里面。

    与一般的Widget添加方式不同,由于QMainWindow已经拥有自己专门的layout,所以DockWidget只能够通过addDockWidget的方式添加到QMainWindow内,在其他任何Layout里添加DockWidget,结果都是灾难的,不信你可以试试。

    addDockWidget方法:

    void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget)

    它有两个参数,第一个参数是代表DockWidget的初始停靠方位,第二个就是对象

    属性描述
    Qt.BottomDockWidgetArea   底部停靠
    Qt.LeftDockWidgetArea    左边停靠
    Qt.RightDockWidgetArea    右边停靠
    Qt.TopDockWidgetArea    上部停靠
    Qt.NoDockWidgetArea   不显示Widget

版本升级的话,有一些内置函数多少也是会修改一部分的


看起来在“setFloating(true)”的情况下,在显示窗口之前它仍然显示但是有“屏幕外”位置,所以你看不到它。尝试将代码改为smth,
dock1.setFloating(true);
qDebug() << "old size: " << dock1.size() << " old pos: " << dock1.pos();
dock1.resize(QSize(200, 200)); // set new size for the dock window
dock1.move(QPoint(50, 50));    // set new position for the dock window
dock1.show();

确保你在使用setFloating()之前已经正确地创建了QDockWidget对象,并将其添加到主窗口或StackWidget中。
尝试使用QDockWidget的setFeature()函数,将QDockWidget::DockWidgetFloatable属性设置为true。
如果不行,还是版本的问题,换一个版本试试看。

换个版本试试

采用chatgpt:
根据您的描述,问题可能是由于在Qt 5.15.2中的更改导致的。为了解决这个问题,您可以尝试以下修改:

在Widget类的构造函数中,将ui->dockWidget->hide();移动到showWidget函数的开头,确保在设置setFloating之前先隐藏QDockWidget。

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea);
    ui->dockWidget->setFeatures(QDockWidget::DockWidgetFloatable);

    ui->widgetEnterSolu->installWidget(ui->dockWidget, NULL);
    connect(ui->widgetEnterSolu, SIGNAL(signal_widgetVisible(bool)), this, SLOT(slot_widgetVisible(bool)));

    ui->dockWidget->hide(); // Move hide() here
}

在showWidget函数中,在设置setFloating之前,将QDockWidget从父窗口中移除,然后再重新设置父窗口。

void Widget::showWidget(const QWidget* widget)
{
    if (widget == ui->widgetEnterSolu)
    {
        if ((!ui->widgetEnterSolu->isLocked()) && (!ui->dockWidget->isFloating()))
        {
            ui->dockWidget->hide(); // Hide the dock widget before modifying its parent

            ui->dockWidget->setParent(nullptr); // Remove parent widget
            ui->dockWidget->setFloating(!ui->widgetEnterSolu->isLocked());
            qDebug() << "0:" << ui->dockWidget->isFloating();
        }
        else if (ui->widgetEnterSolu->isLocked())
        {
            ui->dockWidget->setParent(this); // Set the parent widget again
            ui->dockWidget->setFloating(false);
            qDebug() << "1:" << ui->dockWidget->isFloating();
        }

        // Rest of the code remains the same
        if (!ui->widgetEnterSolu->isLocked())
        {
            const QRect& lRect = ui->widgetEnter->geometry();
            const QPoint& lGPoint = ui->widgetEnter->mapToGlobal(QPoint(0, 0));
            ui->dockWidget->move(lGPoint.x() + lRect.width() + 30, lGPoint.y());
            ui->dockWidget->setFixedHeight(lRect.height()/*-10*/);
        }

        ui->dockWidget->show();
        qDebug() << "##cc## show widget " << ui->dockWidget->geometry() << ui->dockWidget->isVisible();
    }
}

这只是对您提供的代码的一种可能的修改。