程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 文件保存樹形結構數據

文件保存樹形結構數據

編輯:C++入門知識

本文主要研究了一下如何把樹形結構的數據保存到文件並讀取出來。為了更形象說明用了一個界面程序顯示,程序用了model/view框架。   數據類 DataItem 就是保存在樹形結構的基本數據。其最重要的保存數據的函數是SerialzeData [cpp]   {   public:          DataItem(int id = 100,QString name = "root");       ~DataItem();          void SetRoot(DataItem *root);       void SerialzeData(bool isSave,QDataStream &stream);       void Clear();       void Init();       //protected:       int GetID()       {           return ID;       }          QString GetName()       {           return Name;       }          void SetID(int id)       {           ID = id;       }          void SetName(QString name)       {           Name = name;       }          int  GetSize()       {           return dataVec.size();       }          void AddItem(DataItem *pItem);          void DeleteItem(DataItem *pItem);          void DeleteItem(int index);          DataItem *GetItem(int index);          DataItem *GetParent()       {           return pRoot;       }          int indexOf(DataItem* pItem);   private:       int ID;       QString Name;       vector<DataItem*>  dataVec;       DataItem *pRoot;   };   [cpp]   DataItem::DataItem( int id,QString name ):ID(id),Name(name),pRoot(NULL)   {       //pRoot = new DataItem(100,"Root");   }      DataItem::~DataItem()   {      }   //SerialzeData 原來是,保存數據時,先保存每個項的數據,在後面保存該項的子節點個數,並遞歸保存各個子節點數據   void DataItem::SerialzeData( bool isSave,QDataStream &stream )   {       if (isSave)       {           stream<<GetID()<<GetName();  //save ID and Name            stream<<dataVec.size();     //save  the number of child           for(int i = 0; i < dataVec.size(); ++i)           {               dataVec[i]->SerialzeData(isSave,stream);           }       }       else       {           int id;           int size;           QString name;           stream>>id>>name;  //Get ID and Name            SetID(id);           SetName(name);           stream>>size;     //Get  the number of child           for(int i = 0; i < size; ++i)           {               DataItem *pItem = new DataItem(0,"name");               pItem->SerialzeData(isSave,stream);               AddItem(pItem);           }       }   }      void DataItem::AddItem( DataItem *pItem )   {       pItem->SetRoot(this);       dataVec.push_back(pItem);   }      void DataItem::DeleteItem( DataItem *pItem )   {       vector<DataItem*>::iterator it = dataVec.begin();       for (it; it != dataVec.end(); ++it)       {           if (*it == pItem)           {               dataVec.erase(it);               break;           }       }   }      void DataItem::DeleteItem( int index )   {       if (index < dataVec.size())       {           vector<DataItem*>::iterator it = dataVec.begin();           it = it + index;           dataVec.erase(it);       }   }      void DataItem::Init()   {       for (int i = 0; i < 5; ++i)       {           DataItem *pItem = new DataItem(i,QString("child%1").arg(i));           pRoot->AddItem(pItem);           for (int j = 0; j < 2; ++j)           {               DataItem *pChild = new DataItem(j,QString("grandchild%0 -%1").arg(i).arg(j));               pItem->AddItem(pChild);           }       }   }      void DataItem::SetRoot( DataItem *root )   {       pRoot = root;   }      void DataItem::Clear()   {       dataVec.clear();   }      DataItem * DataItem::GetItem( int index )   {         if (index < dataVec.size())           {               return dataVec[index];           }           else           {               return NULL;           }   }      int DataItem::indexOf( DataItem* pItem )   {       int index = -1;       for (int i = 0; i < dataVec.size(); ++i)       {           if (dataVec[i] == pItem)           {               index = i;               break;           }       }       return index;   }     數據模型 TreeDataModel的底層數據就是上面定義的DataItem。用這種視圖/模型的編程方式可以盡量減少數據與界面的耦合性。由於繼承了QAbstractItemModel。所以必須重寫其中的五個純虛函數columnCount (),data(),index (),parent ()和rowCount()。   [cpp]   class TreeDataModel:public QAbstractItemModel   {       Q_OBJECT   public:       TreeDataModel(QObject *parent = NULL);       ~TreeDataModel();          void SetRoot(DataItem *pRoot)       {           m_pTreeData = pRoot;       }       QModelIndex parent ( const QModelIndex & index ) const;        QVariant   data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;        QVariant   headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;        QModelIndex    index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;        int    columnCount ( const QModelIndex & parent = QModelIndex() ) const;        int    rowCount ( const QModelIndex & parent = QModelIndex() ) const;        DataItem* dataFromIndex(const QModelIndex &index) const;           void SaveData(QDataStream &out);        void LoadData(QDataStream &in);   protected:   private:       DataItem  *m_pTreeData;   };     [cpp]   TreeDataModel::TreeDataModel( QObject *parent /*= NULL*/ ):QAbstractItemModel(parent)   {       m_pTreeData = NULL;   }      TreeDataModel::~TreeDataModel()   {      }      QVariant TreeDataModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const   {       DataItem *pItem = dataFromIndex(index);       if ((pItem)&&(role == Qt::DisplayRole))       {           switch (index.column())           {           case 0:               return pItem->GetID();           case 1:               return pItem->GetName();           }       }       return QVariant();      }      QVariant TreeDataModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole */ ) const   {       if ((section <2) && (orientation == Qt::Horizontal)&& (role == Qt::DisplayRole))       {           switch (section)           {           case 0:               return tr("編號");              case 1:               return tr("名稱");           default:               return QVariant();           }       }       else       {           return QVariant();       }   }      QModelIndex TreeDataModel::index( int row, int column, const QModelIndex & parent /*= QModelIndex() */ ) const   {       if (!m_pTreeData ||row < 0 || column < 0)       {           return QModelIndex();       }       else       {           DataItem *pItem = dataFromIndex(parent);           if (pItem)           {               DataItem *pChild = pItem->GetItem(row);               if (pChild)               {                   return createIndex(row,column,pChild);               }           }           return QModelIndex();       }   }      int TreeDataModel::columnCount( const QModelIndex & parent /*= QModelIndex() */ ) const   {       return 2;   }      int TreeDataModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const   {       DataItem *pItem = dataFromIndex(parent);       if (pItem)       {           return pItem->GetSize();       }       return 0;   }      DataItem* TreeDataModel::dataFromIndex( const QModelIndex &index ) const   {       if (index.isValid())       {           return static_cast<DataItem*>(index.internalPointer());       }        else       {           return m_pTreeData;               //這裡不要返回NULL       }   }      QModelIndex TreeDataModel::parent( const QModelIndex & index ) const   {       if (index.isValid())       {           DataItem *pItem = dataFromIndex(index);           if (pItem)           {               DataItem *pParent = pItem->GetParent();               if (pParent)               {                   DataItem *pGrandParent = pParent->GetParent();                   if (pGrandParent)                   {                       int row = pGrandParent->indexOf(pParent);                       return createIndex(row,index.column(),pParent);                   }               }           }       }       return QModelIndex();   }      void TreeDataModel::SaveData( QDataStream &out )   {       m_pTreeData->SerialzeData(true,out);   }      void TreeDataModel::LoadData( QDataStream &in )   {       m_pTreeData->SerialzeData(false,in);   }     主框架類 這個類主要實現左邊的樹形把數據保存到文件中,然後在右邊的樹形結構加載顯示出來。 [cpp]   class MainWidget:public QWidget   {       Q_OBJECT   public:       MainWidget(QWidget *patent = NULL);       ~MainWidget();      protected slots:       void leftSelectBtnSlot();       void rightSelectBtnSlot();       void saveBtnSlot();       void loadBtnSlot();      private:       QSplitter         *m_pSplitter;       QTreeView         *m_pLeftTreeView;       QTreeView         *m_pRightTreeView;       QPushButton       *m_pLeftSaveBtn;       QPushButton       *m_pRightLoadBtn;       QPushButton       *m_pLeftSelectBtn;       QPushButton       *m_pRightSelectBtn;       QLineEdit         *m_pLeftLEdit;       QLineEdit         *m_pRightLEdit;       QGridLayout       *m_pLeftLayout;       QGridLayout       *m_pRightLayout;          TreeDataModel     *m_pLeftModel;       TreeDataModel     *m_pRightModel;         };       [cpp]   MainWidget::MainWidget( QWidget *patent /*= NULL*/ ):QWidget(patent)   {       m_pLeftModel = new TreeDataModel();       m_pRightModel = new TreeDataModel();          m_pSplitter = new QSplitter(this);       QFrame *pLeftFrame = new QFrame(this);       QFrame *pRightFrame = new QFrame(this);       m_pLeftLayout = new QGridLayout(pLeftFrame);       m_pRightLayout = new QGridLayout(pRightFrame);       m_pLeftLEdit = new QLineEdit(this);       m_pRightLEdit = new QLineEdit(this);       m_pLeftSaveBtn = new QPushButton(tr("保存"),this);       m_pRightLoadBtn = new QPushButton(tr("加載"),this);       m_pLeftTreeView = new QTreeView(this);       m_pRightTreeView = new QTreeView(this);       m_pLeftSelectBtn = new QPushButton(tr("選擇文件"),this);       m_pRightSelectBtn = new QPushButton(tr("選擇文件"),this);       m_pRightLEdit->setReadOnly(true);                 m_pLeftLayout->addWidget(m_pLeftSelectBtn,0,0,1,1);       m_pLeftLayout->addWidget(m_pLeftLEdit,0,1,1,1);       m_pLeftLayout->addWidget(m_pLeftSaveBtn,0,2,1,1);       m_pLeftLayout->addWidget(m_pLeftTreeView,1,0,3,3);          m_pRightLayout->addWidget(m_pRightSelectBtn,0,0,1,1);       m_pRightLayout->addWidget(m_pRightLEdit,0,1,1,1);       m_pRightLayout->addWidget(m_pRightLoadBtn,0,2,1,1);       m_pRightLayout->addWidget(m_pRightTreeView,1,0,3,3);          m_pLeftTreeView->setModel(m_pLeftModel);       m_pRightTreeView->setModel(m_pRightModel);       DataItem *pTreeData = new DataItem();       pTreeData->SetRoot(pTreeData);       pTreeData->Init();              m_pLeftModel->SetRoot(pTreeData);       //m_pRightModel->SetRoot(pTreeData);          m_pSplitter->addWidget(pLeftFrame);       m_pSplitter->addWidget(pRightFrame);          connect(m_pLeftSelectBtn,SIGNAL(clicked()),this,SLOT(leftSelectBtnSlot()));       connect(m_pRightSelectBtn,SIGNAL(clicked()),this,SLOT(rightSelectBtnSlot()));       connect(m_pLeftSaveBtn,SIGNAL(clicked()),this,SLOT(saveBtnSlot()));       connect(m_pRightLoadBtn,SIGNAL(clicked()),this,SLOT(loadBtnSlot()));       this->setFixedSize(QSize(650,250));   }      MainWidget::~MainWidget()   {      }      void MainWidget::leftSelectBtnSlot()     //這裡只是選擇了一個文件夾路徑,在保存之前還需要加文件名   {       QFileDialog Dialog(this,tr("選擇目錄"),"","");       Dialog.setFileMode(QFileDialog::Directory);       //Dialog.setNameFilter("*.data");       if (Dialog.exec())       {           QStringList dirs = Dialog.selectedFiles();           if (dirs.size() > 0)           {               m_pLeftLEdit->setText(QDir::toNativeSeparators(dirs.at(0)));               }       }    }      void MainWidget::rightSelectBtnSlot()      //選擇之前保存的.data文件進行加載顯示   {       QFileDialog Dialog(this,tr("選擇文件"),"","");       Dialog.setFileMode(QFileDialog::ExistingFile);       Dialog.setNameFilter("*.data");       if (Dialog.exec())       {           QStringList files = Dialog.selectedFiles();           if (files.size() > 0)           {               m_pRightLEdit->setText(QDir::toNativeSeparators(files.at(0)));           }       }    }      void MainWidget::saveBtnSlot()   {   [cpp]       QString filePath = m_pLeftLEdit->text();       if ((filePath.isEmpty()) || filePath.endsWith("\\") || filePath.endsWith("/"))   //必須得添加文件名,文件名規定後綴為.data       {           QMessageBox::information(this,tr("提示"),tr("請輸入文件名"),QMessageBox::Ok);           return;       }       else if(filePath.endsWith("data"))       {           QFile file(filePath);           if (file.open(QIODevice::WriteOnly))           {               QDataStream outStream(&file);               m_pLeftModel->SaveData(outStream);           }       }   }      void MainWidget::loadBtnSlot()   {       QString filePath = m_pRightLEdit->text();       if((!filePath.isEmpty()) &&filePath.endsWith("data"))       {           DataItem *pTreeData = new DataItem();           //pTreeData->SetRoot(pTreeData);           m_pRightModel->SetRoot(pTreeData);              QFile file(filePath);           if (file.open(QIODevice::ReadOnly))           {               QDataStream inStream(&file);               m_pRightModel->LoadData(inStream);               m_pRightTreeView->setModel(m_pRightModel);               m_pRightTreeView->reset();                  //必須的,不然不會刷新           }       }   }  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved