- 1.QHBoxLayout和QVBoxLayout源码解析
- 1.1.源码查询
- 1.2.布局原理
- 2.动态创建窗口实例
- 2.1.界面编辑
- 2.2.动态代码
- 2.3.setStretchFactor源码
- 3.作者答疑
从官方文档查阅,该类用于构建水平布局。类源码如下所示:
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)
};
从源码上看,这两个类继承至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)
};
从头文件的结构设计上,可以得出,QVBoxLayout和QHBoxLayout是两个容器类,里面可以添加QWidget子控件,QLayout子布局和QSpacerItem子空白区域。以及设置这些子控件之间的间隙(space),哪些控件可以调整(Stretch)。
1.2.布局原理如果 QBoxLayout 的方向是Qt:: Horizontal ,那么这些框将被放置在一行中,并具有合适的大小。每个小部件(或其他框)将至少获得其最小尺寸,至多获得其最大尺寸。任何多余的空间都根据拉伸因子进行共享。 如果 QBoxLayout 的方向是Qt::Vertical,则这些框被放置在一列中,同样具有合适的大小。创建 QBoxLayout 最简单的方法是使用扩展子类,例如QHBoxLayout(用于Qt:: Horizontal框)或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.动态创建窗口实例 本文不讨论具体的算法是如何实现的,接下来讲解构建一个简单的实例,上面一个列表控件,窗口变动时比率不变,下面一个表格控件,上面的列表控件固定高度,当窗口拉动时下面的列表控件改变高度。如下图所示:
在VS2013上启动Qt Designer,如下图所示: 拖入一个垂直布局构建QVBoxLayout,如下图所示:
右键窗口界面空白处,选择布局>垂直布局,修改布局对象名称为UILayerout,然后保存即可。
在布局控件的常见选择有对齐位置,子控件间距,
//公共常数
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 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 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 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);
2.3.setStretchFactor源码
setStretchFactor修改指定子控件或者子布局是否可以调整的状态值。
bool QBoxLayout::setStretchFactor(QWidget *widget, int stretch)
{
Q_D(QBoxLayout);
if (!widget)
return false;
for (int i = 0; i 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 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 list.size()) {
QBoxLayoutItem *box = d->list.at(index);
if (box->stretch != stretch) {
box->stretch = stretch;
invalidate();
}
}
}
3.作者答疑
如有疑问,请留言。