引言
有时候程序中的控件的个数是无法预测的,当程序启动时,根据解析的数据动态的创建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_NAMESPACEclass StudentScoreDialog : public QDialog
{Q_OBJECTpublic: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}]}]
}
整个工程就如上面所示,程序启动的时候根据从配置文件中获取的参数来创建控件,并布局,上面虽使用了栅格布局,但设置了姓名和成绩的控件的宽度,故而将窗口最大化之后不能很完美的显示控件,即成绩和姓名行编辑器没有被拉伸,注释掉对姓名和成绩行编辑器的宽度设置后可以最大化窗口,同时拉伸控件。