QT布局管理(分割窗口QSplitter类、停靠窗口QDockWidget类、堆栈窗体QStackedWidget类、基本布局QLayout)
文章介绍QT常用布局管理类,包括QSpliter、QDockWidget、QStackedWidgwt以及QLayout。
此片文章简单介绍布局管理的使用方法。通过实例先分别介绍分隔窗口QSplitter类、停靠窗口QDockWidget类及QStackedWidget类的使用,最后再通过一个实例介绍QLayout的使用。
分割窗口QSplitter类
分隔窗口可以灵活地布局窗口,可以用在文件资源管理器地窗口设计中。下图显示一个简单的分割窗口功能,界面窗口由3个子窗口组成,各个窗口之间可随意拖拽改变大小。
上图为spliter工程运行效果,相关代码如下:
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QFont font("ZYSong18030", 12); //指定显示字体
a.setFont(font);
//主分割窗口
QSplitter* splitterMain = new QSplitter(Qt::Horizontal, 0);
QTextEdit* textLeft = new QTextEdit(QObject::tr("Left Widget"), splitterMain);
textLeft->setAlignment(Qt::AlignCenter);
//右部分分割窗口
QSplitter* splitterRight = new QSplitter(Qt::Vertical, splitterMain);
splitterRight->setOpaqueResize(false);
QTextEdit* textUp = new QTextEdit(QObject::tr("Top Widget"), splitterRight);
textUp->setAlignment(Qt::AlignCenter);
QTextEdit* textBottom = new QTextEdit(QObject::tr("Bottom Widget"), splitterRight);
textBottom->setAlignment(Qt::AlignCenter);
splitterMain->setStretchFactor(1, 1);
splitterMain->setWindowTitle(QObject::tr("Splitter"));
splitterMain->show();
//spliter w;
//w.show();
return a.exec();
}
关键代码说明如下:
- QSplitter* splitterMain = new QSplitter(Qt::Horizontal, 0):创建QSplitter对象,并设置水平分隔窗口。
- QTextEdit* textLeft = new QTextEdit(QObject::tr(“Left Widget”), splitterMain):新建QTextEdit对象并插添加到主分割窗口中。
- QSplitter* splitterRight = new QSplitter(Qt::Vertical, splitterMain):新建一个QSplitter对象设置为垂直分割并添加到父窗口。
- splitterRight->setOpaqueResize(false):设定分割窗口的分割线在拖拽时是否为实时更新显示,true则实时更新显示,false则在拖拽时只显示一条灰色的粗线条。
- splitterMain->setStretchFactor(1, 1):此方法用于设定可伸缩控件,第一个参数指定设置的控件序号,空间序号按插入顺序从0开始编号;第二个参数大于0表示此控件为可伸缩控件。此实例中设定右边的分割窗口为可伸缩控件,当整个对话框的宽度发生变化,左边的文本编辑框宽度保持不变,右边的分割窗口宽度随调整个对话框大小的改变进行调整。
停靠窗口QDockWidget类
以下是设置QDockWidget停靠窗口的一般流程:
- 创建QDockWidget对象的停靠窗口。
- 设置此停靠窗口的属性,通常调用setFeatures和setAllowedAreas两个方法。
- 新建一个要插入停靠窗口的控件。
- 将控件插入停靠窗口,调用setWidget方法。
- 使用addDockWidget方法在QMainWindow中加入此停靠窗体。
DockWindows工程运行的QDockWidget停靠窗口如下图所示:窗口1只可在主窗口的左边和右边停靠;窗口2只可在浮动窗口和右部停靠两种状态间切换,并且不可移动;窗口3可实现停靠窗口的各种状态。
界面布局核心代码如下:
DockWindows::DockWindows(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle(tr("DockWindows")); //设置主窗口的标题栏文字
QTextEdit* te = new QTextEdit(this); //定义一个QTextEdit对象作为主窗口
te->setText(tr("Main Window"));
te->setAlignment(Qt::AlignCenter);
setCentralWidget(te); //将此编辑框设为主窗口的中央窗体
//停靠窗口1
QDockWidget* dock = new QDockWidget(tr("DockWindow1"), this);
//可移动
dock->setFeatures(QDockWidget::DockWidgetMovable);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
QTextEdit* te1 = new QTextEdit();
te1->setText(tr("Window1,The dock widget can be moved between docks by the user" ""));
dock->setWidget(te1);
addDockWidget(Qt::RightDockWidgetArea, dock);
//停靠窗口2
dock = new QDockWidget(tr("DockWindow2"), this);
dock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable); //可关闭、可浮动
QTextEdit* te2 = new QTextEdit();
te2->setText(tr("Window2,The dock widget can be detached from the main window,""and floated as an independent window, and can be closed"));
dock->setWidget(te2);
addDockWidget(Qt::RightDockWidgetArea, dock);
//停靠窗口3
dock = new QDockWidget(tr("DockWindow3"), this);
dock->setFeatures(QDockWidget::AllDockWidgetFeatures); //全部特性
QTextEdit* te3 = new QTextEdit();
te3->setText(tr("Window3,The dock widget can be closed, moved, and floated"));
dock->setWidget(te3);
addDockWidget(Qt::RightDockWidgetArea, dock);
}
其中有两个方法需要我们关注一下:
- setFeatures:此方法用于设置停靠窗口的特性,函数声明如下:
void setFeatures(QDockWidget::DockWidgetFeatures features)
参数QDockWidget::DockWidgetFeatures指定停靠窗体的特性,包括以下几种参数。- QDockWidget::DockWidgetClosable:停靠窗口可关闭。
- QDockWidget::DockWidgetMovable:停靠窗体可移动。
- QDockWidget::DockWidgetFloatable:停靠窗体可浮动。
- QDockWidget::DockWidgetVerticalTitleBar:dock小部件在左侧显示一个垂直的标题栏。这可以用来增加QMainWindow中的垂直空间。
- QDockWidget::NoDockWidgetFeatures:不可移动、不可关闭、不可浮动。
- setAllowedAreas:从方法用于设置停靠窗体可停靠的区域,函数声明如下:
void setAllowedAreas(Qt::DockWidgetAreas areas)
参数Qt::DockWidgetAreas指定停靠窗口可停靠区域,包括以下几种参数。- Qt::LeftDockWidgetArea:可在主窗口的左侧停靠。
- Qt::RightDockWidgetArea:可在主窗口的右侧停靠。
- Qt::TopDockWidgetArea:可在主窗口的顶部停靠。
- Qt::BottomDockWidgetArea:可在主窗口的底部停靠。
- Qt::AllDockWidgetAreas:可在主窗口的(以上四个)部位停靠。
- Qt::NoDockWidgetArea:只可停靠在插入处。
堆栈窗体QStackedWidget类
堆栈窗体QStackedWidget在实际应用中,经常与列表框QListWidget及下拉列表框QComboBox配合使用。
堆栈窗体QStackedWidget类的使用,当选择左侧列表框中不同的选项时,右侧显示所选的不同的窗体。效果图如下所示。
StackedWidget项目关键代码如下:
StackedWidget::StackedWidget(QWidget *parent)
: QDialog(parent)
{
setWindowTitle(tr("StackedWidget"));
list = new QListWidget(this); //新建一个QListWidget控件对象
//在新建的QListWidget控件中插入三个条目,作为选择项
list->insertItem(0, tr("Window1"));
list->insertItem(1, tr("Window2"));
list->insertItem(2, tr("Window3"));
//创建三个QLabel标签控件对象,作为堆栈窗口需要显示的三层窗体
label1 = new QLabel(tr("WindowTest1"));
label2 = new QLabel(tr("WindowTest2"));
label3 = new QLabel(tr("WindowTest3"));
stack = new QStackedWidget(this);
//新建一个QStackedWidget堆栈窗体对象
//将创建的三个QLabel标签控件依次插入堆栈窗体中
stack->addWidget(label1);
stack->addWidget(label2);
stack->addWidget(label3);
QHBoxLayout* mainLayout = new QHBoxLayout(this);
//对整个对话框进行布局
mainLayout->setMargin(5); //设定对话框(或窗体)的边距为5
mainLayout->setSpacing(5); //设定各个控件之间的间距为5
mainLayout->addWidget(list);
mainLayout->addWidget(stack, 0, Qt::AlignHCenter);
mainLayout->setStretchFactor(list, 1);
mainLayout->setStretchFactor(stack, 3);
connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int)));
}
以下两个方法需要我们关注:
- mainLayout->setStretchFactor(list, 1):设定可伸缩控件,第一个参数用于指定设置的控件(序号从0开始),第二个参数的值大于0则表示此控件为可伸缩控件。
- connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int))):将QListWidget的currentRowChanged信号与堆栈窗体的setCurrentIndex槽函数连接起来,实现按选择显示窗体。此处的堆栈窗体index按插入的顺序从0起依次排序,与QListWidget的条目排序相一致。
基本布局QLayout
Qt提供了QHBoxLayout(水平排列布局)、QVBoxLayout(垂直排列布局)以及QGridLayout(网格排列布局)等布局管理类。各种布局类的派生关系如下:
在代码布局中常用的方法有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() // 指定对齐方式
)
下面通过一个UserInfo工程实现一个“用户资料”的功能表单来介绍如何使用基本布局管理,界面效果图如下所示:
关键代码如下:
UserInfo::UserInfo(QWidget *parent)
: QDialog(parent)
{
setWindowTitle(tr("UserInfo"));
/************** 左侧 ******************************/
UserNameLabel = new QLabel(QString::fromLocal8Bit("用户名:"));
UserNameLineEdit = new QLineEdit;
NameLabel = new QLabel(QStringLiteral("姓名:"));
NameLineEdit = new QLineEdit;
SexLabel = new QLabel(QStringLiteral("性别:"));
SexComboBox = new QComboBox;
SexComboBox->addItem(QStringLiteral("女"));
SexComboBox->addItem(QStringLiteral("男"));
DepartmentLabel = new QLabel(QStringLiteral("部门:"));
DepartmentTextEdit = new QTextEdit;
AgeLabel = new QLabel(QStringLiteral("年龄:"));
AgeLineEdit = new QLineEdit;
OtherLabel = new QLabel(QStringLiteral("备注:"));
OtherLabel->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(OtherLabel, 5, 0, 1, 2); //其他
LeftLayout->setColumnStretch(0, 1);
LeftLayout->setColumnStretch(1, 3);
/*********右侧*********/
HeadLabel = new QLabel(QStringLiteral("头像: ")); //右上角部分
HeadIconLabel = new QLabel;
QPixmap icon("312.png");
HeadIconLabel->setPixmap(icon);
HeadIconLabel->resize(icon.width(), icon.height());
UpdateHeadBtn = new QPushButton(QStringLiteral("更新"));
//完成右上侧头像选择区的布局
TopRightLayout = new QHBoxLayout();
TopRightLayout->setSpacing(20); //设定各个控件之间的间距为20
TopRightLayout->addWidget(HeadLabel);
TopRightLayout->addWidget(HeadIconLabel);
TopRightLayout->addWidget(UpdateHeadBtn);
IntroductionLabel = new QLabel(QStringLiteral("个人说明:")); //右下角部分
IntroductionTextEdit = new QTextEdit;
//完成右侧的布局
RightLayout = new QVBoxLayout();
RightLayout->setMargin(10);
RightLayout->addLayout(TopRightLayout);
RightLayout->addWidget(IntroductionLabel);
RightLayout->addWidget(IntroductionTextEdit);
/*--------------------- 底部 --------------------*/
OkBtn = new QPushButton(QStringLiteral("确定"));
CancelBtn = new QPushButton(QStringLiteral("取消"));
//完成下方两个按钮的布局
ButtomLayout = new QHBoxLayout();
ButtomLayout->addStretch();
ButtomLayout->addWidget(OkBtn);
ButtomLayout->addWidget(CancelBtn);
/*---------------------------------------------*/
QGridLayout* mainLayout = new QGridLayout(this);
mainLayout->setMargin(15); //设定对话框的边距为15
mainLayout->setSpacing(10);
mainLayout->addLayout(LeftLayout, 0, 0);
mainLayout->addLayout(RightLayout, 0, 1);
mainLayout->addLayout(ButtomLayout, 1, 0, 1, 2);
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
}
上述代码的一些内容在此解释一下:
- OtherLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken):设置控件风格。setFrameStyle方法是QFrame类的方法,参数可以通过(|)符号设置多种风格。风格由形状(QFrame::Shape)和阴影(QFrame::Shadow)两项配合设定。其中,形状包括7种,分别是QFrame::NoFrame、QFrame::Box、QFrame::Panel、QFrame::StyledPanel、QFrame::HLine、QFrame::VLine、QFrame::WinPanel;阴影包括3种,分别是QFrame::Plain、QFrame::Raised、QFrame::Sunken。
- LeftLayout = new QGridLayout():左侧布局,由于此布局管理器不是主布局管理器,所以不用指定父窗口。
- LeftLayout->setColumnStretch(0, 1)、LeftLayout->setColumnStretch(1, 3):设定两列分别占用空间的比例,本比例为1:3。即时对话框框架大小改变了,两列之间的狂赌比依然保持不变。
- ButtomLayout->addStretch():在按钮之前插入一个占位符,使两个按钮能够靠右对齐,并且在整个对话框的大小发生改变时,保证按钮的大小不发生变化。
- QGridLayout* mainLayout = new QGridLayout(this):实现主布局,指定父窗口this,也可调用this->setLayout(mainLayout)实现。
- mainLayout->setSizeConstraint(QLayout::SetFixedSize):设定最优化显示,并且使用户改变对话框的大小。所谓最优化显示,即控件都按其sizeHint()的大小显示。
工程源码
文章涉及的所有代码都可点击工程源码下载。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)