ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MFC CTreeCtrl 树结构在SQLite 中的存储和还原

2022-07-07 19:06:49  阅读:150  来源: 互联网

标签:SQLite MFC pFileTable 树结构 void HTREEITEM CFileView hItem wndFileView


MFC  CTreeCtrl 树节点是在插入时确定位置,用hParent, hInsertAfter 这两个HTREEITEM 可以唯一确定节点位置。

这样增,减,移动节点后,只有两个数据变化,涉及的其他节点数据的变化也很少,比较适合存储。随机存储的节点只要有两个相关节点数据就能还原出树。

实际还原很麻烦,因为存储的是两个节点的id,相当于索引,但是还原需要的是两个插入时才生成的句柄,一边要遍历树,另一边要查表,还得按顺序,脑袋嗡嗡的,不搞了。

简单起见,用一个层数据,一个遍历时的顺序数,这两个数据,配合一个节点的标识id,来存储和还原树结构。

id 是唯一标识节点,在数据库中是自动增长的唯一非空整数。每插入一个节点,数据库自动产生唯一的增加的id。这个值始终不变,除非节点删掉。

lev,idno 一个是层,一个是遍历序号,在保存时计算出来,并存入数据库,还原时用这两个数据来还原树结构,树节点中要保存id,用来对应数据库中相关业务数据。保存是遍历树,update 节点数据。

这样插入节点,移动节点不用改变其他节点的位置数据,因为id不变,唯一确定树节点,树的结构在保存时用遍历重新计算。

 

 

 MFC  默认的MDI框架,主要的存取,删除,插入程序段在File View中,用POP菜单做测试。

FileView.h

#pragma once

#include "ViewTree.h"
#include "re2.h"

#include "CSQLite.h"


class CFileViewToolBar : public CMFCToolBar
{
    virtual void OnUpdateCmdUI(CFrameWnd* /*pTarget*/, BOOL bDisableIfNoHndler)
    {
        CMFCToolBar::OnUpdateCmdUI((CFrameWnd*) GetOwner(), bDisableIfNoHndler);
    }

    virtual BOOL AllowShowOnList() const { return FALSE; }
};

class CFileView : public CDockablePane
{
// Construction
public:
    CFileView();

    void AdjustLayout();
    void OnChangeVisualStyle();
            
    CSQLite m_SQLite;

    HTREEITEM m_hNodeSrc;
    HTREEITEM m_hNodeFile;

    FileTable* m_pFileTable;

    //返回值是中间过程
    void FindNode(HTREEITEM hItem, int id, HTREEITEM& hPItem);
    
    //XGZ 这2个变量在递归中全程累计
    int m_NodeNo;
    int m_NodeLev;
        
    void SaveNode(HTREEITEM hItem);
    void UpdateNode(HTREEITEM hItem);
    void ShowAllNodes(HTREEITEM hItem);

    void InsertNode(HTREEITEM hItem);
    void DeleteNode(HTREEITEM hItem);
    void DeleteAllNodes(HTREEITEM hItem);
    CString m_strSave;
    
    HTREEITEM AddFileName(LPCTSTR strFileName, DWORD_PTR dwData);
    BOOL DelFileName(HTREEITEM& hFileNode);

    HTREEITEM AddNote(LPCTSTR Name, DWORD_PTR dwData);

// Attributes
protected:

    CViewTree m_wndFileView;
    CImageList m_FileViewImages;
    CFileViewToolBar m_wndToolBar;

protected:
    void FillFileView();

// Implementation
public:
    virtual ~CFileView();

protected:
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    afx_msg void OnProperties();
    afx_msg void OnFileOpen();
    afx_msg void OnFileOpenWith();
    afx_msg void OnDummyCompile();
    afx_msg void OnEditCut();
    afx_msg void OnEditCopy();
    afx_msg void OnEditClear();
    afx_msg void OnPaint();
    afx_msg void OnSetFocus(CWnd* pOldWnd);

    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnPopExpTest();
    afx_msg void OnPopExpTest2();
    afx_msg void OnPopExpInsertchild();
    afx_msg void OnPopExpInsertsibling();
    afx_msg void OnPopExpDelete();
    afx_msg void OnPopExpSave();
    afx_msg void OnPopExpUpdate();
    afx_msg void OnPopExpShowall();
};

FileView.cpp

#include "stdafx.h"
#include "mainfrm.h"
#include "FileView.h"
#include "Resource.h"
#include "RE2.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// CFileView

CFileView::CFileView()
{
    m_pFileTable = NULL;
}

CFileView::~CFileView()
{
    if (NULL != m_pFileTable)
    {
        delete[] m_pFileTable;
        m_pFileTable = NULL;
    }
    
}

BEGIN_MESSAGE_MAP(CFileView, CDockablePane)
    ON_WM_CREATE()
    ON_WM_SIZE()
    ON_WM_CONTEXTMENU()
    ON_COMMAND(ID_PROPERTIES, OnProperties)
    ON_COMMAND(ID_OPEN, OnFileOpen)
    ON_COMMAND(ID_OPEN_WITH, OnFileOpenWith)
    ON_COMMAND(ID_DUMMY_COMPILE, OnDummyCompile)
    ON_COMMAND(ID_EDIT_CUT, OnEditCut)
    ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
    ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
    ON_WM_PAINT()
    ON_WM_SETFOCUS()
    ON_COMMAND(ID_POP_EXP_TEST, &CFileView::OnPopExpTest)
    ON_COMMAND(ID_POP_EXP_TEST2, &CFileView::OnPopExpTest2)
    ON_COMMAND(ID_POP_EXP_INSERTCHILD, &CFileView::OnPopExpInsertchild)
    ON_COMMAND(ID_POP_EXP_INSERTSIBLING, &CFileView::OnPopExpInsertsibling)
    ON_COMMAND(ID_POP_EXP_DELETE, &CFileView::OnPopExpDelete)
    ON_COMMAND(ID_POP_EXP_SAVE, &CFileView::OnPopExpSave)
    ON_COMMAND(ID_POP_EXP_UPDATE, &CFileView::OnPopExpUpdate)
    ON_COMMAND(ID_POP_EXP_SHOWALL, &CFileView::OnPopExpShowall)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWorkspaceBar message handlers

int CFileView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDockablePane::OnCreate(lpCreateStruct) == -1)
        return -1;

    CRect rectDummy;
    rectDummy.SetRectEmpty();

    // Create view:
    const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS;

    if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))
    {
        TRACE0("Failed to create file view\n");
        return -1;      // fail to create
    }

    // Load view images:
    m_FileViewImages.Create(IDB_FILE_VIEW, 16, 0, RGB(255, 0, 255));
    m_wndFileView.SetImageList(&m_FileViewImages, TVSIL_NORMAL);

    m_wndToolBar.Create(this, AFX_DEFAULT_TOOLBAR_STYLE, IDR_EXPLORER);
    m_wndToolBar.LoadToolBar(IDR_EXPLORER, 0, 0, TRUE /* Is locked */);

    OnChangeVisualStyle();

    m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() | CBRS_TOOLTIPS | CBRS_FLYBY);

    m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() & ~(CBRS_GRIPPER | CBRS_SIZE_DYNAMIC | CBRS_BORDER_TOP | CBRS_BORDER_BOTTOM | CBRS_BORDER_LEFT | CBRS_BORDER_RIGHT));

    m_wndToolBar.SetOwner(this);

    // All commands will be routed via this control , not via the parent frame:
    m_wndToolBar.SetRouteCommandsViaFrame(FALSE);

    // Fill in some static tree view data (dummy code, nothing magic here)
    FillFileView();
    AdjustLayout();


    m_wndFileView.ModifyStyle(0, TVS_HASLINES | TVS_HASBUTTONS | TVS_EDITLABELS);

    return 0;
}

void CFileView::OnSize(UINT nType, int cx, int cy)
{
    CDockablePane::OnSize(nType, cx, cy);
    AdjustLayout();
}

void CFileView::FillFileView()
{
        
    HTREEITEM hRoot = m_wndFileView.InsertItem(_T("FakeApp files"), 0, 0);
    m_wndFileView.SetItemState(hRoot, TVIS_BOLD, TVIS_BOLD);

    HTREEITEM hSrc = m_wndFileView.InsertItem(_T("FakeApp Source Files"), 0, 0, hRoot);

    m_wndFileView.InsertItem(_T("FakeApp.cpp"), 1, 1, hSrc);
    HTREEITEM hSrc1 = m_wndFileView.InsertItem(_T("FakeApp.rc"), 1, 1, hSrc);
    m_wndFileView.InsertItem(_T("FakeAppDoc.cpp"), 1, 1, hSrc);
    m_wndFileView.InsertItem(_T("FakeAppView.cpp"), 1, 1, hSrc);
    m_wndFileView.InsertItem(_T("MainFrm.cpp"), 1, 1, hSrc);
    m_wndFileView.InsertItem(_T("StdAfx.cpp"), 1, 1, hSrc, hSrc1); //插在hSrc1后面


    HTREEITEM hInc = m_wndFileView.InsertItem(_T("FakeApp Header Files"), 0, 0, hRoot);

    m_wndFileView.InsertItem(_T("FakeApp.h"), 2, 2, hInc);
    m_wndFileView.InsertItem(_T("FakeAppDoc.h"), 2, 2, hInc);
    m_wndFileView.InsertItem(_T("FakeAppView.h"), 2, 2, hInc);
    m_wndFileView.InsertItem(_T("Resource.h"), 2, 2, hInc);
    m_wndFileView.InsertItem(_T("MainFrm.h"), 2, 2, hInc);
    m_wndFileView.InsertItem(_T("StdAfx.h"), 2, 2, hInc);

    HTREEITEM hRes = m_wndFileView.InsertItem(_T("FakeApp Resource Files"), 0, 0, hRoot);

    m_wndFileView.InsertItem(_T("FakeApp.ico"), 2, 2, hRes);
    m_wndFileView.InsertItem(_T("FakeApp.rc2"), 2, 2, hRes);
    m_wndFileView.InsertItem(_T("FakeAppDoc.ico"), 2, 2, hRes);
    m_wndFileView.InsertItem(_T("FakeToolbar.bmp"), 2, 2, hRes);

    m_wndFileView.Expand(hRoot, TVE_EXPAND);
    m_wndFileView.Expand(hSrc, TVE_EXPAND);
    m_wndFileView.Expand(hInc, TVE_EXPAND);

    m_hNodeSrc = hRoot;
}

void CFileView::OnContextMenu(CWnd* pWnd, CPoint point)
{
    CTreeCtrl* pWndTree = (CTreeCtrl*) &m_wndFileView;
    ASSERT_VALID(pWndTree);

    if (pWnd != pWndTree)
    {
        CDockablePane::OnContextMenu(pWnd, point);
        return;
    }

    if (point != CPoint(-1, -1))
    {
        // Select clicked item:
        CPoint ptTree = point;
        pWndTree->ScreenToClient(&ptTree);

        UINT flags = 0;
        HTREEITEM hTreeItem = pWndTree->HitTest(ptTree, &flags);
        if (hTreeItem != NULL)
        {
            pWndTree->SelectItem(hTreeItem);
        }
    }

    pWndTree->SetFocus();
    theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EXPLORER, point.x, point.y, this, TRUE);
}

void CFileView::AdjustLayout()
{
    if (GetSafeHwnd() == NULL)
    {
        return;
    }

    CRect rectClient;
    GetClientRect(rectClient);

    int cyTlb = m_wndToolBar.CalcFixedLayout(FALSE, TRUE).cy;

    m_wndToolBar.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(), cyTlb, SWP_NOACTIVATE | SWP_NOZORDER);
    m_wndFileView.SetWindowPos(NULL, rectClient.left + 1, rectClient.top + cyTlb + 1, rectClient.Width() - 2, rectClient.Height() - cyTlb - 2, SWP_NOACTIVATE | SWP_NOZORDER);
}

void CFileView::OnProperties()
{
    AfxMessageBox(_T("Properties...."));

}

//1.树是遍历存储的,实际时update了一个序号idno,读出是按存储的顺序(idno)
//2.创建树是通过层(lev)的变化数量来寻找父节点,sibling顺序遍历存储时就确定了。
//  lev不变时是连续插入sibling节点。父节点不变
//  lev增加(只可能增加1)是在当前节点下插入子节点,父节点就是变成当前节点。
//  lev减小(按差值循环上溯父节点),在找到的父节点下插入子节点,父节点更新。
//
void CFileView::OnFileOpen()
{
    
    CString fileName;
    CString sql;
    int nrow, ncolum;
    int i, j;

    HTREEITEM hItem;
    HTREEITEM hPItem;
    HTREEITEM hRoot;

    CFileDialog dlgFile(TRUE, "DataBase File(*.db)|*.DB", "Test.db",
        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
        "DataBase File(*.db)|*.db|RTF Files (*.rtf)|*.rtf|All Files (*.*)|*.*||", NULL);


    if (IDOK == dlgFile.DoModal())
    {
        fileName = dlgFile.GetFileName();
        if (!m_SQLite.Open(fileName.GetBuffer()))
        {
            PRINT("OPEN FAILED");
            return;
        }

        PRINT("OPEN %s OK", fileName.GetBuffer());
        
        m_wndFileView.DeleteAllItems();
        sql = "select id,lev,idno,name from notesid order by idno";//lev asc, levno asc; ";
        m_SQLite.Query(sql.GetBuffer(), nrow, ncolum);

        PRINT("OPEN OK nrow=%d,ncloum=%d", nrow, ncolum);

        if (NULL != m_pFileTable)
        {
            delete[] m_pFileTable;
            m_pFileTable = NULL;
        }
        m_pFileTable = new FileTable[nrow];
        
        for (i = 1; i < nrow + 1; i++)    //第一行是字段名称
        {
            //wSQLTable.Cell[i] = new SQLCell[ncolum];
            m_pFileTable[i - 1].id = atoi(m_SQLite.m_sresult[i * ncolum + 0]);
            m_pFileTable[i - 1].lev = atoi(m_SQLite.m_sresult[i * ncolum + 1]);
            m_pFileTable[i - 1].idno = atoi(m_SQLite.m_sresult[i * ncolum + 2]);
            
            memset(m_pFileTable[i - 1].name, 0, 256);
            memcpy(m_pFileTable[i - 1].name, m_SQLite.m_sresult[i * ncolum + 3], 255);
            PRINT(m_pFileTable[i - 1].name);
        }
        int levNow = 0;
        
        HTREEITEM  hParent = NULL;
        HTREEITEM  hCurrent = NULL;
        for (i = 0; i < nrow; i++)
        {
            
            if(m_pFileTable[i].lev == levNow)
            {
                hCurrent = m_wndFileView.InsertItem(m_pFileTable[i].name, 0, 0, hParent);
                m_wndFileView.SetItemData(hCurrent, (DWORD_PTR) & (m_pFileTable[i]));
                m_pFileTable[i].hItem = hCurrent;
                if(i == 0) hRoot = hCurrent;  //第一个节点肯定时根节点
            }
            
            if(m_pFileTable[i].lev > levNow)  //子节点优先
            {
                hParent = hCurrent;  //上个节点

                hCurrent = m_wndFileView.InsertItem(m_pFileTable[i].name, 0, 0, hParent);
                m_wndFileView.SetItemData(hCurrent, (DWORD_PTR) & (m_pFileTable[i]));
                m_pFileTable[i].hItem = hCurrent;
        
                levNow = m_pFileTable[i].lev;
            }
            
            if(m_pFileTable[i].lev < levNow)
            {
                int gap = levNow - m_pFileTable[i].lev;
                for (int j = 0; j < gap; j++)
                {
                    hParent = m_wndFileView.GetParentItem(hParent);  //上个节点
                }
                
                hCurrent = m_wndFileView.InsertItem(m_pFileTable[i].name, 0, 0, hParent);
                m_wndFileView.SetItemData(hCurrent, (DWORD_PTR) & (m_pFileTable[i]));
                m_pFileTable[i].hItem = hCurrent;
                levNow = m_pFileTable[i].lev;
            }
    
        }
        m_wndFileView.Expand(hRoot, TVE_EXPAND);
    }
}


void CFileView::FindNode(HTREEITEM hItem, int id, HTREEITEM& hFindItem)
{
    
    if (!hItem)    return ;
        
    FileTable* pFileTable;
    pFileTable = (FileTable*)m_wndFileView.GetItemData(hItem);
    if (pFileTable == NULL)
    {
        PRINT(_T("<ERR> data fail! item = %s"),
                 m_wndFileView.GetItemText(hItem));
        return;
    }

    if (pFileTable->id == id)
    {
        PRINT( _T("Find id=%d,Name=%s"), 
            pFileTable->id, m_wndFileView.GetItemText(hItem).GetBuffer());

        hFindItem = hItem;
        return ;
    }
        
    HTREEITEM hChild = m_wndFileView.GetChildItem(hItem);
    FindNode(hChild, id, hFindItem);
    
    HTREEITEM hSibling = m_wndFileView.GetNextSiblingItem(hItem);
    FindNode(hSibling, id, hFindItem);
    
    return ;

}

void CFileView::OnFileOpenWith()
{
    // TODO: Add your command handler code here
    HTREEITEM htItem = m_wndFileView.GetSelectedItem();
    FileTable* pFileTable;
    pFileTable = (FileTable*)m_wndFileView.GetItemData(htItem);
    

    PRINT("id:%d-pid:%d-sid:%d-lev:%d-lno:%d",
        pFileTable->id, pFileTable->pid, pFileTable->sid,
        pFileTable->lev, pFileTable->levno);

}

void CFileView::OnDummyCompile()
{
    // TODO: Add your command handler code here
}

void CFileView::OnEditCut()
{
    // TODO: Add your command handler code here
}

void CFileView::OnEditCopy()
{
    // TODO: Add your command handler code here
    
}

void CFileView::OnEditClear()
{
    m_wndFileView.DeleteAllItems();
    
}

void CFileView::OnPaint()
{
    CPaintDC dc(this); // device context for painting

    CRect rectTree;
    m_wndFileView.GetWindowRect(rectTree);
    ScreenToClient(rectTree);

    rectTree.InflateRect(1, 1);
    dc.Draw3dRect(rectTree, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DSHADOW));
}

void CFileView::OnSetFocus(CWnd* pOldWnd)
{
    CDockablePane::OnSetFocus(pOldWnd);

    m_wndFileView.SetFocus();
}

void CFileView::OnChangeVisualStyle()
{
    m_wndToolBar.CleanUpLockedImages();
    m_wndToolBar.LoadBitmap(theApp.m_bHiColorIcons ? IDB_EXPLORER_24 : IDR_EXPLORER, 0, 0, TRUE /* Locked */);

    m_FileViewImages.DeleteImageList();

    UINT uiBmpId = theApp.m_bHiColorIcons ? IDB_FILE_VIEW_24 : IDB_FILE_VIEW;

    CBitmap bmp;
    if (!bmp.LoadBitmap(uiBmpId))
    {
        TRACE(_T("Can't load bitmap: %x\n"), uiBmpId);
        ASSERT(FALSE);
        return;
    }

    BITMAP bmpObj;
    bmp.GetBitmap(&bmpObj);

    UINT nFlags = ILC_MASK;

    nFlags |= (theApp.m_bHiColorIcons) ? ILC_COLOR24 : ILC_COLOR4;

    m_FileViewImages.Create(16, bmpObj.bmHeight, nFlags, 0, 0);
    m_FileViewImages.Add(&bmp, RGB(255, 0, 255));

    m_wndFileView.SetImageList(&m_FileViewImages, TVSIL_NORMAL);
}


HTREEITEM CFileView::AddFileName(LPCTSTR strFileName, DWORD_PTR dwData)
{
    HTREEITEM  hFileNode;

    hFileNode = m_wndFileView.InsertItem(strFileName, 0, 0, m_hNodeSrc);

    m_wndFileView.SetItemData(hFileNode, dwData);

    m_hNodeFile = hFileNode;

    return hFileNode;
}

HTREEITEM CFileView::AddNote(LPCTSTR Name, DWORD_PTR dwData)
{
    HTREEITEM  hNode;

    hNode = m_wndFileView.InsertItem(Name, 2, 2, m_hNodeFile);

    m_wndFileView.SetItemData(hNode, dwData);

    return hNode;
}

BOOL CFileView::DelFileName(HTREEITEM& hFileNode)
{
    return m_wndFileView.DeleteItem(hFileNode);
}


void CFileView::OnPopExpTest()
{
    // TODO: Add your command handler code here
    m_wndFileView.Test();
}

void CFileView::OnPopExpTest2()
{
    // TODO: Add your command handler code here
    m_wndFileView.Test2();
}

//子节点的插入
void CFileView::OnPopExpInsertchild()
{
    // TODO: Add your command handler code here
    
    HTREEITEM hItem = m_wndFileView.GetSelectedItem();
    HTREEITEM hItemNew = NULL;

    if (NULL == hItem)
    {
        PRINT("No selected");
        hItemNew = m_wndFileView.InsertItem("NewChild", 0, 0, TVI_ROOT, TVI_FIRST);
    }
    else
    {
        PRINT("Select = %s", m_wndFileView.GetItemText(hItem).GetBuffer());
        hItemNew = m_wndFileView.InsertItem("NewChild", 0, 0, hItem, TVI_FIRST);
        m_wndFileView.Expand(hItem, TVE_EXPAND);
    }
    InsertNode(hItemNew);
}

//sibling节点插入时先找到父节点,在父节点下插入子节点。
void CFileView::OnPopExpInsertsibling()
{
    // TODO: Add your command handler code here
    HTREEITEM hItem = m_wndFileView.GetSelectedItem();
    HTREEITEM hItemNew = NULL;
    HTREEITEM hPItem = NULL;

    if (NULL == hItem)
    {
        hItemNew = m_wndFileView.InsertItem("NewSibling", 0, 0, TVI_ROOT, TVI_FIRST);
    }
    else
    {
        hPItem = m_wndFileView.GetParentItem(hItem);
        hItemNew = m_wndFileView.InsertItem("NewSibling", 0, 0, hPItem, hItem);
        m_wndFileView.Expand(hPItem, TVE_EXPAND);
    }
    InsertNode(hItemNew);
}

//插入节点,直接在数据库中插入一个节点的name,
//id的类型是唯一的自动增长型,由数据自动生成。
//因为是自动增长的,所以查找最大id,读出来放在节点id数据中,用来更新
//id是唯一标识这个节点的。不能用name,name是可以相同的。
void CFileView::InsertNode(HTREEITEM hItem)
{
    if (!hItem)    return;

    CString sql;
    int nrow, ncolum;
    
    sql.Format(_T("INSERT INTO notesid(name) values('%s');"),
            m_wndFileView.GetItemText(hItem).GetBuffer());
    
    if (!m_SQLite.OnSqlExec(sql.GetBuffer()))
    {
        PRINT("OnSqlExec FAILED");
        return;
    }

    sql.Format(_T("SELECT max(id) FROM notesid;"));

    if (!m_SQLite.Query(sql.GetBuffer(), nrow, ncolum))
    {
        PRINT("Query FAILED");
        return;
    }

    
    FileTable* pData = new FileTable;

    int i, j;
    for (i = 1; i < nrow + 1; i++)    //第一行是字段名称
    {
        pData->id = atoi(m_SQLite.m_sresult[i * ncolum + 0]);
    }
            
    m_wndFileView.SetItemData(hItem, (DWORD_PTR)pData);
    pData->hItem = hItem;

    return;
}


//先删除子节点再删除当前节点,避免删掉当前节点的sibling节点
void CFileView::OnPopExpDelete()
{
    // TODO: Add your command handler code here
    PRINT("OnPopExpDelete");
    HTREEITEM hItem = m_wndFileView.GetSelectedItem();

    HTREEITEM hChild = m_wndFileView.GetChildItem(hItem);
    
    DeleteAllNodes(hChild);
    DeleteNode(hItem);
}

//通过id删除数据库中的节点
void CFileView::DeleteNode(HTREEITEM hItem)
{
    if (!hItem)    return;

    FileTable* pData = (FileTable * )m_wndFileView.GetItemData(hItem);
    
    CString sql;

    sql.Format(_T("DELETE FROM notesid WHERE id = %d;"), pData->id);

    if (!m_SQLite.OnSqlExec(sql.GetBuffer()))
    {
        PRINT("OnSqlExec FAILED");
        return;
    }

    m_wndFileView.DeleteItem(hItem);

    return;
}

//遍历时不能在遍历sibling节点前就删除当前节点了。
void CFileView::DeleteAllNodes(HTREEITEM hItem)
{
    if (!hItem)    return;
    
    HTREEITEM hChild = m_wndFileView.GetChildItem(hItem);
    DeleteAllNodes(hChild);
    //DeleteNode(hChild);
    HTREEITEM hSibling = m_wndFileView.GetNextSiblingItem(hItem);
    DeleteAllNodes(hSibling);
    DeleteNode(hItem);
    PRINT(m_wndFileView.GetItemText(hItem).GetBuffer());

    return;
}


//保存前先备份和删除旧表,然后新建新表并批量插入 
void CFileView::OnPopExpSave()
{
    if (NULL == m_SQLite.m_db)
    {
        PRINT("Fail no datebase");
        return;
    }

    CString sql;

    sql = "PRAGMA foreign_keys = 0;";
    sql += "DROP TABLE notesidbak;";
    sql += "CREATE TABLE notesidbak AS SELECT * FROM notesid;";
    sql += "DROP TABLE notesid;";
    sql += "CREATE TABLE notesid (id INTEGER,lev INTEGER,levno INTEGER,name CHAR(256));";
    
    m_strSave = "";
    HTREEITEM hItem = m_wndFileView.GetRootItem();
    m_NodeNo = 0;
    m_NodeLev = 0;
    SaveNode(hItem);  //遍历创建插入语句
    sql += m_strSave;
    sql += "PRAGMA foreign_keys = 1;";

    if (!m_SQLite.OnSqlExec(sql.GetBuffer()))
    {
        PRINT("OnSqlExec FAILED");
    }

    PRINT(m_strSave.GetBuffer());

}

//然后遍历插入节点,id是唯一不变的,其他都是读取树的结构数据
void CFileView::SaveNode(HTREEITEM hItem)
{
    if (!hItem)    return;

    m_NodeNo++;

    CString str;
    FileTable* pdata = (FileTable*)m_wndFileView.GetItemData(hItem);
    
    str.Format(_T("INSERT INTO notesid(id,lev,idno,name) values(%d,%d,%d,'%s');"),
        pdata->id, m_NodeLev, m_NodeNo,
        m_wndFileView.GetItemText(hItem).GetBuffer());
    m_strSave += str;

    HTREEITEM hChild = m_wndFileView.GetChildItem(hItem);
    if (hChild)
    {
        m_NodeLev++;
        if (m_NodeLev > 255)
        {
            PRINT(_T("<ERR> m_NodeLev>255(%d)!"), m_NodeLev);
            return;
        }
    }

    SaveNode(hChild);

    HTREEITEM hSibling = m_wndFileView.GetNextSiblingItem(hItem);

    if (!hSibling)    m_NodeLev--;
        
    SaveNode(hSibling);

    return;
}

//更新只是批量更新旧表,不删除
void CFileView::OnPopExpUpdate()
{
    CString sql;

    if (NULL == m_SQLite.m_db)
    {
        PRINT("Fail no datebase");
        return;
    }

    sql = "";
    m_strSave = "";

    HTREEITEM hItem = m_wndFileView.GetRootItem();
    m_NodeNo = 0;
    m_NodeLev = 0;

    UpdateNode(hItem);
    sql += m_strSave;
        
    if (!m_SQLite.OnSqlExec(sql.GetBuffer()))
    {
        PRINT("OnSqlExec FAILED");
    }

    PRINT(m_strSave.GetBuffer());

}

//
//更新数据库时,m_NodeNo是节点的遍历顺序,也就是idno字段。
//确定了sibling的顺序,可按顺序还原。确保父节点存在。
//
void CFileView::UpdateNode(HTREEITEM hItem)
{
    if (!hItem)    return;

    m_NodeNo++;

    CString str;
    
    FileTable* pdata = (FileTable*)m_wndFileView.GetItemData(hItem);

    str.Format(_T("update notesid set lev=%d,idno=%d, name='%s' where id=%d;"),
        m_NodeLev, m_NodeNo, m_wndFileView.GetItemText(hItem).GetBuffer(),
        pdata->id);
    m_strSave += str;

    HTREEITEM hChild = m_wndFileView.GetChildItem(hItem);
    if (hChild)
    {
        m_NodeLev++;
        if (m_NodeLev > 255)
        {
            PRINT(_T("<ERR> m_NodeLev>255(%d)!"), m_NodeLev);
            return;
        }
    }

    UpdateNode(hChild);

    HTREEITEM hSibling = m_wndFileView.GetNextSiblingItem(hItem);

    if (!hSibling) m_NodeLev--;
    
    UpdateNode(hSibling);

    return;
}

void CFileView::ShowAllNodes(HTREEITEM hItem)
{
    if (!hItem)    return;

    m_NodeNo++;

    PRINT(_T("%d:%d-%s "), 
        m_NodeNo, m_NodeLev, m_wndFileView.GetItemText(hItem).GetBuffer());

    HTREEITEM hChild = m_wndFileView.GetChildItem(hItem);
    if (hChild)
    {
        m_NodeLev++;
        if (m_NodeLev > 255)
        {
            PRINT(_T("<ERR> m_NodeLev>255(%d)!"), m_NodeLev);
            return;
        }
    }
    
    ShowAllNodes(hChild);
    
    HTREEITEM hSibling = m_wndFileView.GetNextSiblingItem(hItem);
    
    if (hSibling) m_NodeLev--;
        
    ShowAllNodes(hSibling);
    
    return;
}
void CFileView::OnPopExpShowall()
{
    m_NodeNo = 0;
    m_NodeLev = 0;

    HTREEITEM hItem = m_wndFileView.GetRootItem();
    ShowAllNodes(hItem);
}

 

标签:SQLite,MFC,pFileTable,树结构,void,HTREEITEM,CFileView,hItem,wndFileView
来源: https://www.cnblogs.com/xgz21/p/16455736.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有