概述
許多工程軟件,如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
反正就是用splitDockWidget
和addDockWidget
你想怎么布置就怎么布置。
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