用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值