当前位置:嗨网首页>书籍在线阅读

15-数据准备

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

9.3.2 数据准备

图9-10左上方的数据采用Model/View结构,在主窗口类MainWindow里定义了数据模型,并在主窗口的构造函数里初始化数据。下面是MainWindow的类定义(省略了部分窗口界面组件的槽函数定义)。

#define    fixedColumnCount   5   //数据模型的列数
#define    iniDataRowCount    6   //学生个数
#define    colNoName       0      //姓名的列编号
#define    colNoMath       1      //数学的列编号
#define    colNoChinese    2      //语文的列编号
#define    colNoEnglish    3      //英语的列编号
#define    colNoAverage    4      //平均分的列编号
class MainWindow : public QMainWindow
{
   Q_OBJECT
private:
   QStandardItemModel  *theModel; //数据模型
   void   iniData();              //初始化数据
   void   surveyData();           //统计数据
   void   iniBarChart();          //柱状图初始化
   void   buildBarChart();        //构建柱状图
   void   iniPiewChart();         //饼图
   void   buildPieChart(); 
   void   iniStackedBar();        //堆叠图
   void   buildStackedBar(); 
   void   iniPercentBar();        //百分比柱状图
   void   buildPercentBar(); 
   void   iniScatterChart();      //散点图
   void   buildScatterChart(); 
private slots:
//三个分数列的数据发生变化,重新计算平均分
   void on_itemChanged(QStandardItem *item);
public:
   explicit MainWindow(QWidget *parent = 0);
   ~MainWindow();
private:
   Ui::MainWindow *ui;
};

在头文件中首先定义了一些常量,包括数据模型的列数fixedColumnCount和学生人数iniData RowCount。定义为常量后便于修改,例如现在学生人数定义为6个,后续为了增大数据样本,可以将学生人数定义为30人。头文件里还定义了数据模型中5个列的编号,在后续的程序里使用常量。

MainWindow类中定义了数据模型类变量theModel,函数iniData()用于随机初始化数据,surveyData()用于对数据进行统计。

每个图表有两个函数,一个用于初始化,一个用于根据数据构建图表。如iniBarChart()用于初始化柱状图,buildBarChart()用于根据数据构建柱状图。

数据模型中每名学生的平均分根据3门课的成绩自动计算,希望在界面修改一个分数时,自动计算其平均分。这里可以利用QStandardItemModel的itemChanged()信号,在某个数据项被修改后会发射此信号,定义了一个私有槽函数on_itemChanged()用于响应此信号,实现平均分的自动计算。

下面是MainWindow的构造函数的实现代码。

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
   ui->setupUi(this);
   theModel = new QStandardItemModel(iniDataRowCount,fixedColumnCount,this); 
   iniData(); //初始化数据
   surveyData();//数据统计
//数据模块的 itemChanged信号与自定义的槽函数关联,用于自动计算平均分
   connect(theModel,SIGNAL(itemChanged(QStandardItem *)),
          this,SLOT(on_itemChanged(QStandardItem *)));
   ui->tableView->setModel(theModel); //设置数据模型
   iniBarChart(); //柱状图初始化
   iniPiewChart();//饼图初始化
   iniStackedBar();//堆叠图初始化
   iniPercentBar();//百分比柱状图初始化
   iniScatterChart(); //散点图初始化
}

在构造函数中,创建数据模型theModel,然后初始化数据、统计数据,将数据模型的itemChanged()信号与自定义槽函数on_itemChanged()关联起来。然后对5个图表调用函数进行初始化。

下面是iniData()函数的实现代码,用于对数据模型进行初始化。

void MainWindow::iniData()
{ //数据初始化
   QStringList   headerList;
   headerList<<"姓名"<<"数学"<<"语文"<<"英语"<<"平均分";
   theModel->setHorizontalHeaderLabels(headerList); //设置表头文字
   qsrand(QTime::currentTime().second());//随机数种子
   for (int i=0;i<theModel->rowCount();i++)
   {
      QString  studName=QString::asprintf("学生%2d",i+1);
      QStandardItem*   aItem=new QStandardItem(studName);//创建item
      aItem->setTextAlignment(Qt::AlignHCenter);
      theModel->setItem(i,colNoName,aItem); //学生列,设置item
      qreal   avgScore=0;
      for (int j=colNoMath;j<=colNoEnglish;j++) //数学,语文,英语
      { //不包含最后一列
         qreal   score=50.0+(qrand() % 50);//随机数
         avgScore+=score;
         aItem=new QStandardItem(QString::asprintf("%.0f",score));
         aItem->setTextAlignment(Qt::AlignHCenter);
         theModel->setItem(i,j,aItem); //设置Item
      }
     aItem=new QStandardItem(QString::asprintf("%.1f",avgScore/3));//平均分
      aItem->setTextAlignment(Qt::AlignHCenter);
      aItem->setFlags(aItem->flags() & (!Qt::ItemIsEditable));//不允许编辑
      theModel->setItem(i,colNoAverage,aItem); 
   }
}

数据初始化会设置表头标题,数学、语文、英语分数采用随机数生成,然后计算平均分。其中,平均分一列是不允许编辑的。

数据统计函数surveyData()用于对数据模型里的数据按照分数段进行统计,然后显示在QTreeWidget组件里。数据统计是简单的数学计算,对QTreeWidget的操作在4.7节有介绍,所以surveyData()函数的代码不再具体显示。

自定义槽函数on_itemChanged()用于在分数修改后自动计算平均分,下面是槽函数on_itemChanged()的代码。

void MainWindow::on_itemChanged(QStandardItem *item)
{ //自动计算平均分
   if ((item->column()<colNoMath) || (item->column()>colNoEnglish))
      return; //如果被修改的item不是数学、语文、英语,就退出
   int rowNo=item->row(); //获取数据的行编号
   qreal   avg=0;
   QStandardItem   *aItem;
   for (int i=colNoMath;i<=colNoEnglish;i++)
   { //获取三个分数的和
      aItem=theModel->item(rowNo,i);
      avg+=aItem->text().toDouble();
   }
   avg=avg/3; //计算平均分
   aItem=theModel->item(rowNo,colNoAverage); //获取平均分数据的item
   aItem->setText(QString::asprintf("%.1f",avg)); 
}

传递的参数item是被修改的数据项。程序首先判断该数据项是不是3个基本分数,如果不是就退出。通过item->row()获取当前数据的行号,然后提取3个基本分数计算平均分,再更新数据模型中的平均分数据项。