概述

许多工程软件,如Qt Creator,VS,matlab等,都是使用dock布局窗口,这样用户可以自定义界面,自由组合窗口。 
Qt的嵌套布局由QDockWidget完成,用Qt Creator拖界面得到的dock布置形式比较固定,不能得想要的任意组合形式,要得到如下图所示的效果,后续布局必须通过代码来完成。 
 
ps:这是自己没事写的一个数据可视化软件 
下面说说如何实现完全自由的界面布局效果:

QDockWidget在QMainWindow的布局函数

要在QMainWindow里对dock进行布局,需要用到如下几个函数:

  • 添加dock函数 
    此函数用于给dock指定位置,同时也可以更改dock的位置,此函数命名为addDockWidget有点容易误导,因为不仅仅有add的功能,还有chang的功能
void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget)
void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget, Qt::Orientation orientation)
  • 1
  • 2
  • 1
  • 2
  • 分割dock窗口函数 
    此函数的功能是把两个dock进行左右或上下并排布置,做成一个类似QSplit的功能
void QMainWindow::splitDockWidget(QDockWidget * first, QDockWidget * second, Qt::Orientation orientation)
  • 1
  • 1
  • tab化窗口函数 
    此函数的功能是把多个dock变成一个tab形式的窗体
void QMainWindow::tabifyDockWidget(QDockWidget * first, QDockWidget * second)
  • 1
  • 1
  • 设置dock嵌套布局 
    此函数是设置嵌套布局的关键
void QMainWindow::setDockNestingEnabled(bool enabled)
  • 1
  • 1

以上几个函数就能完成比较复杂的嵌套布局了。

设置嵌套布局

下面通过例子来讲解如何设置复杂的嵌套布局 
先用Qt Creator拖放9个dock进视图里,为了好区分,给每个dock设置一个背景颜色: 
 
dock属性随便设置,保证都任意区域可以停靠即可 
由于这里不需要MainWindow的中间窗口,整个视图都由dock组成,因此先把QMainWindow的中间窗口部件去除: 
在MainWindow的构造函数加入如下语句,即可把MainWindow的中间窗口去除,这时整个MainWindow只有Dock组成

QWidget* p = takeCentralWidget();
if(p)
delete p;
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

编译出来的效果如图所示: 
 
拖动dock可以发现,只能在两边进行组合,我想把dock放置到中间是无法实现的,这是由于为了简化dock的吸附,QMainWindow默认是把dock嵌套关闭的,需要我们手动设置,在MainWindow的构造函数里添加:

setDockNestingEnabled(true);
  • 1
  • 1

即可打开嵌套功能,这时编译出来的窗口能实现如下嵌套: 
 
此时,整个窗口的布局将变得非常灵活且复杂,由于Qt Creator在ui编辑器中无法像编译出来的程序那样任意调整位置,因此需要手动对窗口进行设置。下面将介绍如何用代码设置复杂的dock 
为了方便,添加两个函数和一个成员变量: 
head:

public:
//移除并隐藏所有dock
void removeAllDock();
//显示dock窗口
void showDock(const QList<int>& index = QList<int>());
private:
QList<QDockWidget*> m_docks;///< 记录所有dockWidget的指针
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

CPP:

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//删除中央窗体
QWidget* p = takeCentralWidget();
if(p)
delete p;
//允许嵌套dock
setDockNestingEnabled(true);
//记录所有的dock指针
m_docks.append(ui->dockWidget_1);
m_docks.append(ui->dockWidget_2);
m_docks.append(ui->dockWidget_3);
m_docks.append(ui->dockWidget_4);
m_docks.append(ui->dockWidget_5);
m_docks.append(ui->dockWidget_6);
m_docks.append(ui->dockWidget_7);
m_docks.append(ui->dockWidget_8);
m_docks.append(ui->dockWidget_9);
} MainWindow::~MainWindow()
{
delete ui;
}
///
/// \brief 移除并隐藏所有的dock
///
void MainWindow::removeAllDock()
{
for(int i=0;i<9;++i)
{
removeDockWidget(m_docks[i]);
}
}
///
/// \brief 显示指定序号的dock
/// \param index 指定序号,如果不指定,则会显示所有
///
void MainWindow::showDock(const QList<int> &index)
{
if (index.isEmpty())
{
for(int i=0;i<9;++i)
{
m_docks[i]->show();
}
}
else
{
foreach (int i, index) {
m_docks[i]->show();
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

void removeAllDock();函数可以把所有的dock隐藏void showDock(const QList<int>& index = QList<int>())则可以显示指定的dock。 
下面先对需要用到的几个函数进行示范:

addDockWidget

addDockWidget函数用于给MainWindow添加dock窗体,指定添加的区域,如果想改变dock的位置,也可以使用此函数进行移动。

void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget)
void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget, Qt::Orientation orientation)
  • 1
  • 2
  • 1
  • 2

如:

addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_1);
addDockWidget(Qt::RightDockWidgetArea,ui->dockWidget_2);
addDockWidget(Qt::TopDockWidgetArea,ui->dockWidget_3);
addDockWidget(Qt::BottomDockWidgetArea,ui->dockWidget_4);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

把4个dock按照上下左右布置,效果如下: 

splitDockWidget

splitDockWidget

void QMainWindow::splitDockWidget(QDockWidget * first, QDockWidget * second, Qt::Orientation orientation)
  • 1
  • 1

此函数可以把一个dock(QDockWidget * first)在其位置上进行嵌套,嵌套可以指定水平嵌套或者垂直嵌套,嵌套方向是从左到右,从上到下,也就是QDockWidget * first相对于QDockWidget * second永远在左边或者上边。 
如:

removeAllDock();
addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_1);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_2,Qt::Horizontal);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_3,Qt::Horizontal);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_4,Qt::Horizontal);
splitDockWidget(ui->dockWidget_4,ui->dockWidget_5,Qt::Horizontal);
showDock(QList<int>()<< 0<<1<<2<<3<<4);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

得到如下效果: 
 
若是:

removeAllDock();
addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_1);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_2,Qt::Vertical);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_3,Qt::Vertical);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_4,Qt::Vertical);
splitDockWidget(ui->dockWidget_4,ui->dockWidget_5,Qt::Vertical);
showDock(QList<int>()<< 0<<1<<2<<3<<4);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

那么效果变为: 
 
此函数是实现嵌套布局的关键,首先指定基准,然后开始进行分割,即可得到比较复杂的布局。 
分割原则是:先水平,再竖直,从左到右,从上到下 
下面显示一个九宫格布局: 
 
实现代码

removeAllDock();
//原则,先左右,再上下
addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_1);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_2,Qt::Horizontal);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_3,Qt::Horizontal);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_4,Qt::Vertical);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_5,Qt::Vertical);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_6,Qt::Vertical);
splitDockWidget(ui->dockWidget_4,ui->dockWidget_7,Qt::Vertical);
splitDockWidget(ui->dockWidget_5,ui->dockWidget_8,Qt::Vertical);
splitDockWidget(ui->dockWidget_6,ui->dockWidget_9,Qt::Vertical);
showDock();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

 
实现代码:

removeAllDock();
//原则,先左右,再上下
addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_1);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_2,Qt::Horizontal);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_3,Qt::Horizontal);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_4,Qt::Vertical);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_6,Qt::Vertical);
splitDockWidget(ui->dockWidget_4,ui->dockWidget_7,Qt::Vertical);
splitDockWidget(ui->dockWidget_6,ui->dockWidget_9,Qt::Vertical);
showDock(QList<int>()<< 0<<1<<2<<3<<5<<6<<8);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

 
实现代码:

removeAllDock();
addDockWidget(Qt::TopDockWidgetArea,ui->dockWidget_1);
addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_2);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_3,Qt::Horizontal);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_4,Qt::Horizontal);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_5,Qt::Horizontal);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_6,Qt::Horizontal);
splitDockWidget(ui->dockWidget_4,ui->dockWidget_7,Qt::Horizontal);
showDock(QList<int>()<< 0<<1<<2<<3<<4<<5<<6);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

反正就是用splitDockWidgetaddDockWidget你想怎么布置就怎么布置。

tabifyDockWidget

此函数就是实现tab合并功能 
直接看看下面例子: 
 
实现原理:

removeAllDock();
addDockWidget(Qt::LeftDockWidgetArea,ui->dockWidget_1);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_2,Qt::Horizontal);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_3,Qt::Horizontal);
splitDockWidget(ui->dockWidget_1,ui->dockWidget_4,Qt::Vertical);
splitDockWidget(ui->dockWidget_2,ui->dockWidget_5,Qt::Vertical);
splitDockWidget(ui->dockWidget_3,ui->dockWidget_6,Qt::Vertical);
tabifyDockWidget(ui->dockWidget_1,ui->dockWidget_7);
tabifyDockWidget(ui->dockWidget_5,ui->dockWidget_8);
tabifyDockWidget(ui->dockWidget_3,ui->dockWidget_9);
showDock();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

代码: 
本例代码下载:本例代码免积分-

http://blog.csdn.net/czyt1988/article/details/51209619#comments

QDockWidget嵌套布局详解-实现Visual Studio布局的更多相关文章

  1. NUint使用详解及Visual Studio配置

    NUint使用详解及Visual Studio配置 阅读目录 什么是单元测试? 为什么使用单元测试? NUint使用详解: 示例 属性 断言 简单测试 VS配置: External Tools Vis ...

  2. Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

    [Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.And ...

  3. 【单元测试】NUint使用详解及Visual Studio配置

    阅读目录 什么是单元测试? 为什么使用单元测试? NUint使用详解: 示例 属性 断言 简单测试 VS配置: External Tools Visual Nunit 2010 NUnit Test ...

  4. Android五大布局详解——FrameLayout(帧布局)

    FrameLayout 这个布局相对前面两节介绍的布局就简单了很多,因此它的应用场景也就特别的少.这种布局没有方便的定位方式,所有的控件都会默认摆放在布局的左上角.新建UILayoutTestThre ...

  5. Android五大布局详解——LinearLayout(线性布局)

    Android五大布局 本篇开始介绍Android的五大布局的知识,一个丰富的界面显示总是要有众多的控件来组成的,那么怎样才能让这些控件能够按你的想法进行摆放,从而自定义你所想要的用户界面呢?这就牵涉 ...

  6. 详解在Visual Studio中使用git版本系统[转]

    这篇教程的预期,是希望没有任何版本使用基础的新手也可以掌握,所以细节较多,不当之处,欢迎指正. 一 .安装 git 开发工具 如果要使用 git 进行版本管理,其实使用 git 命令行工具就完全足够了 ...

  7. 详解在visual studio中使用git版本系统(图文)

    很多人已经在使用git(或正在转移到git上),在github.com上,也看到园子里不少同学的开源项目,非常不错.但相关教程似乎不多,所以趁着我自己的开源项目源码托管(https://github. ...

  8. 详解在Visual Studio中使用git版本系统

    转自:http://www.uml.org.cn/pzgl/201206211.asp

  9. 【转】详解在visual studio中使用git版本系统(图文)

    http://blog.csdn.net/wojilu/article/details/6976230 很多人已经在使用git(或正在转移到git上),在github.com上,也看到不少国内同学的开 ...

随机推荐

  1. 关于jave在oracle驱动下事务提交与回滚问题

    一直以来,都觉得Connection假设设置了setAutoCommit(false)后.启动手工事务提交.必须手工进行commit或者rollback才行.今天正好遇到一个问题.结果大跌眼镜. 于是 ...

  2. Java简单记录

    XML指令: <?xml version="1.0" encoding="UTF-8" standalone="no" ?> & ...

  3. iOS开发中两个不错的宏定义

    /** Synthsize a weak or strong reference. Example: @weakify(self) [self doSomething^{ @strongify(sel ...

  4. FFT算法

    FFT算法的完整DSP实现 傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's G ...

  5. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  6. Android 应用内HttpClient 与 WebView 共享 Cookie

    DefaultHttpClient httpclient=....; String toUrl="https://cap.cityu.edu.hk/studentlan/details.as ...

  7. __get __set 实例

    <?php class Person { //下面是人的成员属性,都是封装的私有成员 private $name; //人的名子 private $sex; //人的性别 private $ag ...

  8. web.xml的配置问题

    [转]http://perfy315.iteye.com/blog/2009258 首先 classpath是指 WEB-INF文件夹下的classes目录 ,指的就是java文件编译之后的path. ...

  9. dotnet tools 运行 dotnet run

    dotnet tools 运行 dotnet run dotnet run 命令介绍 前言 本篇主要介绍 asp.net core 中,使用 dotnet tools 运行 dotnet run 之后 ...

  10. BZOJ 2429: [HAOI2006]聪明的猴子( MST )

    水题, 求MST即可. -------------------------------------------------------------------------------- #includ ...