引言
有时候程序中的控件的个数是无法预测的,当程序启动时,根据解析的数据动态的创建n行m列的控件,并为其布局。下面记录一下动态创建控件,并布局。
运行效果
示例
此示例主要是从json配置文件中读取参数,然后根据参数的个数创建姐买你上的控件并布局。
下面是具体的实现代码:
main.cpp
#include "studentscoredialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StudentScoreDialog w;
w.show();
return a.exec();
}
studentscoredialog.h
#ifndef STUDENTSCOREDIALOG_H
#define STUDENTSCOREDIALOG_H
/********************************************
======功能描述:=======
1.根据解析的数据动态创建按钮,并布局,
2.数据太多超过显示的窗口的大小时,自动添加滚动条。
********************************************/
#include <QDialog>
//具体学生成绩结构
typedef struct studentInfo
{
QString name;//学生姓名
qreal score;//学生成绩
}ST_STUDENTINFO;
typedef ST_STUDENTINFO stuStudent;
typedef struct scoreInfo
{
QString strClass;//班级
qreal arvgScore;//平均成绩
qreal totalScore;//总成绩
uint8_t number;//人数
QList<stuStudent> students;//学生成绩列表
}ST_SCOREINFO;
typedef ST_SCOREINFO stuScore;
class QVBoxLayout;
QT_BEGIN_NAMESPACE
namespace Ui { class StudentScoreDialog; }
QT_END_NAMESPACE
class StudentScoreDialog : public QDialog
{
Q_OBJECT
public:
StudentScoreDialog(QWidget *parent = nullptr);
~StudentScoreDialog();
protected:
QString getExePath();//获取可执行文件的路径
void readStudentJsonFile();//读取json文件
void parseJsonContent(QByteArray &array);//解析json文件内容
void createCtrl();//创建控件
void createEveryClassScore(stuScore &score,QVBoxLayout *vLayout);//创建每一个班级的成绩情况
private:
Ui::StudentScoreDialog *ui;
QList<stuScore> m_stuScoreList;//保存从json文件读取的变量值
};
#endif // STUDENTSCOREDIALOG_H
studentscoredialog.cpp
#include "studentscoredialog.h"
#include "ui_studentscoredialog.h"
#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonParseError>
#include <QFile>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QDebug>
StudentScoreDialog::StudentScoreDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::StudentScoreDialog)
{
ui->setupUi(this);
setWindowFlags(Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
readStudentJsonFile();
createCtrl();
}
StudentScoreDialog::~StudentScoreDialog()
{
delete ui;
}
QString StudentScoreDialog::getExePath()
{
return QCoreApplication::applicationDirPath();
}
void StudentScoreDialog::readStudentJsonFile()
{
QString strPath = getExePath() + "/students.json";
QFile file(strPath);
if (file.open(QIODevice::ReadOnly)) {
QByteArray byteArray = file.readAll();
file.close();
parseJsonContent(byteArray);
}else {
qDebug()<<QStringLiteral("文件打开失败!");
}
}
void StudentScoreDialog::parseJsonContent(QByteArray &array)
{
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(array,&parseError);
if (!doc.isEmpty() && parseError.error == QJsonParseError::NoError) {
QJsonObject rootObject = doc.object();
if (rootObject.value("msg").toString() == "score") {
QJsonArray resultArray = rootObject.value("results").toArray();
for (int i = 0; i < resultArray.size(); ++i) {
QJsonObject resultObject = resultArray[i].toObject();
stuScore tempScore;
tempScore.strClass = resultObject.value("class").toString();
tempScore.arvgScore = resultObject.value("averageScore").toDouble();
tempScore.totalScore = resultObject.value("totalScore").toDouble();
tempScore.number = resultObject.value("number").toInt();
QJsonArray studentArray = resultObject.value("students").toArray();
for (int j = 0; j < studentArray.size(); ++j) {
stuStudent tempStudent;
QJsonObject studentObject = studentArray.at(j).toObject();
tempStudent.name = studentObject.value("name").toString();
tempStudent.score = studentObject.value("score").toDouble();
tempScore.students.append(tempStudent);
}
m_stuScoreList.append(tempScore);
}
}
}
}
void StudentScoreDialog::createCtrl()
{
QWidget *widget = ui->scrollAreaWidgetContents;
QVBoxLayout *vLayout = new QVBoxLayout(widget);
vLayout->setSpacing(5);
vLayout->setContentsMargins(5,5,5,5);
for (int i = 0; i < m_stuScoreList.size(); ++i) {
QGroupBox *groupBox = new QGroupBox;
QVBoxLayout *groupVlayout = new QVBoxLayout(groupBox);
groupVlayout->setSpacing(5);
groupVlayout->setContentsMargins(5,0,5,0);
stuScore classScore = m_stuScoreList.at(i);
createEveryClassScore(classScore,groupVlayout);
vLayout->addWidget(groupBox);
}
}
void StudentScoreDialog::createEveryClassScore(stuScore &score, QVBoxLayout *vLayout)
{
QHBoxLayout *hLayout = new QHBoxLayout;
QLabel *classLabel = new QLabel(QStringLiteral("班级:"));
QLineEdit *classEdit = new QLineEdit(score.strClass);
QLabel *averageLabel = new QLabel(QStringLiteral("平均成绩:"));
QLineEdit *averageEdit = new QLineEdit(QString::number(score.arvgScore));
QLabel *totalLabel = new QLabel(QStringLiteral("总成绩:"));
QLineEdit *totalEdit = new QLineEdit(QString::number(score.totalScore));
QLabel *numberLabel = new QLabel(QStringLiteral("人数:"));
QLineEdit *numberEdit = new QLineEdit(QString::number(score.number));
hLayout->addWidget(classLabel);
hLayout->addWidget(classEdit);
hLayout->addWidget(averageLabel);
hLayout->addWidget(averageEdit);
hLayout->addWidget(totalLabel);
hLayout->addWidget(totalEdit);
hLayout->addWidget(numberLabel);
hLayout->addWidget(numberEdit);
vLayout->addLayout(hLayout);
QHBoxLayout *scoreLayout = nullptr;
for (int i = 0; i < score.students.size(); ++i) {
if (i % 4 == 0) {
scoreLayout = new QHBoxLayout;
scoreLayout->setSpacing(5);
scoreLayout->setContentsMargins(0,0,0,0);
vLayout->addLayout(scoreLayout);
}
stuStudent tempStudent = score.students[i];
QLabel *nameLabel = new QLabel(QStringLiteral("姓名:"));
QLineEdit *nameEdit = new QLineEdit(tempStudent.name);
nameEdit->setFixedWidth(120);
QLabel *scoreLabel = new QLabel(QStringLiteral("成绩:"));
QLineEdit *scoreEdit = new QLineEdit(QString::number(tempStudent.score));
scoreEdit->setFixedWidth(50);
scoreLayout->addWidget(nameLabel);
scoreLayout->addWidget(nameEdit);
scoreLayout->addWidget(scoreLabel);
scoreLayout->addWidget(scoreEdit);
if (i == score.students.size() - 1 && score.students.size() % 4 != 0) {
scoreLayout->addStretch();
}
}
}
ui文件中添加的控件:
创建的项目的结构:
此项目中读取的配置文件students.json,配置文件的内容如下:
students.json
{
"msg":"score",
"results":[
{
"class":"二年级一班",
"averageScore":78,
"totalScore":936,
"number":12,
"students":[{
"name":"李明",
"score":77
},{
"name":"胡书",
"score":77
},{
"name":"扫速度",
"score":79
},{
"name":"山山倒",
"score":80
},{
"name":"阿萨",
"score":68
},{
"name":"维欧",
"score":77
},{
"name":"奇数",
"score":75
},{
"name":"使能",
"score":78
},{
"name":"水浇地",
"score":69
},{
"name":"当数据",
"score":87
},{
"name":"但是",
"score":76
},{
"name":"撒口",
"score":79
}]
},{
"class":"二年级二班",
"averageScore":80,
"totalScore":960,
"number":12,
"students":[{
"name":"蛋黄酥",
"score":77
},{
"name":"随机",
"score":79
},{
"name":"奥斯基",
"score":80
},{
"name":"赛德克",
"score":78
},{
"name":"收到",
"score":83
},{
"name":"卡松",
"score":77
},{
"name":"欧俄",
"score":86
},{
"name":"撒旦",
"score":78
},{
"name":"喀什",
"score":84
},{
"name":"科奥",
"score":87
},{
"name":"杰斯",
"score":76
},{
"name":"欧维",
"score":83
}]
}
]
}
整个工程就如上面所示,程序启动的时候根据从配置文件中获取的参数来创建控件,并布局,上面虽使用了栅格布局,但设置了姓名和成绩的控件的宽度,故而将窗口最大化之后不能很完美的显示控件,即成绩和姓名行编辑器没有被拉伸,注释掉对姓名和成绩行编辑器的宽度设置后可以最大化窗口,同时拉伸控件。