Qt之自定义布局管理器(QFlowLayout)

简述

QFlowLayout,顾名思义-流布局,实现了处理不同窗口大小的布局。根据应用窗口的宽度来进行控件放置的变化。

具体实现要求不再赘述,请参考前两节内容。

  • 简述
  • 实现
    • 效果
    • 源码

实现

QFlowLayout主要采用QLayout和QWidgetItem实现,而窗口使用了QWidget和QPushButton。

效果

源码

QFlowLayout.h

#ifndef QFLOWLAYOUT_H
#define QFLOWLAYOUT_H

#include <QLayout>
#include <QRect>
#include <QStyle>

class QFlowLayout : public QLayout
{
public:
    explicit QFlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
    explicit QFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
    ~QFlowLayout();

    void addItem(QLayoutItem *item) Q_DECL_OVERRIDE;
    int horizontalSpacing() const;
    int verticalSpacing() const;
    Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
    bool hasHeightForWidth() const Q_DECL_OVERRIDE;
    int heightForWidth(int) const Q_DECL_OVERRIDE;
    int count() const Q_DECL_OVERRIDE;
    QLayoutItem *itemAt(int index) const Q_DECL_OVERRIDE;
    QSize minimumSize() const Q_DECL_OVERRIDE;
    void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
    QSize sizeHint() const Q_DECL_OVERRIDE;
    QLayoutItem *takeAt(int index) Q_DECL_OVERRIDE;

private:
    int doLayout(const QRect &rect, bool testOnly) const;
    int smartSpacing(QStyle::PixelMetric pm) const;

private:
    QList<QLayoutItem *> itemList;
    int m_hSpace;
    int m_vSpace;
};

#endif // QFLOWLAYOUT_H

QFlowLayout.cpp

#include <QWidget>
#include "QFlowLayout.h"

QFlowLayout::QFlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
    : QLayout(parent),
      m_hSpace(hSpacing),
      m_vSpace(vSpacing)
{
    setContentsMargins(margin, margin, margin, margin);
}

QFlowLayout::QFlowLayout(int margin, int hSpacing, int vSpacing)
    : m_hSpace(hSpacing),
      m_vSpace(vSpacing)
{
    setContentsMargins(margin, margin, margin, margin);
}

QFlowLayout::~QFlowLayout()
{
    QLayoutItem *item;
    while ((item = takeAt(0)))
        delete item;
}

void QFlowLayout::addItem(QLayoutItem *item)
{
    itemList.append(item);
}

int QFlowLayout::horizontalSpacing() const
{
    if (m_hSpace >= 0) {
        return m_hSpace;
    } else {
        return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
    }
}

int QFlowLayout::verticalSpacing() const
{
    if (m_vSpace >= 0) {
        return m_vSpace;
    } else {
        return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
    }
}

int QFlowLayout::count() const
{
    return itemList.size();
}

QLayoutItem *QFlowLayout::itemAt(int index) const
{
    return itemList.value(index);
}

QLayoutItem *QFlowLayout::takeAt(int index)
{
    if (index >= 0 && index < itemList.size())
        return itemList.takeAt(index);
    else
        return 0;
}

Qt::Orientations QFlowLayout::expandingDirections() const
{
    return 0;
}

bool QFlowLayout::hasHeightForWidth() const
{
    return true;
}

int QFlowLayout::heightForWidth(int width) const
{
    int height = doLayout(QRect(0, 0, width, 0), true);
    return height;
}

void QFlowLayout::setGeometry(const QRect &rect)
{
    QLayout::setGeometry(rect);
    doLayout(rect, false);
}

QSize QFlowLayout::sizeHint() const
{
    return minimumSize();
}

QSize QFlowLayout::minimumSize() const
{
    QSize size;
    QLayoutItem *item;
    foreach (item, itemList)
        size = size.expandedTo(item->minimumSize());

    size += QSize(2*margin(), 2*margin());
    return size;
}

int QFlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
    int left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);
    QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
    int x = effectiveRect.x();
    int y = effectiveRect.y();
    int lineHeight = 0;

    QLayoutItem *item;
    foreach (item, itemList) {
        QWidget *wid = item->widget();
        int spaceX = horizontalSpacing();
        if (spaceX == -1)
            spaceX = wid->style()->layoutSpacing(
                        QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
        int spaceY = verticalSpacing();
        if (spaceY == -1)
            spaceY = wid->style()->layoutSpacing(
                        QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);

        int nextX = x + item->sizeHint().width() + spaceX;
        if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
            x = effectiveRect.x();
            y = y + lineHeight + spaceY;
            nextX = x + item->sizeHint().width() + spaceX;
            lineHeight = 0;
        }

        if (!testOnly)
            item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));

        x = nextX;
        lineHeight = qMax(lineHeight, item->sizeHint().height());
    }
    return y + lineHeight - rect.y() + bottom;
}

int QFlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{
    QObject *parent = this->parent();
    if (!parent) {
        return -1;
    } else if (parent->isWidgetType()) {
        QWidget *pw = static_cast<QWidget *>(parent);
        return pw->style()->pixelMetric(pm, 0, pw);
    } else {
        return static_cast<QLayout *>(parent)->spacing();
    }
}
时间: 2024-09-29 22:04:15

Qt之自定义布局管理器(QFlowLayout)的相关文章

Qt之自定义布局管理器(QCardLayout)

简述 手动布局另一种方法是通过继承QLayout类编写自己的布局管理器. 下面我们详细来举一个例子-QCardLayout.它由同名的Java布局管理器启发而来.也被称之为卡片布局,每个项目偏移QLayout::spacing(). 简述 定义 实现 效果 源码 定义 编写自己的布局,必须定义如下: 一种存储布局处理项目的数据结构,每个项目都是一个QLayoutItem,本例使用QList. addItem() 如何添加项目布局. setGeometry() 如何控制布局. sizeHint()

Qt之自定义布局管理器(QBorderLayout)

简述 QBorderLayout,顾名思义-边框布局,实现了排列子控件包围中央区域的布局. 具体实现要求不再赘述,请参考前几节内容. 简述 实现 效果 源码 使用 实现 QBorderLayout主要采用QLayout和QWidgetItem实现,而窗口使用了QWidget,中央窗体使用QTextBrowser,四周以QLabel排列. 效果 源码 QBorderLayout.h #ifndef QBORDERLAYOUT_H #define QBORDERLAYOUT_H #include <

Qt之布局管理器

简述 Qt的布局系统提供了一个简单的和强有力的方式,来自动排列窗口子控件布局. 所有QWidget子类可以使用布局来管理他们的子控件.QWidget::setLayout()函数可以为一个控件布局.当通过这种方式布局以后,它负责以下任务: 布置子控件. 最高层窗口可感知的默认大小. 最高层窗口可感知的最小大小. 调整大小的处理. 当内容改变的时候自动更新: 字体大小.文本或者子控件的其它内容. 隐藏或者显示子控件. 移除一些子控件. 简述 Qt的布局类 水平垂直网格表单布局 代码布局 为布局添加

AndroidUI设计之 布局管理器 - 详细解析布局实现

写完博客的总结 : 以前没有弄清楚的概念清晰化 父容器与本容器属性 : android_layout...属性是本容器的属性, 定义在这个布局管理器的LayoutParams内部类中, 每个布局管理器都有一个LayoutParams内部类, android:... 是父容器用来控制子组件的属性. 如android:layout_gravity 是控制组件本身的对齐方式, android:gravity是控制本容器子组件的对齐方式; . 作者 :万境绝尘  转载请注明出处 : http://blo

马士兵 J2SE 第11章 GUI编程 GUI初步和布局管理器

/* 范例名称:Frame 应用举例 * 源文件名称:TestFrame.java * 要 点:Frame组件的创建及显示设置 */ import java.awt.*; public class TestFrame { public static void main( String args[]) { Frame f = new Frame("My First Test"); f.setLocation(300, 300); f.setSize( 170,100); f.setBac

离开Java布局管理器

Java语言中提供的布局管理器种类有:边界式布局.卡片式布局.流式布局和网格式布局等,各有不同的特点,可根据实际需要选用:但有最大自由设计空间的是"无布局管理器"--即不使用任何布局格式,而通过手工方式添加组件到页面布局的绝对位置上.本例中使用的便是"无布局管理器". 在使用"无布局管理器"时,首先要作出声明,即: setLayout(null); 然后用reshape()方法指定组件的具体位置和尺寸, 基本语句如下所示: Label label

Java布局管理器在现实工程中的应用

内容简介:Java的出现是编程艺术和计算环境改变的结果,是Intenet发展的产物同时也是推动Internet发展的动力.但是Java作为新的编程语言,有许多不与以往编程语言不同的地方.布局管理就是其中的一个,本文的目的在于介绍如何将布局管理应用于现实工程中,而不是作为学习布局管理的参考资料. 布局管理对于众多编程人员来说是一个比较新的概念,因为以前使用的多种编程工具已经很好地解决了这个问题,根本就不用程序员自己考虑控件的布局问题,只需要简单的拖拽就可.但是接触到java之后,尤其是因为使用el

Java布局管理器的具体实现

我们都知道,java的GUI界面定义是由awt类和swing类来完成的.它在布局管 理上面采用了容器和布局管理分离的方案.也就是说,容器只管将其他小件放入 其中,而不管这些小件是如何放置的.对于布局的管理交给专门的布局管理器类 (LayoutManager)来完成. 其实,java在GUI方面应该是并不成功的.Awt类和swing类的结构非常复杂, 加上充斥其间的子类继承和接口实现,使得要想掌握这两个类非常困难.这也是 很多的java程序员抱怨的事情,但GUI已经成了程序发展的方向,所以这里我们

Java 的布局管理器GridBagLayout的使用方法(转)

  GridBagLayout是java里面最重要的布局管理器之一,可以做出很复杂的布局,可以说GridBagLayout是必须要学好的的, GridBagLayout 类是一个灵活的布局管理器,它不要求组件的大小相同便可以将组件垂直.水平或沿它们的基线对齐. 每个 GridBagLayout 对象维持一个动态的矩形单元网格,每个组件占用一个或多个这样的单元,该单元被称为显示区域. 下面就通过一个记事本案例去说明GridBagLayout的使用方法.   分析: 带有箭头的说明可以拉伸的. 4占