引言
上一篇中講述了工具箱的添加。通過一個水平佈局管理器,我們將一系列的工具按鈕組合到了一起,完成了工具箱的編寫。本文在前面的基礎上實現窗體分割效果、堆棧式窗口以及Tab選項卡。
窗體分割
窗體分割是一個常見的功能,尤其在一些IDE中用的非常廣泛。主要是窗體分割能夠在視覺上對程序功能進行分組分類,在保證界面美觀的同時還能保證內容井井有條,何樂而不爲呢?Qt中提供了一個用於分割窗體的類:QSplitter。這個類的使用也非常簡單,準備好需要分割的窗口,設置好分割方向和比例即可。不過值得注意的是,QSplitter是一個窗口管理類,在沒有添加子控件是看不到QSplitter效果的。這一點在Qt Designer中也可以驗證。
在我們的項目中,我們增加一個QSplitter類成員,並在主窗口的構造函數中添加如下代碼:
1
2
3
4
5
6
7
8
9
|
splitter
= new QSplitter(Qt::Horizontal,
this ); splitter->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding); splitter->setHandleWidth(1); splitter->addWidget( new QWidget( this )); splitter->addWidget( new QWidget( this )); splitter->handle(1)->setDisabled( true ); splitter->setStretchFactor(0,
1); splitter->setStretchFactor(1,
3); |
在上面的代碼中,我們將左右兩個子窗口的比例設置爲1:3。也就是說左邊窗口占25%的空間,右邊佔75%。另外,我們還設置了QSplitter的Handle寬度。handle指的就用於分割窗體的那根線。我們將其寬度設置爲1個像素寬,setDisabled(true)將其設置爲不可拖動的。這樣一來,用戶就無法用鼠標拖拽左右窗口的大小了。看看效果:
在分割出來的子窗口中,還可以進行進一步的分割,也就是QSplitter的嵌套使用。
堆棧式窗口及Tab選項卡
堆棧式窗口取義於數據結構中的堆棧,也就是說多個窗口堆疊在一起,當用戶點擊對應層的窗口時進行切換。以騰訊QQ的設置窗口爲例,看看到底是怎樣一種效果:
當用戶點擊“基本設置”時,窗口中的內容全部都是相關的選項卡;當點擊“安全設置”的時候,窗口內容切換爲對應的選項卡內容。也就是說一個窗口被另一個窗口“遮住”了。利用這種形式可以很容易的組織邏輯相關的內容。QStackedWidget是Qt爲我們提供的一個實現這種功能的類。除此之外,Qt還提供了一個堆棧式窗口布局管理器類:QStackedLayout。而事實上,QStackedWidget的功能正是基於QStackedLayout實現的。那麼,我們又該如何去組織這樣一種結構呢?
基本思路其實也很簡單。QStackedWidget繼承自QWidget,它本身是一個控件容器,但是也可以作爲子控件放置於其他的容器中去。那麼,我們先構造好一個QStackedWidget,然後再考慮集成到父窗口中去:
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
TrojanAssessment::TrojanAssessment(QWidget
*parent) :
ShadowWindow(parent) { //
前面省略…… //
create tree widget and stacked widget treeWidget
= new QTreeWidget( this ); treeWidget->setFrameShape(QFrame::NoFrame); stackedWidget
= new QStackedWidget( this ); stackedWidget->resize(680,
500); stackedWidget->setFrameShape(QFrame::NoFrame); initStackedWidget(); initTreeWidget(); splitter
= new QSplitter(Qt::Horizontal,
this ); splitter->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding); splitter->setHandleWidth(1); splitter->addWidget(treeWidget); splitter->addWidget(stackedWidget); splitter->handle(1)->setDisabled( true ); splitter->setStretchFactor(0,
1); splitter->setStretchFactor(1,
3); //
create title widget and status bar titleWidget
= new TitleWidget( this ); icon_label
= new QLabel( this ); icon_label->setPixmap(QPixmap( ":/menu/cloud" )); icon_label->setFixedSize(QPixmap( ":/menu/cloud" ).size()); lastrun_label
= new QLabel( this ); m_bottomLayout
= new QHBoxLayout( this ); m_bottomLayout->addStretch(); m_bottomLayout->addWidget(icon_label,
0, Qt::AlignCenter); m_bottomLayout->addWidget(lastrun_label,
0, Qt::AlignCenter); m_bottomLayout->setSpacing(5); m_bottomLayout->setContentsMargins(0,
3, 10, 3); //
remember the time when the program start login_dt
= QDateTime::currentDateTime(); restoreSettings(); QPalette
plt; plt.setBrush(QPalette::Window,
QBrush(Qt::white)); treeWidget->setPalette(plt); treeWidget->setAutoFillBackground( true ); stackedWidget->setPalette(plt); stackedWidget->setAutoFillBackground( true ); //
省略更多…… } void TrojanAssessment::initStackedWidget() { /*
initialize the stacked pages */ fmp
= new FileMonitorPage( this ); iep
= new IEPage( this ); mp
= new MemoryPage( this ); np
= new NetworkPage( this ); pp
= new ProcessPage( this ); rp
= new RegisterPage( this ); scp
= new SecurityCenterPage( this ); //add
page widgets to StackedWidgets stackedWidget->addWidget(fmp); stackedWidget->addWidget(iep); stackedWidget->addWidget(mp); stackedWidget->addWidget(np); stackedWidget->addWidget(pp); stackedWidget->addWidget(rp); stackedWidget->addWidget(scp); //
set File Monitoring as the default page. stackedWidget->setCurrentWidget(fmp); connect( this ,
SIGNAL(changeTabFMP( int )),
fmp, SLOT(onChangeTab( int ))); connect( this ,
SIGNAL(changeTabPP( int )),
pp, SLOT(onChangeTab( int ))); connect( this ,
SIGNAL(changeTabMP( int )),
mp, SLOT(onChangeTab( int ))); connect( this ,
SIGNAL(changeTabNP( int )),
np, SLOT(onChangeTab( int ))); connect( this ,
SIGNAL(changeTabRP( int )),
rp, SLOT(onChangeTab( int ))); connect( this ,
SIGNAL(changeTabSCP( int )),
scp, SLOT(onChangeTab( int ))); connect( this ,
SIGNAL(changeTabIEP( int )),
iep, SLOT(onChangeTab( int ))); } |
在構造函數中我們構造了一個QStackedWidget實例,在initStackedWidget()中,用addWidget陸續添加了7個子控件。這裏需要注意的是:我們添加的每一個控件都是堆棧式窗口中的“一頁”了,setCurrentWidget()用於設置當前可見的“頁”。那麼,Tab選項卡又是如何實現的呢?繼承QTabWidget類。QTabWidget也是一個容器類,可以添加很多子控件。每一個控件都是一個Tab了。以File monitor這一頁爲例:
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
class FileMonitorPage
: public QTabWidget { Q_OBJECT public : FileMonitorPage(QWidget
*parent = 0); ~FileMonitorPage(){} private slots: void onChangeTab( int index); private : FileMonitorPage&
operator=( const FileMonitorPage&
obj); FileMonitorPage( const FileMonitorPage&
obj); private : //QTabWidget*
m_tabWidget; DataFileTab*
m_dataFileTab; ExecFileTab*
m_execFileTab; FileBrowserTab*
m_browserTab; }; ////////////////////////////////////////////////////////////////////////// //Tab
for data file monitoring class DataFileTab
: public QWidget { Q_OBJECT public : DataFileTab(QWidget*
parent = 0); ~DataFileTab(){} private : DataFileTab( const DataFileTab&
obj); DataFileTab&
operator=( const DataFileTab&
obj); private : CustomItemModel*
m_model; QSortFilterProxyModel*
m_proxy; QTableView*
m_view; QHBoxLayout*
m_topLayout; QLineEdit*
m_filter; QPushButton*
m_clearBtn; QPushButton*
m_exportBtn; QHBoxLayout*
m_statusLayout; QLabel*
m_status; QLineEdit*
m_status_info; QPushButton*
m_chooseDir; QPushButton*
m_startBtn; QPushButton*
m_stopBtn; QVBoxLayout*
m_mainLayout; }; ////////////////////////////////////////////////////////////////////////// //
Tab for executable file monitoring class ExecFileTab
: public QWidget { Q_OBJECT public : ExecFileTab(QWidget*
parent = 0); ~ExecFileTab(){} private : ExecFileTab( const ExecFileTab&
obj); ExecFileTab&
operator=( const ExecFileTab&
obj); private : QTableView*
m_view; CustomItemModel*
m_model; QHBoxLayout*
m_topLayout; QPushButton*
m_clearBtn; QPushButton*
m_startBtn; QPushButton*
m_stopBtn; QVBoxLayout*
m_mainLayout; }; ////////////////////////////////////////////////////////////////////////// //
Tab for file browser file monitoring class FileBrowserTab
: public QWidget { Q_OBJECT public : FileBrowserTab(QWidget*
parent = 0); ~FileBrowserTab(){} private : FileBrowserTab( const FileBrowserTab&
obj); FileBrowserTab&
operator=( const FileBrowserTab&
obj); private : QTreeView*
m_view; QFileSystemModel*
m_model; QVBoxLayout*
m_layout; }; |
在File Monitor中我們添加了三個TAB:DataFileTab,ExecFileTab,FileBrowserTab,這三個類每一個都有自己的佈局管理器和子控件。這麼說來,QTabWidget和QStackedWidget的結構是非常相似的。其實,編寫Qt程序的時候,我們要組合一個窗口其實是非常簡單的。QWidget可以通過佈局管理器嵌套任意多的子窗口,從而構建負責的UI元素。最終的效果看起來是這樣的:
小結
本文重點實現了三個功能:窗體分割(QSplitter),堆棧式窗口(QStackedWidget),Tab選項卡(QTabWidget)。通過這三個功能,一個窗口能同時展示多項內容,並按邏輯功能分類。
轉載自:http://www.cnblogs.com/csuftzzk/p/Trojan_Assessment_Platform_3.html