QT基础与实例应用目录
QLayout
是由具体类
QBoxLayout
、
QGridLayout
、
QFormLayout
和
QStackedLayout
继承的抽象基类。
对于
QLayout
子类或
QMainWindow
的用户,很少需要使用
QLayout
提供的基本功能,例如
setSizeConstraint()
或
setMenuBar()
。Qt 布局系统提供了一种简单而强大的方法,可以在控件内自动排列子控件,以确保它们充分利用可用空间。Qt 包含一组布局管理类,用于描述控件在应用程序用户界面中的布局方式。 当控件的可用空间发生变化时,这些布局会自动定位和调整控件的大小,确保它们的排列一致并且用户界面作为一个整体仍然可用。
所有
QWidget
子类都可以使用布局来管理它们的子类。
QWidget::setLayout()
函数可以为一个控件布局。 当以这种方式在
widget
上设置布局时,它负责以下任务:
-
布置子控件。
-
最高层窗口可感知的默认大小。
-
最高层窗口可感知的最小大小。
-
调整大小的处理。
-
当内容改变的时候自动更新:
-
字体大小、文本或者子控件的其它内容。
-
隐藏或者显示子控件。
-
移除一些子控件。
Qt的布局类使用手写的C++代码设计的,所以很容易理解和使用。
使用Qt Designer创建的界面生成的代码也使用了布局类。涉及用户界面开发时,Qt Designer非常有用,因为它避免了编译、链接、运行这样一个循环。
类
|
描述
|
QBoxLayout
|
水平或垂直排列子控件
|
QButtonGroup
|
用于组织按钮控件组的容器
|
QFormLayout
|
管理输入控件和其相关的标签
|
QGraphicsAnchor
|
表示在QGraphicsAnchorLayout中两个项目之间的锚
|
QGraphicsAnchorLayout
|
可以在图形视图中将控件锚定在一起的布局
|
QGridLayout
|
网格布局
|
QGroupBox
|
带标题的分组框
|
QHBoxLayout
|
水平排列控件
|
QLayout
|
几何管理器的基类
|
QLayoutItem
|
QLayout 操作的抽象item
|
QSizePolicy
|
描述水平和垂直大小调整策略的布局属性
|
QSpacerItem
|
布局中的空间隔
|
QStackedLayout
|
堆栈布局,同一时间只有一个控件可见
|
QStackedWidget
|
堆栈窗体,同一时间只有一个控件可见
|
QVBoxLayout
|
垂直排列控件
|
QWidgetItem
|
表示一个控件的布局item
|
为控件提供良好布局的最简单方法是使用内置布局管理器:
QHBoxLayout
、
QVBoxLayout
、
QGridLayout
和
QFormLayout
。这些类从
QLayout
继承,而
QLayout
又从
QObject
(而不是
QWidget
)派生。他们负责一组控件的几何管理。 要创建更复杂的布局,可以将布局管理器相互嵌套。
-
QHBoxLayout
:从左到右在水平行中布置控件。
-
QFormLayout
:把控件按照标签-输入框的形式排列在两列。
当使用布局的时候,构建子控件的时候不需要指定parent,布局将会自动的指定parent(使用
QWidget::setParent()
),使它们成为安装了该布局的界面的子控件。
注意:布局中的控件是安装了该布局的控件的子控件,而非布局自身的,控件只能以控件作为parent,不能是布局。也可以在布局中使用
addLayout()
来嵌套布局,内部的布局就会变成它的子布局。
将控件添加到一个布局时,布局过程如下:
-
所有控件最初将根据它们的
QWidget::sizePolicy()
和
QWidget::sizeHint()
分配一定数量的空间。
-
如果任何控件设置了拉伸系数,并且其值大于零,那么它们将按其拉伸因子的比例分配空间(如下
伸展因素
所述)。
-
如果任何控件的拉伸系数设置为零,它们只会在没有其他控件需要空间的情况下获得更多空间。 其中,空间首先分配给具有扩展大小策略的控件。
-
任何控件被分配的空间的大小如果小于它们的最小大小(如果未指定最小尺寸,则为最小尺寸提示),它们就会被按它们所需要的最小大小分配空间。(如果控件的伸展因素是它们的决定因素,它们不必有最小大小或者最小大小的提示。)
-
任何控件被分配的空间的大小如果大于它们的最大大小,它们就会被按它们所需要的最大大小分配空间。(如果控件的伸展因素是它们的决定因素,它们不必有最大大小。)
控件通常是在没有伸展因素设置的情况下被生成的。当它们被布置到一个布局中时,控件会被根据它们的
QWidget::sizePolicy()
或者它们的最小大小的提示中大的那一个分配给整个空间的一部分。伸展因素是用来根据控件互相的比例来改变它们所被分配的空间。
如果你使用一个
QHBoxLayout
来布置没有伸展参数设置的三个控件,我们就会得到像下面这样的布局:
如果我们给每个控件设置一个伸展因素,它们就会被按比例布置(但是不能小于最小大小的提示):
当您创建自己的控件类时,还应该传达其布局属性。如果这个控件有一个QLayout,这样的话就已经被处理了。 如果控件没有任何子控件,或使用自定义布局,可以使用以下方法更改控件的行为:
-
重新实现
QWidget::sizeHint()
以返回控件的首选大小。
-
重新实现
QWidget::minimumSizeHint()
以返回控件可以具有的最小尺寸。
-
调用
QWidget::setSizePolicy()
来指定控件的空间要求。
只要大小提示、最小大小提示或者大小策略发生改变,都要调用
QWidget::updateGeometry()
。这将导致布局重新计算。 多次连续调用
QWidget::updateGeometry()
只会导致一次布局重新计算。
如果您的控件的首选高度取决于其实际宽度(例如,带有自动断字的标签),在控件的大小策略中设置
height-for-width
标志并重新实现
QWidget::heightForWidth()
。即使你实现了
heightForWidth()
,提供一个好的
sizeHint()
仍然是必需的。
如果要生成一种特殊的布局,也可以按上面的描述来生成一个自定义控件。重新实现
QWidget::resizeEvent()
来计算所需要分配的大小并且给每一个子控件调用
setGeometry()
。当布局需要重新计算的时候,控件会得到一个类型是
QEvent::LayoutRequest
的事件。重新实现
QWidget::event()
来处理
QEvent::LayoutRequest
事件。
手动布局的替代方法是通过继承
QLayout
来编写自己的布局管理器。 具体操作介绍见后续文章
QT提供了
QHBoxLayout
、
QVBoxLayout
、
QGridLayout
类等基本布局管理器,分别是水平排列布局、垂直排列布局、网格排列布局。
QHBoxLayout
、
QVBoxLayout
继承自
QBoxLayout
,
QBoxLayout
、
QGridLayout
继承自
QLayout
布局中常用的方法有
addWidget()
和
addLayout()
.
addWidget()
方法用于加入需要布局的控件
void addWidget
QWidget *widget,
int fromRow,
int fromColumn,
int rowSpan,
int columnSpan,
Qt::Alignment alignment = Qt::Alignment()
addLayout()
方法用于加入子布局
void addLayout
QLayout *layout,
int row,
int column,
int rowSpan,
int columnSpan,
Qt::Alignment alignment = Qt::Alignment()
Demo介绍了如何使用基本布局管理,如QHBoxLayout
QVBoxLayout
QGridLayout
类。Demo用到了四个布局管理器,分别是 LeftLayout
(使用QGridLayout
),RightLayout
(使用QVBoxLayout
),BottomLayout
(使用QHBoxLayout
),MainLayout
(使用QGridLayout
)
GitHub链接 : UserInfo
LeftLayout
(使用QGridLayout
)
void Dialog::LeftLayoutSetting()
UserNameLabel = new QLabel(tr("用户名:"));
UserNameLineEdit = new QLineEdit();
NameLabel = new QLabel(tr("姓名:"));
NameLineEdit = new QLineEdit();
SexLabel = new QLabel(tr("性别:"));
SexComboBox = new QComboBox();
SexComboBox->addItem(tr("女"));
SexComboBox->addItem(tr("男"));
DepartmentLabel = new QLabel(tr("部门:"));
DepartmentTextEdit = new QTextEdit();
AgeLabel = new QLabel(tr("年龄:"));
AgeLineEdit = new QLineEdit();
NoteLabel = new QLabel(tr("备注:"));
NoteLabel->setFrameStyle(QFrame::Panel|QFrame::Sunken);
LeftLayout = new QGridLayout();
LeftLayout->addWidget(UserNameLabel,0,0);
LeftLayout->addWidget(UserNameLineEdit,0,1);
LeftLayout->addWidget(NameLabel,1,0);
LeftLayout->addWidget(NameLineEdit,1,1);
LeftLayout->addWidget(SexLabel,2,0);
LeftLayout->addWidget(SexComboBox,2,1);
LeftLayout->addWidget(DepartmentLabel,3,0);
LeftLayout->addWidget(DepartmentTextEdit,3,1);
LeftLayout->addWidget(AgeLabel,4,0);
LeftLayout->addWidget(AgeLineEdit,4,1);
LeftLayout->addWidget(NoteLabel,5,0,1,2);
LeftLayout->setColumnStretch(0,1);
LeftLayout->setColumnStretch(1,3);
RightLayout
(使用QVBoxLayout
)
void Dialog::RightLayoutSetting()
HeadLabel = new QLabel(tr("头像"));
HeadIconLabel = new QLabel();
QPixmap icon(":/icon/head.png");
HeadIconLabel->setPixmap(icon);
HeadIconLabel->setFixedSize(100, 100);
HeadIconLabel->setScaledContents(true);
UpdateHeadBtn = new QPushButton(tr("更新"));
RightTopLayout = new QHBoxLayout();
RightTopLayout->addWidget(HeadLabel);
RightTopLayout->addWidget(HeadIconLabel);
RightTopLayout->addWidget(UpdateHeadBtn);
RightTopLayout->setSpacing(20);
PersonalInfoLabel = new QLabel(tr("个人说明"));
PersonalInfoTextEdit = new QTextEdit();
RightLayout = new QVBoxLayout();
RightLayout->addLayout(RightTopLayout);
RightLayout->addWidget(PersonalInfoLabel);
RightLayout->addWidget(PersonalInfoTextEdit);
RightLayout->setMargin(10);
BottomLayout
(使用QHBoxLayout
)
void Dialog::BottomLayoutSetting()
OkBtn = new QPushButton(tr("确定"));
CancelBtn = new QPushButton(tr("取消"));
BottomLayout = new QHBoxLayout();
BottomLayout->addStretch();
BottomLayout->addWidget(OkBtn);
BottomLayout->addWidget(CancelBtn);
MainLayout
(使用QGridLayout
)
void Dialog::MainLayoutSetting()
MainLayout = new QGridLayout(this);
MainLayout->setMargin(15);
MainLayout->setSpacing(10);
MainLayout->addLayout(LeftLayout,0,0);
MainLayout->addLayout(RightLayout,0,1);
MainLayout->addLayout(BottomLayout,1,0,1,2);
MainLayout->setSizeConstraint(QLayout::SetFixedSize);
void QGridLayout::setColumnStretch(int column, int stretch)
Sets the stretch factor of column column to stretch. The first column is number 0.
The stretch factor is relative to the other columns in this grid. Columns with a higher stretch factor take more of the available space.
The default stretch factor is 0. If the stretch factor is 0 and no other column in this table can grow at all, the column may still grow.
An alternative approach is to add spacing using addItem() with a QSpacerItem.
添加资源:
右键工程->add New…->选择Qt Qt Resource File -> 选择保存路径和名称(默认 .qrc) -> 下一步选着添加项目
在 add Prefix 中 前缀 修改为 icon (根据需要修改)
点击 add Files 添加 图片,并取别名
希望我的文章对于大家有帮助,由于个人能力的局限性,文中可能存在一些问题,欢迎指正、补充!
介绍QT基本布局QLayout,Qt的布局类,水平、垂直、网格、表单布局,伸展因素等,并通过Demo介绍如何使用基本布局管理,如QHBoxLayout、QVBoxLayout、QGridLayout 类
介绍完常用控件之后,我们发现,之前控件的大小位置都是通过resize()、move()来设置的,很不方便,当你修改某个控件的位置时,其他控件也需要进行调整,容易出现牵一发而动全身的情况。
QT提供了类QLayout进行布局管理,能很好解决这一情况。常用的布局管理有QVBoxLayout、QHBoxLayout、QFormLayout、QGridLayout。通过布局嵌套基本可以实现理想的...
QLayout 类是布局管理器的基类,是 QBoxLayout、QGridLayout、QFormLayout 和 QStackedLayout 继承的抽象基类。
要自定义布局管理器,须实现函数:
addItem()
sizeHint()
setGeometry()
itemAt()
takeAt()
还应该实现 minimumSize() 以确保如果空间太少,布局不会调整为零大小。要支持高度取决于宽度的子项,须实现 hasHeightForWidth() 和 heightForW.
总结了部分常用了基本控件之后,本篇笔记对Qt的布局管理进行总结。Qt自带一系列简单而强大的布局管理工具,以自动在窗体中排布控件。这极大的方便了开发人员管理GUI控件,达到几乎强迫症级别的优美排布,尤其是在适应不同分辨率界面的时候。
所有的QWidget子类都可以用layout管理他们的控件,用QWidget::setLayout()函数既可以为这个widget设置layout。如果一个Layou...
开发一个图形界面应用程序,界面的布局影响到界面的美观。在设计一个界面之前,应该考虑到开发的界面可能给不用的用户使用,而用户的屏幕大小、纵横比例、分辨率可能不同,界面还可能是可缩放的,程序应该可以适应这些变化。
前面的程序中都是使用setGeometry()方法定位控件的位置,这个方法比较笨拙。试想如果控件很多,布局这些控件需要编写大量的代码。幸运的是,QT提供了更好的方法布局控件
您好,可以使用QStackedLayout来实现两个布局的重叠。首先,将两个布局添加到QStackedLayout中,然后使用setCurrentIndex()方法来切换布局的显示。具体实现可以参考以下代码:
QVBoxLayout *layout1 = new QVBoxLayout;
QLabel *label1 = new QLabel("Layout 1");
layout1->addWidget(label1);
QVBoxLayout *layout2 = new QVBoxLayout;
QLabel *label2 = new QLabel("Layout 2");
layout2->addWidget(label2);
QStackedLayout *stackedLayout = new QStackedLayout;
stackedLayout->addWidget(layout1);
stackedLayout->addWidget(layout2);
stackedLayout->setCurrentIndex(1); // 切换到第二个布局
QWidget *widget = new QWidget;
widget->setLayout(stackedLayout);
setCentralWidget(widget);
希望能帮到您。