目标:

        

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. Android中的service

    1.service简介:service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息 ...

  2. Window Handle介绍

    HANDLE(句柄)是Windows操作系统中的一个概念.在Windows程序中,有各种各样的资源(窗口.图标.光标等),系统在创建这些资源时会为它们分配内存,并返回标示这些资源的标示号,即句柄.句柄 ...

  3. thunderbird 设置 邮件回复时内容在上方显示

    1 . 编辑->属性 2.选择当前账户,在弹出窗体的右下角 选择 管理标示 ,在弹出窗中选择编辑 3.在弹出标识设置窗体中选择 编写&地址簿 选项卡选择 在引用内容之前回复

  4. Xcode 打开playground文件的时候提示-Unable to find execution service for selected run destination

    解决办法: step 1: 关闭Xcode (快捷键cmd + q) step 2:在terminal里面运行如下语句 rm -rf ~/Library/Developer/CoreSimulator ...

  5. sklearn one_hot 操作

    1.编码 one_hot编码不再过多叙述,类似于hash的那种方法去改变数的编码方式.比如label存在与(0,1,2,3),那么一条记录的label为3,那么将编码维[0,0,0,1] 2.包: t ...

  6. 洛谷3004 [USACO10DEC]宝箱Treasure Chest

    题目:https://www.luogu.org/problemnew/show/P3004 一眼看上去就是记忆化搜索的dp.像 一双木棋 一样. 结果忘了记忆化.T了5个点. 然后加上记忆化.MLE ...

  7. TabControl控件用法图解

    1.首先创建一个MFC对话框框架,在对话框资源上从工具箱中添加上一个TabControl控件 2.根据需要修改一下属性,然后右击控件,为这个控件添加一个变量,将此控件跟一个CTabCtrl类变量绑定在 ...

  8. Svn使用遇到的错误

    1. 权限不足导致的错误

  9. Java面试(二)

    1 同步方法 VS 同步代码块: java中,每一个对象都有一把锁,线程用synchronized获取对象上的锁. 非静态同步方法:锁是类的对象的锁. 静态同步方法:锁的是类本身. 同步方法块:锁是可 ...

  10. CVE-2017-8464(震网三代)复现

    开启msf root@sch01ar:~# msfconsole 设置模块 msf > use exploit/windows/fileformat/cve_2017_8464_lnk_rce ...