此片文章简单介绍布局管理的使用方法。通过实例先分别介绍分隔窗口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); //将此编辑框设为主窗口的中央窗体//停靠窗口1QDockWidget* 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);//停靠窗口2dock = 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);//停靠窗口3dock = 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); //设定对话框(或窗体)的边距为5mainLayout->setSpacing(5); //设定各个控件之间的间距为5mainLayout->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); //设定各个控件之间的间距为20TopRightLayout->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); //设定对话框的边距为15mainLayout->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()的大小显示。
工程源码
文章涉及的所有代码都可点击工程源码下载。