目标:

        

1.添加控件的函数 void QLayout::addWidget ( QWidget * w )

在这个例子里面我们重载这个函数 void addWidget ( QWidget * w, int position)

2.添加到布局里面的都是QLayoutItem。我们把QLayoutItem和position封装成一个结构体ItemWrapper。

QList <ItemWrapper *> list。 私有变量list来管理布局中控件数量。

阅读官方文档:

To make your own layout manager, implement the functions addItem(), sizeHint(), setGeometry(), itemAt() and takeAt(). You should also implement minimumSize() to ensure your layout isn't resized to zero size if there is too little space. To support children whose heights depend on their widths, implement hasHeightForWidth() and heightForWidth().

1.先考虑布局的尺寸问题(布局的长度和宽度问题)

QSize BorderLayout::sizeHint() const 返回布局的理想的长度和宽度。

QSize BorderLayout::minimumSize() const 空间不够时,布局所需的最小的长度和宽度(布局不能少于这个最小的长度和宽度)

我们设计一个 QSize BorderLayout::calculateSize(SizeType sizeType) const函数来计算

enum SizeType { MinimumSize, SizeHint }

QSize BorderLayout::sizeHint() const { return calculateSize(SizeHint ); }

QSize BorderLayout::minimumSize() const { return calculateSize(MinimumSize); }

calculateSize函数中,我们遍历布局中的每个控件,计算出理想尺寸和最小尺寸

QSize BorderLayout::calculateSize(SizeType sizeType) const
{
QSize totalSize; for(int i=; i<list.size(); i++) {
ItemWrapper *wrapper = list.at(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position;
QSize itemSize; if(sizeType == MinimumSize)
itemSize = item->minimumSize();
else
itemSize = item->sizeHint(); if(position == North || position == South || position == Central) {
totalSize.rheight() += itemSize.rheight();
} if(position == West || position == East || position == Central) {
totalSize.rwidth() += itemSize.rwidth();
}
} return totalSize;
}

2.添加控件的方法,添加控件也就是把控件添加到list中去

void QLayout::addItem ( QLayoutItem * item ) [pure virtual] 这个函数在应用程序中程序员不调用。

void addWidget ( QWidget * w, Position  position) 最常用的添加控件方法。我们这里重载该函数,添加一个参数 position

void add(QLayoutItem *item, Position position) 我们实现add函数来添加控件

void BorderLayout::addItem(QLayoutItem *i)
{
add(i, West);
} void BorderLayout::addWidget(QWidget *w, Position position)
{
add(new QWidgetItem (w), position);
} void BorderLayout::add(QLayoutItem *i, Position position)
{
list.append(new ItemWrapper(i, position));
}

3.查找和删除控件的方法

QLayoutItem * itemAt(int index) const;  返回索引下的QLayoutItem 
QLayoutItem * takeAt(int index); 删除索引下的QLayoutItem  并返回QLayoutItem的值

QLayoutItem * BorderLayout::itemAt(int index) const
{
ItemWrapper *wrapper = list.value(index);
if(wrapper)
return wrapper->item;
else
return ;
} QLayoutItem * BorderLayout::takeAt(int index)
{
if(index >= && index < list.size()) {
ItemWrapper *wrapper = list.takeAt(index);
return wrapper->item;
}
return ;
}

list中takeat函数删除索引是index的值

4.布局中控件的数量,布局的高度是否依赖其宽度,布局的延伸方向。

Qt::Orientations expandingDirections() const;
bool hasHeightForWidth() const;
int count() const;

Qt::Orientations BorderLayout::expandingDirections() const
{
return Qt::Horizontal | Qt::Vertical;
} bool BorderLayout::hasHeightForWidth() const
{
return false;
} int BorderLayout::count() const
{
return list.size();
}

5。我们现在知道有多少控件,每个控件的尺寸,整个布局的尺寸。

但是控件摆放在整个布局中那个位置,如何摆放。这里需要void setGeometry(const QRect &rect)函数。

QLayout::setGeometry(rect). 获得布局的整个矩形大小。

然后设施每个QLayoutItem的setGeometry函数。把每个控件放在指定的位置

void BorderLayout::setGeometry(const QRect &rect)
{
ItemWrapper *center = ; int northHeight = ;
int southHeight = ;
int centerHeight = ;
int westWidth = ;
int eastWidth = ; int i = ; QLayout::setGeometry(rect); for(i = ; i < list.size(); i++) {
ItemWrapper *wrapper = list.at(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position; if(position == North) {
item->setGeometry(QRect(rect.x(), northHeight, rect.width(), item->sizeHint().height()));
northHeight += item->geometry().height() + spacing();
}
else if(position == South) {
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(), rect.width(),
item->sizeHint().height()));
southHeight += item->geometry().height() + spacing(); item->setGeometry(QRect(rect.x(), rect.y()+rect.height()-southHeight+spacing(),
item->geometry().width(), item->geometry().height()));
}
else if(position == Central)
center = wrapper;
} centerHeight = rect.height() - northHeight - southHeight; for(i = ; i < list.size(); i++) {
ItemWrapper *wrapper = list.value(i);
QLayoutItem *item = wrapper->item;
Position position = wrapper->position; if(position == West) {
item->setGeometry(QRect(westWidth, northHeight, item->sizeHint().width(), centerHeight));
westWidth += item->geometry().width() + spacing();
}
else if(position == East) {
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
item->sizeHint().width(), centerHeight)); eastWidth += item->geometry().width() + spacing(); item->setGeometry(QRect(rect.width() - eastWidth + spacing(), northHeight,
item->geometry().width(), item->geometry().height()));
}
} if(center) {
center->item->setGeometry(QRect(westWidth, northHeight,
rect.width() - westWidth - eastWidth, centerHeight));
} }

效果图:

        

源代码: https://github.com/Satius/qt5/tree/master/qtbase/examples/widgets/layouts/borderlayout

2.Border Layout 自定义一个Layout来完成布局。的更多相关文章

  1. 自定义View(7)官方教程:自定义View(含onMeasure),自定义一个Layout(混合组件),重写一个现有组件

    Custom Components In this document The Basic Approach Fully Customized Components Compound Controls ...

  2. 自定义View Layout过程 (3)

    目录 目录 1. 知识基础 具体请看我写的另外一篇文章:(1)自定义View基础 - 最易懂的自定义View原理系列 2. 作用 计算View视图的位置. 即计算View的四个顶点位置:Left.To ...

  3. Customize the View Items Layout 自定义视图项目布局

    In this lesson, you will learn how to customize the default editor layout in a Detail View. For this ...

  4. 自定义一个更好用的SwipeRefreshLayout(弹力拉伸效果详解)(转载)

    转自: 自定义一个更好用的SwipeRefreshLayout(弹力拉伸效果详解) 前言 熟悉SwipeRefreshLayout的同学一定知道,SwipeRefreshLayout是android里 ...

  5. 在Dynamics CRM中自定义一个通用的查看编辑注释页面

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复162或者20151016可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 注释在CRM中的显示是比较特别, ...

  6. [WPF 自定义控件]自定义一个“传统”的 Validation.ErrorTemplate

    1. 什么是Validaion.ErrorTemplate 数据绑定模型允许您将与您Binding的对象相关联ValidationRules. 如果用户输入的值无效,你可能希望在应用程序 用户界面 ( ...

  7. Android The layout "activity_main" in layout has no declaration in the base layout folder

    报错: The layout "activity_main" in layout has no declaration in the base layout folder; thi ...

  8. SpringMVC 自定义一个拦截器

    自定义一个拦截器方法,实现HandlerInterceptor方法 public class FirstInterceptor implements HandlerInterceptor{ /** * ...

  9. jQuery Validate 表单验证插件----自定义一个验证方法

    一.下载依赖包 网盘下载:https://yunpan.cn/cryvgGGAQ3DSW  访问密码 f224 二.引入依赖包 <script src="../../scripts/j ...

随机推荐

  1. Dawn 简单使用

     1. install npm install dawn -g 2. create project # 1. Create & Initialize $ dn init -t front # ...

  2. js插件大全 jquery插件大全

    CocoaUI - 一个强大的 iOS UI 框架 http://www.cocoaui.com/ tab,slider,轮播不错的说 http://www.superslide2.com/index ...

  3. delphi 2010安装unidac

    UniDAC是一个功能强大的非可视化跨数据库的数据访问组件,可用于Delphi,Delphi for .NET,C++Builder,and Lazarus (Free Pascal).它提供了对流行 ...

  4. MFC命令消息的路由

    下面,我们以Menu这个程序为例,来看看 菜单命令消息路由的具体过程:当单击某个菜单项时,最先接收到这个菜单命令消息的是框架类.框架类将把接收到的这个消息交给它的子窗口.即视类,由视类首先进行处理.视 ...

  5. VC++中如何让RadioButton分组,并且互斥

    首先让两个RadioButton的Group属性为False. 将两个RadioButton放入一个GroupBox里面,即可如果分成多个组,则将多组Radio分别用GroupBox框起来,并将每组的 ...

  6. 【转】windows下mysql5.1忘记root密码解决方法

    步骤如下:1.停止mysql服务(以管理员身份,在cmd命令行下运行) net stop mysql D:\>net stop mysql MySQL 服务正在停止. MySQL 服务已成功停止 ...

  7. SERDES高速系统(一)

    在目前主流厂商的高端FPGA 中都集成了SERDES(串并收发单元)硬核,如Altera的Stratix IV GX器件族内部集成的SERDES单通道支持600Mbit/s到8.5Gbit/s数据熟率 ...

  8. 安全测试之session,cookie

    session session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息.•但程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这 ...

  9. Linux - 对文件和目录的权限管理

    对文件的权限管理 ls -l,也可以用 ll 命令查看文件权限的相关信息 第一列“-rw-r--r--.”为权限信息,权限信息的最后一个点表示为在安全环境下创建的 第二列“1”为硬链接数,第三列“ro ...

  10. windows 10 服务组件安装出现0x80070422错误解决方法

    问题描述:   windows 10通过控制面板->程序->启用或关闭Windows 功能安装Windows服务或组件时,出现0x80070422错误,提示服务禁止或未启用 问题产生原因: ...