程序从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中。
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();
}
}
这只是对您提供的代码的一种可能的修改。