zoukankan      html  css  js  c++  java
  • 文件保存树形结构数据

    本文主要研究了一下如何把树形结构的数据保存到文件并读取出来。为了更形象说明用了一个界面程序显示,程序用了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

  • 相关阅读:
    [Codeup 25482]选美
    [Codeup 25481] swan
    暑假集训D12总结
    [技术]浅谈重载操作符
    2020年寒假第6次学*进度记录
    2020年寒假第5次学*进度记录
    2020年寒假第4次学*进度记录
    “家庭记账本”软件开发(1)
    阅读《梦断代码》随笔(1)
    2020年寒假第三次学*进度记录
  • 原文地址:https://www.cnblogs.com/findumars/p/5176052.html
Copyright © 2011-2022 走看看