前面两节讲的model是一维的,这次开始二维的也就是我们常说的Table,相对与list,我们多了一个列的概念。
下面讲解一个例子。我先说明一下我们这个例子,在程序目录下,我们有一个文本文件,其中存放的学生信息。
数据存放的格式
学号 姓名 性别
xxx xxx x
每个学生的信息占一行,现在我们需要将这个文件中的所有学生信息加载显示。
在例子中主要涉及这几个类,Student,FileReader和DataTableModel类。
Student是学生实体类,FileRead从文件加载数据,后面的一个就是我们的model了。
下面代码贴出来
Student
- /************************************************
- *
- *author:周翔
- *e-mail:604487178@qq.com
- *blog:http://blog.csdn.net/zhx6044
- *
- *
- *************************************************/
- #ifndef STUDENT_HPP
- #define STUDENT_HPP
- #include <QString>
- #include <QTextStream>
- class Student
- {
- friend QTextStream& operator >>(QTextStream &in,Student &t) {
- in >> t.m_no >> t.m_name >> t.m_sex;
- return in;
- }
- public:
- Student(){}
- Student(const QString &no, const QString &name,const QString &sex);
- const QString& getNo() const;
- const QString& getName() const;
- const QString& getSex() const;
- static int members() {
- return 3;
- }
- QString operator [](int i) const{
- switch (i) {
- case 0:
- return m_no;
- case 1:
- return m_name;
- case 2:
- return m_sex;
- default:
- break;
- }
- return QString();
- }
- static QString describe(int i) {
- switch (i) {
- case 0:
- return "No.";
- case 1:
- return "Name";
- case 2:
- return "Sex";
- default:
- break;
- }
- return QString();
- }
- private:
- QString m_no;
- QString m_name;
- QString m_sex;
- };
- #endif // STUDENT_HPP
- /************************************************
- *
- *author:周翔
- *e-mail:604487178@qq.com
- *blog:http://blog.csdn.net/zhx6044
- *
- *
- *************************************************/
- #include "student.hpp"
- Student::Student(const QString &no, const QString &name, const QString &sex):
- m_no(no),
- m_name(name),
- m_sex(sex)
- {
- }
- inline
- const QString& Student::getNo() const
- {
- return m_no;
- }
- inline
- const QString& Student::getName() const
- {
- return m_name;
- }
- inline
- const QString& Student::getSex() const
- {
- return m_sex;
- }
重载的[]是为了使用方便,>>是为了支持流。
FileReader是一个模板类
- /************************************************
- *
- *author:周翔
- *e-mail:604487178@qq.com
- *blog:http://blog.csdn.net/zhx6044
- *
- *
- *************************************************/
- #ifndef FILEREADER_HPP
- #define FILEREADER_HPP
- #include <QFile>
- #include <QTextStream>
- #include "student.hpp"
- //you also can use QDataStream
- template <typename T>
- class FileReader
- {
- public:
- FileReader(const QString &name);
- ~FileReader();
- bool open();
- bool hasNext();
- T getNext();
- private:
- QString m_fileName;
- QFile m_file;
- QTextStream m_stream;
- };
- template <typename T>
- inline
- FileReader<T>::FileReader(const QString &name):m_fileName(name)
- {
- }
- template <typename T>
- FileReader<T>::~FileReader()
- {
- if (m_file.isOpen()) {
- m_file.close();
- }
- }
- template <typename T>
- bool FileReader<T>::open()
- {
- m_file.setFileName(m_fileName);
- if (m_file.open(QIODevice::ReadWrite)) {
- m_stream.setDevice(&m_file);
- return true;
- }
- return false;
- }
- template <typename T>
- bool FileReader<T>::hasNext()
- {
- if (m_file.isOpen()) {
- return !m_stream.atEnd();
- }
- return false;
- }
- template <typename T>
- T FileReader<T>::getNext()
- {
- T t;
- m_stream >> t;
- return t;
- }
- #endif // FILEREADER_HPP
构造参数是加载数据的文件名,提供了open操作,hasNext是判断是否结束,getNext得到一个加载的对象。
下面是我们的models,其中我使用了我的蹩脚的英文写了注释
- /************************************************
- *
- *author:周翔
- *e-mail:604487178@qq.com
- *blog:http://blog.csdn.net/zhx6044
- *
- *
- *************************************************/
- #ifndef DATATABLEMODEL_HPP
- #define DATATABLEMODEL_HPP
- #include <QAbstractTableModel>
- #include <vector>
- #include "student.hpp"
- #include "filereader.hpp"
- //Here,I want to use 'template class',but is not supported by the macor 'Q_OBJECT',
- //so I use typedef,of cause you also use macor
- //If you want to use it,the type of T use should implement the two static function
- //and overload operator[] and >>--int members(),it return T numbers of members,
- //QString describe(int ),the describe about T.operator[](int i),return the i-st member data.
- //the >> you know
- typedef Student T;
- class DataTableModel : public QAbstractTableModel
- {
- Q_OBJECT
- public:
- explicit DataTableModel(const QString &fileName,QObject *parent = 0);
- int rowCount(const QModelIndex &parent) const;
- int columnCount(const QModelIndex &parent) const;
- Qt::ItemFlags flags(const QModelIndex &index) const;
- QVariant data(const QModelIndex &index, int role) const;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const;
- signals:
- void sig_error(const QString &info);
- public slots:
- private:
- QString m_fileName;
- //use vector,loading data form file may low speed,but seaching is fast!
- std::vector<T> m_data;
- void load();
- };
- #endif // DATATABLEMODEL_HPP
- /************************************************
- *
- *author:周翔
- *e-mail:604487178@qq.com
- *blog:http://blog.csdn.net/zhx6044
- *
- *
- *************************************************/
- #include "datatablemodel.hpp"
- DataTableModel::DataTableModel(const QString &fileName, QObject *parent):
- QAbstractTableModel(parent),
- m_fileName(fileName)
- {
- load();
- }
- int DataTableModel::rowCount(const QModelIndex &/*parent*/) const
- {
- return m_data.size();
- }
- int DataTableModel::columnCount(const QModelIndex &/*parent*/) const
- {
- return T::members();
- }
- Qt::ItemFlags DataTableModel::flags(const QModelIndex &/*index*/) const
- {
- return Qt::ItemIsEnabled;
- }
- QVariant DataTableModel::data(const QModelIndex &index, int role) const
- {
- if (index.isValid() && role == Qt::DisplayRole) {
- return m_data[index.row()][index.column()];
- }
- return QVariant();
- }
- QVariant DataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
- {
- if (role != Qt::DisplayRole) {
- return QVariant();
- }
- if (orientation == Qt::Vertical) {
- return QString("row %1").arg(section);
- } else {
- return T::describe(section);
- }
- return QVariant();
- }
- /**
- * @brief DataTableModel::load load data from file
- */
- void DataTableModel::load()
- {
- //create a file reader that can read object about type of T from file
- //which name is m_fileName,the type of T should overload the operator >> on QTextStream.
- //A bug about FileReader,the last read is empty because the file is end with empty line.
- //But I think it is not a problem.
- FileReader<T> fr(m_fileName);
- if (fr.open()) {
- while (fr.hasNext()) {
- m_data.push_back(fr.getNext());
- }
- } else {
- emit sig_error("load data failure!");
- }
- }
本来是想也做成模板的,可是Qt元对象系统和模板机制是存在冲突的,以后讲为什么冲突。这里我使用了typedef来提前做了编译器应该做的事避免了冲突
data,rowCounts,flag,headerData这些都是需要重新实现的,在二维中columnCount就需要重新实现了。
只是为了显示所以flag很简单。
大家也看见了我在Student中实现的members,describe的用处,和重载[]所带来的便捷。
我们的列数就是需要对外实现的成员数,describe就是得到成员的描述。其实我感觉已经有点框架的味道了...算了不说大话了
其中的一个bug我已经用英文说了。
无图无真相
z
转自: