引言

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

窗体分割

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

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

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,然后再考虑集成到父窗口中去:

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这一页为例:

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

用Qt写软件系列五:一个安全防护软件的制作(3)的更多相关文章

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

    引言 又有许久没有更新了.Qt,我心爱的Qt,为了找工作不得不抛弃一段时间,业余时间来学一学了.本来计划要写一系列关于Qt组件美化的博文,但是写了几篇之后就没坚持下去了.技术上倒是问题不大,主要是时间 ...

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

    引言 在上一篇中讲述了主窗体的创建和设计.主窗体的无边框效果.阴影效果.拖动事件处理.窗体美化等工作在前面的博客中早就涉及,因此上篇博文中并未花费过多笔墨.这一篇继续讲述工具箱(Tool Button ...

  3. 系列五AnkhSvn

    原文:系列五AnkhSvn AnkhSvn介绍 AnkhSVN是一款在VS中管理Subversion的插件,您可以在VS中轻松的提交.更新.添加文件,而不用在命令行或资源管理器中提交.而且该插件属于开 ...

  4. 用Qt写软件系列三:一个简单的系统工具(上)

    导言 继上篇<用Qt写软件系列二:QIECookieViewer>之后,有一段时间没有更新博客了.这次要写的是一个简单的系统工具,需求来自一个内部项目.功能其实很简单,就是查看当前当前系统 ...

  5. 用Qt写软件系列一:QCacheViewer(浏览器缓存查看器)

    介绍 Cache技术广泛应用于计算机行业的软硬件领域.该技术既是人们对新技术探讨的结果,也是对当前软硬件计算能力的一种妥协.在浏览器中使用cache技术,可以大幅度提高web页面的响应速度,降低数据传 ...

  6. tensorflow笔记(五)之MNIST手写识别系列二

    tensorflow笔记(五)之MNIST手写识别系列二 版权声明:本文为博主原创文章,转载请指明转载地址 http://www.cnblogs.com/fydeblog/p/7455233.html ...

  7. Qt写的截图软件包含源代码和可执行程序

    http://blog.yundiantech.com/?log=blog&id=14 Qt写的截图软件包含源代码和可执行程序 http://download.csdn.net/downloa ...

  8. <p>在我们的实际软件项目中,管理团队事实上比写代码或者实现一个客户的需求更为的有挑战性。由于编程实际上是和机器打交道,而和机器打交道,仅仅要你符合机器预定的逻辑,</p>

    在我们的实际软件项目中,管理团队事实上比写代码或者实现一个客户的需求更为的有挑战性. 由于编程实际上是和机器打交道.而和机器打交道,仅仅要你符合机器预定的逻辑, 一步步迈向解决这个问题的道路上一点都不 ...

  9. SAP ECC6安装系列五:安装后 License 的处理

    原作者博客 http://www.cnblogs.com/Michael_z/ ======================================== 我发现我确实比较懒,先和各位说声抱歉了 ...

随机推荐

  1. RCP:拖拽功能的实现 Drag and Drop

    SWT中的拖拽是使用的org.eclipse.swt.dnd. 有三个需要密切注意的类: 1.DragSource 2.DropTarget 3.Transfer DragSource封装了需要被拖拽 ...

  2. STC12C5A60S2笔记6(中断)

    1. 基本特性 1) 中断源 STC12C5A60S2共有十个中断源,每个中断源可设置4类优先级:当相同优先级下各中断优先级由高到低依次如下: 1.1)INT0(外部中断0) 中断向量地址 0003H ...

  3. dojo/aspect源码解析

    dojo/aspect模块是dojo框架中对于AOP的实现.关于AOP的详细解释请读者另行查看其它资料,这里简单复习一下AOP中的基本概念: 切面(Aspect):其实就是共有功能的实现.如日志切面. ...

  4. 《C#图解教程》读书笔记之六:接口和转换

    本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.接口那点事儿 (1)什么是接口? 一组函数成员而未实现的引用类型.只有类和结构能实现接口. (2)从ICom ...

  5. 示例篇-购物车的简单示例和自定义JS

    简介: 支持平台: Android4.0,iOS7.0,Windows 10, Windows 10 mobile 说明:主要是演示listview所在的ui和模板cell所在的ui之间数据的交互,点 ...

  6. [异常解决] MPU6050启动异常读出陀螺仪和加速度计的值全为0的解决办法

    在调试一个自己做的手环,每次用keil烧写好程序运行的蓝牙.陀螺仪都是正常的.但是掉电再上电之后蓝牙是好的.陀螺仪可以读出ID但是读出的加速度和角速度数据全为0. 下面是发生问题时main函数的前面部 ...

  7. xamarin误删vEthernet(internal Ethernet Port Windows Phone Emulator) 网络设备的处理。

    昨天一不小心误删了xamarin 开发环境下的虚拟设备网络设备.名称为:vEthernet(internal Ethernet Port Windows Phone Emulator).导致原来能正确 ...

  8. iOS给图片添加滤镜&使用openGLES动态渲染图片

    给图片增加滤镜有这两种方式: CoreImage / openGLES 下面先说明如何使用CoreImage给图片添加滤镜, 主要为以下步骤: #1.导入CIImage格式的原始图片 #2.创建CIF ...

  9. Atian inputmethod 输入法解决方案 方言与多语言多文字支持 英语汉字汉语阿拉伯文的支持 (au

    Atian inputmethod 输入法解决方案 方言与多语言多文字支持 英语汉字汉语阿拉伯文的支持 (au 1.1. Overview概论 支持母语优先的战略性产品,主要是针对不想以及不愿使用普通 ...

  10. JavaScript函数后面加不加括号的区别

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...