QFormLayout顾名思义,主要用来做表单的输入及显示。和前面讲到的QBoxLayout、QGridLayout类似,QFormLayout可以插入widget、layout,直接用QGridLayout也可以做出QFormLayout的效果。
下面开始介绍QFormLayout用作表单应用时相关的接口函数。
基本方法
在末尾新增
左侧添加标签,右侧添加widget或layout
void addRow(QWidget *label, QWidget *field)
void addRow(QWidget *label, QLayout *field)一般,左侧添加一个QLabel用来显示文本信息,右侧增加一个QLineEdit用来给用户输入。
左侧使用QFormLayout自带标签,右侧增加widget或layout
void addRow(const QString &labelText, QWidget *field)
void addRow(const QString &labelText, QLayout *field)针对上面提到的接口函数,QFormLayout提供了一种更为便利的方法,该方法直接使用QFormLayout内部的QLabel,labelText所传参数为左侧label所显示的内容。
跨越两列增加widget或layout
void addRow(QWidget *widget)
void addRow(QLayout *layout)该方法直接在末尾添加一个横跨两列的widget或layout,比如在末尾添加一个含有ok和clear按钮的layout。
在指定位置新增
void insertRow(int row, QWidget *label, QWidget *field)
void insertRow(int row, QWidget *label, QLayout *field)
void insertRow(int row, const QString &labelText, QWidget *field)
void insertRow(int row, const QString &labelText, QLayout *field)
void insertRow(int row, QWidget *widget)
void insertRow(int row, QLayout *layout)只不过加了一个行号,其他含义和用法和上面一样,这里就不分条介绍了。
删除
删除某一行
void removeRow(int row)删除某一widget或layout
void removeRow(QWidget *widget)
void removeRow(QLayout *layout)获取
QLayoutItem *itemAt(int row, QFormLayout::ItemRole role) const返回具有指定角色(列)的给定行中的布局项。如果没有这样的项,则返回nullptr。
QFormLayout::ItemRole参数列表:
QFormLayout::LabelRole A label widget.
QFormLayout::FieldRole A field widget.
QFormLayout::SpanningRole A widget that spans label and field columns.
这里其实和前面add或insert时对应的label或field对应。
演示表单提交的代码
界面编写:
自定义Widget类的构造函数代码
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//创建表单布局
QFormLayout *flay = new QFormLayout();
//创建QLabel作为表单标题显示
QLabel *title = new QLabel("学生信息录入");
//居中显示
title->setAlignment(Qt::AlignHCenter);
//设置字体大小
title->setStyleSheet("font-size:20px");
//放置标题到最前面
flay->addRow(title);
QLineEdit *nameLineEdit = new QLineEdit();
//添加name
flay->addRow("&Name:", nameLineEdit);
//添加email
QLineEdit *emailLineEdit = new QLineEdit();
flay->addRow("&Email:", emailLineEdit);
//添加age
QSpinBox *ageSpinBox = new QSpinBox();
flay->addRow("&Age:", ageSpinBox);
//在最底部增加两个按钮
QHBoxLayout *hlay = new QHBoxLayout();
QPushButton *btOk = new QPushButton("ok");
QPushButton *btClear = new QPushButton("clear");
hlay->addWidget(btOk);
hlay->addWidget(btClear);
flay->addRow(hlay);
//设置widget的主布局
this->setLayout(flay);
}main函数代码
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}运行效果:

其中"&Age:"、"&Email:"、"&Name:",前面都有加一个'&'符号,其目的是可以用快捷键"ALT+首字母"将光标切换到目标行进行输入。
表单的提交
所谓表单的提交就是在用户按下ok按钮时,拿到用户输入的各项数据,并作出相应的处理。
既然和按钮按下有关,那就要先绑定按钮按下事件。
在widget构造函数中新增以下代码,用于信号与槽的绑定
connect(btOk,SIGNAL(clicked()),this,SLOT(OnOkBtClicked()));槽函数的具体实现
void Widget::OnOkBtClicked()
{
//得到QFormLayout指针
QFormLayout *flay = static_cast<QFormLayout *>(this->layout());
if(!flay)
{
qDebug() << "Get layout failed!";
return;
}
//用来收集错误信息
QString errCode = "";
//用来收集正确的信息
QString inputMessage = "";
//遍历所有行,逐个取出所需内容
for(int i = 0 ; i < flay->rowCount() ; i++)
{
//获取label
QLayoutItem *itemLab = flay->itemAt(i, QFormLayout::LabelRole);
if(!itemLab)
continue;
QLabel *lab = static_cast<QLabel*>(itemLab->widget());
if(!lab)
continue;
//获取内容输入框
QLayoutItem *item = flay->itemAt(i, QFormLayout::FieldRole);
if(!item)
continue;
//获取widget
QWidget *widget = item->widget();
if(!widget)
continue;
//取到label的文字
QString labelText = lab->text();
//去掉前面的'&'
if(labelText[0] == '&')
labelText.remove(0,1);
//widget类型为QLineEdit
if(QString(widget->metaObject()->className()) == "QLineEdit")
{
//强制转换
QLineEdit *edit = static_cast<QLineEdit*>(widget);
if(!edit)
continue;
//如果是空的,证明此项没有输入,增加错误信息
if(edit->text().isEmpty())
{
errCode += labelText + "null\n";
continue;
}
//放到正确信息里
inputMessage += labelText + edit->text() + "\n";
}
else if(QString(widget->metaObject()->className()) == "QSpinBox")
{
QSpinBox *spinbox = static_cast<QSpinBox*>(widget);
if(!spinbox)
continue;
if(spinbox->text().isEmpty())
{
errCode += labelText + "null\n";
continue;
}
inputMessage += labelText + spinbox->text() + "\n";
}
else {
continue;
}
}
//弹出MessageBox提示成功或失败
if(!errCode.isEmpty())
QMessageBox::warning(this,"Input Error",errCode);
else {
QMessageBox::information(this,"Input OK",inputMessage);
}
}整个代码的功能是逐行获取用户输入,如果发现输入为空时,弹出警告窗口,提醒用户哪些项为空。如果程序成功获取到用户输入的所有内容时,弹出information窗口,显示出用户的输入。
其中的关键点是itemAt的使用,当想要获取左侧label时,需要给它的第二个参数传递QFormLayout::LabelRole。当想要获取右侧的用户输入时,需要给它的第二个参数传递QFormLayout::FieldRole。除此之外,还要做类型的强转、空指针的判断、widget对应的ClassName的获取,这些缺一不可。本程序中没有用到任何全局可访问的变量,全部通过动态获取的方式获取目标指针。
程序运行结果:
正确输入

有空项时:
