当前位置:   article > 正文

Qt-水平垂直动态布局-实用解析-QHBoxLayout-QVBoxLayout

qvboxlayout


  Qt是一个具有强大生命力的C++开发套件集合,可以非常迅速的按照客户需求构建对应的软件产品,本文针对QHBoxLayout和QVBoxLayout两个类来讲解,如何采用代码来动态构建窗口界面。

1.QHBoxLayout和QVBoxLayout源码解析

1.1.源码查询

  从官方文档查阅,该类用于构建水平布局。类源码如下所示:

class Q_WIDGETS_EXPORT QHBoxLayout : public QBoxLayout
{
    Q_OBJECT
public:
    QHBoxLayout();
    explicit QHBoxLayout(QWidget *parent);
    ~QHBoxLayout();


private:
    Q_DISABLE_COPY(QHBoxLayout)
};

class Q_WIDGETS_EXPORT QVBoxLayout : public QBoxLayout
{
    Q_OBJECT
public:
    QVBoxLayout();
    explicit QVBoxLayout(QWidget *parent);
    ~QVBoxLayout();


private:
    Q_DISABLE_COPY(QVBoxLayout)
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

  从源码上看,这两个类继承至QBoxLayout,再查看一下QBoxLayout的源码,如下所示:

class Q_WIDGETS_EXPORT QBoxLayout : public QLayout
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QBoxLayout)
public:
    enum Direction { LeftToRight, RightToLeft, TopToBottom, BottomToTop,
                     Down = TopToBottom, Up = BottomToTop };

    explicit QBoxLayout(Direction, QWidget *parent = Q_NULLPTR);

    ~QBoxLayout();

    Direction direction() const;
    void setDirection(Direction);

    void addSpacing(int size);
    void addStretch(int stretch = 0);
    void addSpacerItem(QSpacerItem *spacerItem);
    void addWidget(QWidget *, int stretch = 0, Qt::Alignment alignment = Qt::Alignment());
    void addLayout(QLayout *layout, int stretch = 0);
    void addStrut(int);
    void addItem(QLayoutItem *) Q_DECL_OVERRIDE;

    void insertSpacing(int index, int size);
    void insertStretch(int index, int stretch = 0);
    void insertSpacerItem(int index, QSpacerItem *spacerItem);
    void insertWidget(int index, QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment());
    void insertLayout(int index, QLayout *layout, int stretch = 0);
    void insertItem(int index, QLayoutItem *);

    int spacing() const;
    void setSpacing(int spacing);

    bool setStretchFactor(QWidget *w, int stretch);
    bool setStretchFactor(QLayout *l, int stretch);
    void setStretch(int index, int stretch);
    int stretch(int index) const;

    QSize sizeHint() const Q_DECL_OVERRIDE;
    QSize minimumSize() const Q_DECL_OVERRIDE;
    QSize maximumSize() const Q_DECL_OVERRIDE;

    bool hasHeightForWidth() const Q_DECL_OVERRIDE;
    int heightForWidth(int) const Q_DECL_OVERRIDE;
    int minimumHeightForWidth(int) const Q_DECL_OVERRIDE;

    Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
    void invalidate() Q_DECL_OVERRIDE;
    QLayoutItem *itemAt(int) const Q_DECL_OVERRIDE;
    QLayoutItem *takeAt(int) Q_DECL_OVERRIDE;
    int count() const Q_DECL_OVERRIDE;
    void setGeometry(const QRect&) Q_DECL_OVERRIDE;

private:
    Q_DISABLE_COPY(QBoxLayout)
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

  从头文件的结构设计上,可以得出,QVBoxLayout和QHBoxLayout是两个容器类,里面可以添加QWidget子控件,QLayout子布局和QSpacerItem子空白区域。以及设置这些子控件之间的间隙(space),哪些控件可以调整(Stretch)。

1.2.布局原理

  如果 QBoxLayout 的方向是Qt:: Horizo​​ntal ,那么这些框将被放置在一行中,并具有合适的大小。每个小部件(或其他框)将至少获得其最小尺寸,至多获得其最大尺寸。任何多余的空间都根据拉伸因子进行共享。
  如果 QBoxLayout 的方向是Qt::Vertical,则这些框被放置在一列中,同样具有合适的大小。创建 QBoxLayout 最简单的方法是使用扩展子类,例如QHBoxLayout(用于Qt:: Horizo​​ntal框)或QVBoxLayout(用于Qt::Vertical框)。您也可以直接使用 QBoxLayout 构造函数,将其方向指定为LeftToRight、RightToLeft、TopToBottom或BottomToTop。如果 QBoxLayout 不是顶级布局(即它没有管理所有小部件的区域和子项),则必须先将其添加到其父布局中,然后才能对其进行任何操作。添加布局的常规方法是调用 parentLayout-> addLayout ()。

  完成此操作后,您可以使用以下四个函数之一将框添加到 QBoxLayout:

addWidget () 将一个小部件添加到 QBoxLayout 并设置小部件的拉伸因子。(拉伸因子沿着方框行。)
addSpacing () 创建一个空框;这是您用来创建漂亮而宽敞的对话框的功能之一。有关设置边距的方法,请参见下文。
addStretch () 创建一个空的、可伸缩的盒子。
addLayout () 将包含另一个QLayout的框添加到行并设置该布局的拉伸因子。
使用insertWidget ()、insertSpacing ()、insertStretch () 或insertLayout () 在布局中的指定位置插入一个框。

  QBoxLayout 还包括两个边距宽度:

setContentsMargins () 设置小部件每一侧的外边框的宽度。这是沿 QBoxLayout 的四个边的每个保留空间的宽度。
setSpacing () 设置相邻框之间的宽度。(您可以使用addSpacing () 在特定位置获得更多空间。)
边距默认值由样式提供。大多数 Qt 样式指定的默认边距是 9 用于子窗口小部件和 11 用于窗口。间距默认与顶级布局的边距宽度相同,或与父布局相同。

  要从布局中删除小部件,请调用removeWidget ()。在小部件上调用QWidget::hide () 也有效地从布局中删除小部件,直到调用QWidget::show ()。

2.动态创建窗口实例

  本文不讨论具体的算法是如何实现的,接下来讲解构建一个简单的实例,上面一个列表控件,窗口变动时比率不变,下面一个表格控件,上面的列表控件固定高度,当窗口拉动时下面的列表控件改变高度。如下图所示:
在这里插入图片描述

2.1.界面编辑

  在VS2013上启动Qt Designer,如下图所示:
在这里插入图片描述
  拖入一个垂直布局构建QVBoxLayout,如下图所示:
在这里插入图片描述  右键窗口界面空白处,选择布局>垂直布局,修改布局对象名称为UILayerout,然后保存即可。
在这里插入图片描述

2.2.动态代码

  在布局控件的常见选择有对齐位置,子控件间距,

	//公共常数
	int item_space = 10;
	int img_w = 200;

	QHBoxLayout* pLayoutHeader1 = new QHBoxLayout();//水平游戏选择
	pLayoutHeader1->setAlignment(Qt::AlignTop);
	pLayoutHeader1->setContentsMargins(0,0,0,0);
	pLayoutHeader1->setSpacing(0);

	QHBoxLayout* pLayoutHeader2 = new QHBoxLayout();//水平游戏选择
	pLayoutHeader2->setAlignment(Qt::AlignHCenter);
	pLayoutHeader2->setContentsMargins(0, 0, 0, 0);
	pLayoutHeader2->setSpacing(0);

	QHBoxLayout* pLayoutBody = new QHBoxLayout();//垂直游戏选择
	pLayoutBody->setAlignment(Qt::AlignHCenter);
	pLayoutBody->setContentsMargins(0, 0, 0, 0);
	pLayoutBody->setSpacing(0);

	QListWidget* pHoriGameList1 = new QListWidget;
	pHoriGameList1->setIconSize(QSize(img_w, img_w));
	pHoriGameList1->setResizeMode(QListView::Adjust);
	pHoriGameList1->setViewMode(QListView::ListMode);   //设置QListWidget的显示模式
	pHoriGameList1->setMovement(QListView::Static);     //设置QListWidget中的单元项不可被拖动
	pHoriGameList1->setSpacing(item_space);
	pHoriGameList1->setFixedHeight(260);
	pHoriGameList1->setFlow(QListView::LeftToRight);
	pHoriGameList1->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隐藏滚动条
	pHoriGameList1->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隐藏滚动条
	/* 设置为像素滚动 */
	pHoriGameList1->setHorizontalScrollMode(QListWidget::ScrollPerPixel);
	/* 设置鼠标左键拖动 */
	QScroller::grabGesture(pHoriGameList1, QScroller::LeftMouseButtonGesture);
	pHoriGameList1->setStyleSheet("background-color:rgba(244,244,244,180);border:0px;");//设置列表控件背景颜色
	//加载图像
	int sizec[3] = {-60,0,0};
	for (int nIndex = 0; nIndex < 11; ++nIndex)
	{
		QDir dir;
		QString strPath = QString::fromLocal8Bit("2077.jpg");
		QString path = dir.absoluteFilePath(strPath);
		QPixmap objPixmap(path);
		int dstw = img_w;
		if (nIndex!=5){
			dstw = dstw - 60;
		}
		QListWidgetItem *pItem = new QListWidgetItem(QIcon(objPixmap.scaled(QSize(dstw, dstw))), "");
		pItem->setSizeHint(QSize(dstw, dstw));
		pHoriGameList1->insertItem(nIndex, pItem);
	}
	pLayoutHeader1->addWidget(pHoriGameList1);

	QListWidget* pHoriGameList2 = new QListWidget;
	pHoriGameList2->setIconSize(QSize(img_w, img_w));
	pHoriGameList2->setResizeMode(QListView::Adjust);
	pHoriGameList2->setViewMode(QListView::ListMode);   //设置QListWidget的显示模式
	pHoriGameList2->setMovement(QListView::Static);     //设置QListWidget中的单元项不可被拖动
	pHoriGameList2->setSpacing(item_space);
	pHoriGameList2->setFixedHeight(260);
	pHoriGameList2->setFlow(QListView::LeftToRight);
	pHoriGameList2->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隐藏滚动条
	pHoriGameList2->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隐藏滚动条
	/* 设置为像素滚动 */
	pHoriGameList2->setHorizontalScrollMode(QListWidget::ScrollPerPixel);
	/* 设置鼠标左键拖动 */
	QScroller::grabGesture(pHoriGameList2, QScroller::LeftMouseButtonGesture);
	pHoriGameList2->setStyleSheet("background-color:rgba(244,244,244,180);border:0px;");//设置列表控件背景颜色
	//加载图像
	for (int nIndex = 0; nIndex < 11; ++nIndex)
	{
		QDir dir;
		QString strPath = QString::fromLocal8Bit("2077.jpg");
		QString path = dir.absoluteFilePath(strPath);
		QPixmap objPixmap(path);
		int dstw = img_w;
		if (nIndex != 5){
			dstw = dstw - 60;
		}
		QListWidgetItem *pItem = new QListWidgetItem(QIcon(objPixmap.scaled(QSize(dstw, dstw))), "");
		pItem->setSizeHint(QSize(dstw, dstw));
		pHoriGameList2->insertItem(nIndex, pItem);
	}
	pLayoutHeader2->addWidget(pHoriGameList2);

	QListWidget* pHoriGameTable = new QListWidget;
	pHoriGameTable->setIconSize(QSize(img_w, img_w));
	pHoriGameTable->setResizeMode(QListView::Adjust);
	pHoriGameTable->setViewMode(QListView::IconMode);   //设置QListWidget的显示模式
	pHoriGameTable->setMovement(QListView::Static);     //设置QListWidget中的单元项不可被拖动
	pHoriGameTable->setSpacing(item_space);
	pHoriGameTable->setFixedWidth(item_space * 6 + img_w*5+6);
	pHoriGameTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	pHoriGameTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	/* 设置为像素滚动 */
	pHoriGameTable->setHorizontalScrollMode(QListWidget::ScrollPerPixel);
	/* 设置鼠标左键拖动 */
	//QScroller::grabGesture(pHoriGameTable, QScroller::LeftMouseButtonGesture);
	pHoriGameTable->setStyleSheet("background-color:rgba(244,244,244,0);");

	//加载图像
	for (int nIndex = 0; nIndex < 30; ++nIndex)
	{
		QDir dir;
		QString strPath = QString::fromLocal8Bit("2077.jpg");
		QString path = dir.absoluteFilePath(strPath);
		QPixmap objPixmap(path);
		QListWidgetItem *pItem = new QListWidgetItem(QIcon(objPixmap.scaled(QSize(200, 200))), "animal");
		pItem->setSizeHint(QSize(img_w, img_w));
		pHoriGameTable->insertItem(nIndex, pItem);
	}
	pLayoutBody->addWidget(pHoriGameTable);

	ui.UILayerout->addLayout(pLayoutHeader1);//添加布局构件
	ui.UILayerout->addLayout(pLayoutHeader2);//添加布局构件
	ui.UILayerout->addLayout(pLayoutBody);//添加布局构件
	//ui.UILayerout->setStretch(0, 1);//设置第1个构件可以改变比率
	//ui.UILayerout->setStretch(1, 1);//设置第2个构件可以改变比率
	//ui.UILayerout->setStretch(2, 1);//设置第3个构件可以改变比率
	//ui.UILayerout->setStretchFactor(pLayoutHeader1, 0);
	//ui.UILayerout->setStretchFactor(pLayoutHeader2, 0);
	ui.UILayerout->setStretchFactor(pLayoutBody, 1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121

2.3.setStretchFactor源码

  setStretchFactor修改指定子控件或者子布局是否可以调整的状态值。

bool QBoxLayout::setStretchFactor(QWidget *widget, int stretch)
{
    Q_D(QBoxLayout);
    if (!widget)
        return false;
    for (int i = 0; i < d->list.size(); ++i) {
        QBoxLayoutItem *box = d->list.at(i);
        if (box->item->widget() == widget) {
            box->stretch = stretch;
            invalidate();
            return true;
        }
    }
    return false;
}

/*!
    \overload

    Sets the stretch factor for the layout \a layout to \a stretch and
    returns \c true if \a layout is found in this layout (not including
    child layouts); otherwise returns \c false.
*/
bool QBoxLayout::setStretchFactor(QLayout *layout, int stretch)
{
    Q_D(QBoxLayout);
    for (int i = 0; i < d->list.size(); ++i) {
        QBoxLayoutItem *box = d->list.at(i);
        if (box->item->layout() == layout) {
            if (box->stretch != stretch) {
                box->stretch = stretch;
                invalidate();
            }
            return true;
        }
    }
    return false;
}

/*!
    Sets the stretch factor at position \a index. to \a stretch.

    \since 4.5
*/

void QBoxLayout::setStretch(int index, int stretch)
{
    Q_D(QBoxLayout);
    if (index >= 0 && index < d->list.size()) {
        QBoxLayoutItem *box = d->list.at(index);
        if (box->stretch != stretch) {
            box->stretch = stretch;
            invalidate();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

3.作者答疑


  如有疑问,请留言。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号