文件保存树形结构数据

本文主要研究了一下如何把树形结构的数据保存到文件并读取出来。为了更形象说明用了一个界面程序显示,程序用了model/view框架。

数据类

DataItem 就是保存在树形结构的基本数据。其最重要的保存数据的函数是SerialzeData
[cpp] view plain copy
 
  1. class DataItem  
  2. {  
  3. public:  
  4.   
  5.     DataItem(int id = 100,QString name = "root");  
  6.     ~DataItem();  
  7.   
  8.     void SetRoot(DataItem *root);  
  9.     void SerialzeData(bool isSave,QDataStream &stream);  
  10.     void Clear();  
  11.     void Init();  
  12.     //protected:  
  13.     int GetID()  
  14.     {  
  15.         return ID;  
  16.     }  
  17.   
  18.     QString GetName()  
  19.     {  
  20.         return Name;  
  21.     }  
  22.   
  23.     void SetID(int id)  
  24.     {  
  25.         ID = id;  
  26.     }  
  27.   
  28.     void SetName(QString name)  
  29.     {  
  30.         Name = name;  
  31.     }  
  32.   
  33.     int  GetSize()  
  34.     {  
  35.         return dataVec.size();  
  36.     }  
  37.   
  38.     void AddItem(DataItem *pItem);  
  39.   
  40.     void DeleteItem(DataItem *pItem);  
  41.   
  42.     void DeleteItem(int index);  
  43.   
  44.     DataItem *GetItem(int index);  
  45.   
  46.     DataItem *GetParent()  
  47.     {  
  48.         return pRoot;  
  49.     }  
  50.   
  51.     int indexOf(DataItem* pItem);  
  52. private:  
  53.     int ID;  
  54.     QString Name;  
  55.     vector<DataItem*>  dataVec;  
  56.     DataItem *pRoot;  
  57. };  
[cpp] view plain copy
 
  1. DataItem::DataItem( int id,QString name ):ID(id),Name(name),pRoot(NULL)  
  2. {  
  3.     //pRoot = new DataItem(100,"Root");  
  4. }  
  5.   
  6. DataItem::~DataItem()  
  7. {  
  8.   
  9. }  
  10. //SerialzeData 原来是,保存数据时,先保存每个项的数据,在后面保存该项的子节点个数,并递归保存各个子节点数据  
  11. void DataItem::SerialzeData( bool isSave,QDataStream &stream )  
  12. {  
  13.     if (isSave)  
  14.     {  
  15.         stream<<GetID()<<GetName();  //save ID and Name   
  16.         stream<<dataVec.size();     //save  the number of child  
  17.         for(int i = 0; i < dataVec.size(); ++i)  
  18.         {  
  19.             dataVec[i]->SerialzeData(isSave,stream);  
  20.         }  
  21.     }  
  22.     else  
  23.     {  
  24.         int id;  
  25.         int size;  
  26.         QString name;  
  27.         stream>>id>>name;  //Get ID and Name   
  28.         SetID(id);  
  29.         SetName(name);  
  30.         stream>>size;     //Get  the number of child  
  31.         for(int i = 0; i < size; ++i)  
  32.         {  
  33.             DataItem *pItem = new DataItem(0,"name");  
  34.             pItem->SerialzeData(isSave,stream);  
  35.             AddItem(pItem);  
  36.         }  
  37.     }  
  38. }  
  39.   
  40. void DataItem::AddItem( DataItem *pItem )  
  41. {  
  42.     pItem->SetRoot(this);  
  43.     dataVec.push_back(pItem);  
  44. }  
  45.   
  46. void DataItem::DeleteItem( DataItem *pItem )  
  47. {  
  48.     vector<DataItem*>::iterator it = dataVec.begin();  
  49.     for (it; it != dataVec.end(); ++it)  
  50.     {  
  51.         if (*it == pItem)  
  52.         {  
  53.             dataVec.erase(it);  
  54.             break;  
  55.         }  
  56.     }  
  57. }  
  58.   
  59. void DataItem::DeleteItem( int index )  
  60. {  
  61.     if (index < dataVec.size())  
  62.     {  
  63.         vector<DataItem*>::iterator it = dataVec.begin();  
  64.         it = it + index;  
  65.         dataVec.erase(it);  
  66.     }  
  67. }  
  68.   
  69. void DataItem::Init()  
  70. {  
  71.     for (int i = 0; i < 5; ++i)  
  72.     {  
  73.         DataItem *pItem = new DataItem(i,QString("child%1").arg(i));  
  74.         pRoot->AddItem(pItem);  
  75.         for (int j = 0; j < 2; ++j)  
  76.         {  
  77.             DataItem *pChild = new DataItem(j,QString("grandchild%0 -%1").arg(i).arg(j));  
  78.             pItem->AddItem(pChild);  
  79.         }  
  80.     }  
  81. }  
  82.   
  83. void DataItem::SetRoot( DataItem *root )  
  84. {  
  85.     pRoot = root;  
  86. }  
  87.   
  88. void DataItem::Clear()  
  89. {  
  90.     dataVec.clear();  
  91. }  
  92.   
  93. DataItem * DataItem::GetItem( int index )  
  94. {  
  95.       if (index < dataVec.size())  
  96.         {  
  97.             return dataVec[index];  
  98.         }  
  99.         else  
  100.         {  
  101.             return NULL;  
  102.         }  
  103. }  
  104.   
  105. int DataItem::indexOf( DataItem* pItem )  
  106. {  
  107.     int index = -1;  
  108.     for (int i = 0; i < dataVec.size(); ++i)  
  109.     {  
  110.         if (dataVec[i] == pItem)  
  111.         {  
  112.             index = i;  
  113.             break;  
  114.         }  
  115.     }  
  116.     return index;  
  117. }  

数据模型

TreeDataModel的底层数据就是上面定义的DataItem。用这种视图/模型的编程方式可以尽量减少数据与界面的耦合性。由于继承了QAbstractItemModel。所以必须重写其中的五个纯虚函数columnCount (),data(),index (),parent ()和rowCount()。

[cpp] view plain copy
 
  1. class TreeDataModel:public QAbstractItemModel  
  2. {  
  3.     Q_OBJECT  
  4. public:  
  5.     TreeDataModel(QObject *parent = NULL);  
  6.     ~TreeDataModel();  
  7.   
  8.     void SetRoot(DataItem *pRoot)  
  9.     {  
  10.         m_pTreeData = pRoot;  
  11.     }  
  12.     QModelIndex parent ( const QModelIndex & index ) const;  
  13.      QVariant   data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;  
  14.      QVariant   headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;  
  15.      QModelIndex    index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;  
  16.      int    columnCount ( const QModelIndex & parent = QModelIndex() ) const;  
  17.      int    rowCount ( const QModelIndex & parent = QModelIndex() ) const;  
  18.      DataItem* dataFromIndex(const QModelIndex &index) const;  
  19.   
  20.      void SaveData(QDataStream &out);  
  21.      void LoadData(QDataStream &in);  
  22. protected:  
  23. private:  
  24.     DataItem  *m_pTreeData;  
  25. };  

[cpp] view plain copy
 
  1. TreeDataModel::TreeDataModel( QObject *parent /*= NULL*/ ):QAbstractItemModel(parent)  
  2. {  
  3.     m_pTreeData = NULL;  
  4. }  
  5.   
  6. TreeDataModel::~TreeDataModel()  
  7. {  
  8.   
  9. }  
  10.   
  11. QVariant TreeDataModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const  
  12. {  
  13.     DataItem *pItem = dataFromIndex(index);  
  14.     if ((pItem)&&(role == Qt::DisplayRole))  
  15.     {  
  16.         switch (index.column())  
  17.         {  
  18.         case 0:  
  19.             return pItem->GetID();  
  20.         case 1:  
  21.             return pItem->GetName();  
  22.         }  
  23.     }  
  24.     return QVariant();  
  25.   
  26. }  
  27.   
  28. QVariant TreeDataModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole */ ) const  
  29. {  
  30.     if ((section <2) && (orientation == Qt::Horizontal)&& (role == Qt::DisplayRole))  
  31.     {  
  32.         switch (section)  
  33.         {  
  34.         case 0:  
  35.             return tr("编号");  
  36.   
  37.         case 1:  
  38.             return tr("名称");  
  39.         default:  
  40.             return QVariant();  
  41.         }  
  42.     }  
  43.     else  
  44.     {  
  45.         return QVariant();  
  46.     }  
  47. }  
  48.   
  49. QModelIndex TreeDataModel::index( int row, int column, const QModelIndex & parent /*= QModelIndex() */ ) const  
  50. {  
  51.     if (!m_pTreeData ||row < 0 || column < 0)  
  52.     {  
  53.         return QModelIndex();  
  54.     }  
  55.     else  
  56.     {  
  57.         DataItem *pItem = dataFromIndex(parent);  
  58.         if (pItem)  
  59.         {  
  60.             DataItem *pChild = pItem->GetItem(row);  
  61.             if (pChild)  
  62.             {  
  63.                 return createIndex(row,column,pChild);  
  64.             }  
  65.         }  
  66.         return QModelIndex();  
  67.     }  
  68. }  
  69.   
  70. int TreeDataModel::columnCount( const QModelIndex & parent /*= QModelIndex() */ ) const  
  71. {  
  72.     return 2;  
  73. }  
  74.   
  75. int TreeDataModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const  
  76. {  
  77.     DataItem *pItem = dataFromIndex(parent);  
  78.     if (pItem)  
  79.     {  
  80.         return pItem->GetSize();  
  81.     }  
  82.     return 0;  
  83. }  
  84.   
  85. DataItem* TreeDataModel::dataFromIndex( const QModelIndex &index ) const  
  86. {  
  87.     if (index.isValid())  
  88.     {  
  89.         return static_cast<DataItem*>(index.internalPointer());  
  90.     }   
  91.     else  
  92.     {  
  93.         return m_pTreeData;               //这里不要返回NULL  
  94.     }  
  95. }  
  96.   
  97. QModelIndex TreeDataModel::parent( const QModelIndex & index ) const  
  98. {  
  99.     if (index.isValid())  
  100.     {  
  101.         DataItem *pItem = dataFromIndex(index);  
  102.         if (pItem)  
  103.         {  
  104.             DataItem *pParent = pItem->GetParent();  
  105.             if (pParent)  
  106.             {  
  107.                 DataItem *pGrandParent = pParent->GetParent();  
  108.                 if (pGrandParent)  
  109.                 {  
  110.                     int row = pGrandParent->indexOf(pParent);  
  111.                     return createIndex(row,index.column(),pParent);  
  112.                 }  
  113.             }  
  114.         }  
  115.     }  
  116.     return QModelIndex();  
  117. }  
  118.   
  119. void TreeDataModel::SaveData( QDataStream &out )  
  120. {  
  121.     m_pTreeData->SerialzeData(true,out);  
  122. }  
  123.   
  124. void TreeDataModel::LoadData( QDataStream &in )  
  125. {  
  126.     m_pTreeData->SerialzeData(false,in);  
  127. }  

主框架类

这个类主要实现左边的树形把数据保存到文件中,然后在右边的树形结构加载显示出来。
[cpp] view plain copy
 
  1. class MainWidget:public QWidget  
  2. {  
  3.     Q_OBJECT  
  4. public:  
  5.     MainWidget(QWidget *patent = NULL);  
  6.     ~MainWidget();  
  7.   
  8. protected slots:  
  9.     void leftSelectBtnSlot();  
  10.     void rightSelectBtnSlot();  
  11.     void saveBtnSlot();  
  12.     void loadBtnSlot();  
  13.   
  14. private:  
  15.     QSplitter         *m_pSplitter;  
  16.     QTreeView         *m_pLeftTreeView;  
  17.     QTreeView         *m_pRightTreeView;  
  18.     QPushButton       *m_pLeftSaveBtn;  
  19.     QPushButton       *m_pRightLoadBtn;  
  20.     QPushButton       *m_pLeftSelectBtn;  
  21.     QPushButton       *m_pRightSelectBtn;  
  22.     QLineEdit         *m_pLeftLEdit;  
  23.     QLineEdit         *m_pRightLEdit;  
  24.     QGridLayout       *m_pLeftLayout;  
  25.     QGridLayout       *m_pRightLayout;  
  26.   
  27.     TreeDataModel     *m_pLeftModel;  
  28.     TreeDataModel     *m_pRightModel;  
  29.   
  30.   
  31. };  


[cpp] view plain copy
 
  1. MainWidget::MainWidget( QWidget *patent /*= NULL*/ ):QWidget(patent)  
  2. {  
  3.     m_pLeftModel = new TreeDataModel();  
  4.     m_pRightModel = new TreeDataModel();  
  5.   
  6.     m_pSplitter = new QSplitter(this);  
  7.     QFrame *pLeftFrame = new QFrame(this);  
  8.     QFrame *pRightFrame = new QFrame(this);  
  9.     m_pLeftLayout = new QGridLayout(pLeftFrame);  
  10.     m_pRightLayout = new QGridLayout(pRightFrame);  
  11.     m_pLeftLEdit = new QLineEdit(this);  
  12.     m_pRightLEdit = new QLineEdit(this);  
  13.     m_pLeftSaveBtn = new QPushButton(tr("保存"),this);  
  14.     m_pRightLoadBtn = new QPushButton(tr("加载"),this);  
  15.     m_pLeftTreeView = new QTreeView(this);  
  16.     m_pRightTreeView = new QTreeView(this);  
  17.     m_pLeftSelectBtn = new QPushButton(tr("选择文件"),this);  
  18.     m_pRightSelectBtn = new QPushButton(tr("选择文件"),this);  
  19.     m_pRightLEdit->setReadOnly(true);  
  20.   
  21.       
  22.     m_pLeftLayout->addWidget(m_pLeftSelectBtn,0,0,1,1);  
  23.     m_pLeftLayout->addWidget(m_pLeftLEdit,0,1,1,1);  
  24.     m_pLeftLayout->addWidget(m_pLeftSaveBtn,0,2,1,1);  
  25.     m_pLeftLayout->addWidget(m_pLeftTreeView,1,0,3,3);  
  26.   
  27.     m_pRightLayout->addWidget(m_pRightSelectBtn,0,0,1,1);  
  28.     m_pRightLayout->addWidget(m_pRightLEdit,0,1,1,1);  
  29.     m_pRightLayout->addWidget(m_pRightLoadBtn,0,2,1,1);  
  30.     m_pRightLayout->addWidget(m_pRightTreeView,1,0,3,3);  
  31.   
  32.     m_pLeftTreeView->setModel(m_pLeftModel);  
  33.     m_pRightTreeView->setModel(m_pRightModel);  
  34.     DataItem *pTreeData = new DataItem();  
  35.     pTreeData->SetRoot(pTreeData);  
  36.     pTreeData->Init();  
  37.       
  38.     m_pLeftModel->SetRoot(pTreeData);  
  39.     //m_pRightModel->SetRoot(pTreeData);  
  40.   
  41.     m_pSplitter->addWidget(pLeftFrame);  
  42.     m_pSplitter->addWidget(pRightFrame);  
  43.   
  44.     connect(m_pLeftSelectBtn,SIGNAL(clicked()),this,SLOT(leftSelectBtnSlot()));  
  45.     connect(m_pRightSelectBtn,SIGNAL(clicked()),this,SLOT(rightSelectBtnSlot()));  
  46.     connect(m_pLeftSaveBtn,SIGNAL(clicked()),this,SLOT(saveBtnSlot()));  
  47.     connect(m_pRightLoadBtn,SIGNAL(clicked()),this,SLOT(loadBtnSlot()));  
  48.     this->setFixedSize(QSize(650,250));  
  49. }  
  50.   
  51. MainWidget::~MainWidget()  
  52. {  
  53.   
  54. }  
  55.   
  56. void MainWidget::leftSelectBtnSlot()     //这里只是选择了一个文件夹路径,在保存之前还需要加文件名  
  57. {  
  58.     QFileDialog Dialog(this,tr("选择目录"),"","");  
  59.     Dialog.setFileMode(QFileDialog::Directory);  
  60.     //Dialog.setNameFilter("*.data");  
  61.     if (Dialog.exec())  
  62.     {  
  63.         QStringList dirs = Dialog.selectedFiles();  
  64.         if (dirs.size() > 0)  
  65.         {  
  66.             m_pLeftLEdit->setText(QDir::toNativeSeparators(dirs.at(0)));      
  67.         }  
  68.     }   
  69. }  
  70.   
  71. void MainWidget::rightSelectBtnSlot()      //选择之前保存的.data文件进行加载显示  
  72. {  
  73.     QFileDialog Dialog(this,tr("选择文件"),"","");  
  74.     Dialog.setFileMode(QFileDialog::ExistingFile);  
  75.     Dialog.setNameFilter("*.data");  
  76.     if (Dialog.exec())  
  77.     {  
  78.         QStringList files = Dialog.selectedFiles();  
  79.         if (files.size() > 0)  
  80.         {  
  81.             m_pRightLEdit->setText(QDir::toNativeSeparators(files.at(0)));  
  82.         }  
  83.     }   
  84. }  
  85.   
  86. void MainWidget::saveBtnSlot()  
  87. {  
[cpp] view plain copy
 
  1.     QString filePath = m_pLeftLEdit->text();  
  2.     if ((filePath.isEmpty()) || filePath.endsWith("\\") || filePath.endsWith("/"))   //必须得添加文件名,文件名规定后缀为.data  
  3.     {  
  4.         QMessageBox::information(this,tr("提示"),tr("请输入文件名"),QMessageBox::Ok);  
  5.         return;  
  6.     }  
  7.     else if(filePath.endsWith("data"))  
  8.     {  
  9.         QFile file(filePath);  
  10.         if (file.open(QIODevice::WriteOnly))  
  11.         {  
  12.             QDataStream outStream(&file);  
  13.             m_pLeftModel->SaveData(outStream);  
  14.         }  
  15.     }  
  16. }  
  17.   
  18. void MainWidget::loadBtnSlot()  
  19. {  
  20.     QString filePath = m_pRightLEdit->text();  
  21.     if((!filePath.isEmpty()) &&filePath.endsWith("data"))  
  22.     {  
  23.         DataItem *pTreeData = new DataItem();  
  24.         //pTreeData->SetRoot(pTreeData);  
  25.         m_pRightModel->SetRoot(pTreeData);  
  26.   
  27.         QFile file(filePath);  
  28.         if (file.open(QIODevice::ReadOnly))  
  29.         {  
  30.             QDataStream inStream(&file);  
  31.             m_pRightModel->LoadData(inStream);  
  32.             m_pRightTreeView->setModel(m_pRightModel);  
  33.             m_pRightTreeView->reset();                  //必须的,不然不会刷新  
  34.         }  
  35.     }  
  36. }  

运行结果如下图

http://blog.csdn.net/hai200501019/article/details/11022581

posted @ 2016-02-01 18:49  findumars  Views(2617)  Comments(0Edit  收藏  举报