1. 简介
要用QDockWidget就不得不提QMainWindow。
1.1 QMainWindow
The QMainWindow class provides a main application window.
QMainWindow类提供一个主应用窗口A main window provides a framework for building an application’s user interface. Qt has QMainWindow and its related classes for main window management. QMainWindow has its own layout to which you can add QToolBars, QDockWidgets, a QMenuBar, and a QStatusBar. The layout has a center area that can be occupied by any kind of widget. You can see an image of the layout below.
一个主窗口提供一个用于构造程序用户界面的平台,Qt使用QMainWindow及其相关的类来管理主窗口界面,QMainWindow类拥有自己的layout,你可以添加QToolBars, QDockWidgets, a一个QMenuBar,以及一个 QStatusBar。这个layout还有一个中心区域,可以添加任何种类的widget
Note: Creating a main window without a central widget is not supported. You must have a central widget even if it is just a placeholder.
QMainWindow对象必须要有一个central widget
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 |
2. QDockWidget在QMainWindow的布局函数
常用函数:
1、addDockWidget:添加停靠控件,用于指定或更改停靠控件的位置以及方向。
void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget)
void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget, Qt::Orientation orientation)
2、splitDockWidget:分割窗口,用于对两个QDockWidget进行水平或垂直布局,做成类似QSplit的功能。
void QMainWindow::splitDockWidget(QDockWidget * first, QDockWidget * second, Qt::Orientation orientation)
3、tabifyDockWidget:合并窗口,用于将多个QDockWidget变成一个tab形式的叠加窗体。
void QMainWindow::tabifyDockWidget(QDockWidget * first, QDockWidget * second)
4、setDockNestingEnabled:是否允许嵌套布局
void QMainWindow::setDockNestingEnabled(bool enabled)
5、setTitleBarWidget:
void QDockWidget::setTitleBarWidget(QWidget * widget)
设置任意的widget作为dock widget的工具栏。如果widget设置为0,那么之前在dock widget上设置的任意自定义工具栏都会被清除,但是不是删除,并且会使用默认的工具栏。
如果我们为工具栏设置了widget,那么当它悬浮的时候,QDockWidget不会使用本地窗口装饰它。
下面是对实现自定义的工具栏的一些建议:
- 那些不是明确由工具栏处理的鼠标事件应该通过调用QMouseEvent::ignore()函数忽略掉。这些事件就会传递给QDockWidget,由QDockWidget按照常规的方式处理。拖动鼠标的时候就移动,双击的时候就锁住/解锁等等。
- 当为QDockWidget设置了DockWidgetVerticalTitleBar时,那么工具栏窗口部件就会相应的放置在新的位置上。在resizeEvent()中,工具栏必须检查放置的方向:
QDockWidget *dockWidget = qobject_cast<QDockWidget*>(parentWidget()); if (dockWidget->features() & QDockWidget::DockWidgetVerticalTitleBar) { // I need to be vertical } else { // I need to be horizontal }
- 工具栏widget必须包含有合法的QWidget::sizeHint()和QWidget::minimumSizeHint()。这些方法必须考虑工具栏放置的方向。
- 从一个锁定的widget中移除工具栏是不可能的。然而,我们可以通过将默认构造的QWidget作为工具栏widget来达到这种效果。
6. setWidget:
void QDockWidget::setWidget(QWidget * widget)
当widget添加的时候,如果dock widget是可见的,那么你就需要显示的调用show()函数。
在调用这个函数之前,你必须先添加widget的布局,否则,添加的widget就是不可见的。
3. DockWidget 应用实例:
原文:【QT】QT从零入门教程(六):QDockWidget停靠窗口
3.1 设置嵌套布局
在自编软件中,博主用到了9个QDockWidget,作为软件的基本窗口进行布局。下面介绍创建布局的方法。
首先是去除中央窗体(这是重点)。QMainWindow中自带中央窗体,如果不去除的话,可能会造成窗口间有空块的情况,大家可以自行尝试。去除后,所有窗口都由QDockWidget构成。
// cpp
QWidget* p = takeCentralWidget(); //删除中央窗体
if (p)
delete p;
setDockNestingEnabled(true); //允许嵌套dock
3.2 创建多个窗口
如果想对窗口大小进行限制呢?QDockWidget也有相应的函数。
dock ->setFixedWidth(int w);
dock ->setFixedHeight(int h);
dock ->setFixedSize(int w, int h);
dock ->setMinimumWidth(int minw);
dock ->setMinimumHeight(int minh);
dock ->setMinimumSize(int minw, int minh)
dock ->setMaximumWidth(int maxw);
dock ->setMaximumHeight (int maxh);
dock ->setMaximumSize(int maxw, int maxh)
示例代码:
// 头文件
QDockWidget *dock_Image; // 图像窗口
QDockWidget* dock_Tool;// 工具箱窗口
QDockWidget* dock_Geom;// 几何变换窗口
QDockWidget* dock_Gray;// 灰度变换窗口
QDockWidget* dock_Enhance;// 图像增强窗口
QDockWidget* dock_Morp;// 形态学处理窗口
QDockWidget* dock_Color;// 颜色模型窗口
QDockWidget* dock_Prop;// 属性窗口
QDockWidget* dock_Output;// 输出窗口
// cpp
// QDockWidget* dock_Image = new QDockWidget(tr("图像"), this); // 上节中已定义,如果只想做本节内容,可取消注释
dock_Image->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); // 设置为可移动可浮动,但不可关闭
dock_Image->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); // 可移动范围:左右
dock_Image->setMinimumSize(600, 600); // 设置最小宽高
dock_Tool = new QDockWidget(tr("工具箱"), this); // 工具箱窗口,若想设置特征或移动范围,方法同上。
dock_Geom = new QDockWidget(tr("几何变换"), this); // 几何变换窗口
dock_Gray = new QDockWidget(tr("灰度变换"), this); // 灰度变换窗口
dock_Enhance = new QDockWidget(tr("图像增强"), this); // 图像增强窗口
dock_Morp = new QDockWidget(tr("形态学处理"), this); // 形态学处理窗口
dock_Color = new QDockWidget(tr("颜色模型"), this); // 颜色模型窗口
dock_Prop = new QDockWidget(tr("属性"), this); // 属性窗口
dock_Output = new QDockWidget(tr("输出"), this); // 输出窗口
// 进行布局
setCentralWidget(dock_Image); // 指定为中心窗口
addDockWidget(Qt::LeftDockWidgetArea, dock_Tool);
addDockWidget(Qt::BottomDockWidgetArea, dock_Output);
addDockWidget(Qt::RightDockWidgetArea, dock_Geom);
addDockWidget(Qt::RightDockWidgetArea, dock_Gray);
addDockWidget(Qt::RightDockWidgetArea, dock_Enhance);
addDockWidget(Qt::RightDockWidgetArea, dock_Morp);
addDockWidget(Qt::RightDockWidgetArea, dock_Color);
addDockWidget(Qt::RightDockWidgetArea, dock_Prop);
// 分割窗口
splitDockWidget(dock_Tool, dock_Image, Qt::Horizontal); // 水平
splitDockWidget(dock_Geom, dock_Output, Qt::Vertical); // 垂直
// 合并窗口
tabifyDockWidget(dock_Geom, dock_Gray);
tabifyDockWidget(dock_Gray, dock_Enhance);
tabifyDockWidget(dock_Enhance, dock_Morp);
tabifyDockWidget(dock_Morp, dock_Color);
tabifyDockWidget(dock_Output, dock_Prop);
dock_Geom->raise(); // raise()函数可使指定窗口置于最前
// connect(dock_Tool, SIGNAL(visibilityChanged(bool)), this, SLOT(isDockTool()));
// 当窗体隐藏或显示时,其信号为visibilityChanged(bool)函数,此处仅作简单演示,槽函数是自定义的,其他窗口同理。
效果: