前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用Qt写软件系列五:一个安全防护软件的制作(3)

用Qt写软件系列五:一个安全防护软件的制作(3)

作者头像
24K纯开源
发布2018-01-18 10:29:35
1.7K0
发布2018-01-18 10:29:35
举报
文章被收录于专栏:24K纯开源24K纯开源

引言

       上一篇中讲述了工具箱的添加。通过一个水平布局管理器,我们将一系列的工具按钮组合到了一起,完成了工具箱的编写。本文在前面的基础上实现窗体分割效果、堆栈式窗口以及Tab选项卡。

窗体分割

       窗体分割是一个常见的功能,尤其在一些IDE中用的非常广泛。主要是窗体分割能够在视觉上对程序功能进行分组分类,在保证界面美观的同时还能保证内容井井有条,何乐而不为呢?Qt中提供了一个用于分割窗体的类:QSplitter。这个类的使用也非常简单,准备好需要分割的窗口,设置好分割方向和比例即可。不过值得注意的是,QSplitter是一个窗口管理类,在没有添加子控件是看不到QSplitter效果的。这一点在Qt Designer中也可以验证。

      在我们的项目中,我们增加一个QSplitter类成员,并在主窗口的构造函数中添加如下代码:

代码语言:javascript
复制
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,然后再考虑集成到父窗口中去:

代码语言:javascript
复制
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这一页为例:

代码语言:javascript
复制
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)。通过这三个功能,一个窗口能同时展示多项内容,并按逻辑功能分类。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-06-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 窗体分割
  • 堆栈式窗口及Tab选项卡
  • 小结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档