用Qt寫軟件系列五:一個安全防護軟件的製作(3)

引言

       上一篇中講述了工具箱的添加。通過一個水平佈局管理器,我們將一系列的工具按鈕組合到了一起,完成了工具箱的編寫。本文在前面的基礎上實現窗體分割效果、堆棧式窗口以及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

發佈了2 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章