首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

TreeCtrl + DAO 實現資料庫分層瀏覽:主從表同步顯示架構

     編輯:關於VC++

架構總覽

  • **單文檔 MFC**,View 繼承 `CFormView`
  • **DAO 連線 Access**,`CShengSet` 繼承 `CDaoRecordset`
  • **分割視窗**:左側 `CPppView` (TreeCtrl 省份清單),右側 `CShengView` (記錄明細)
  • **即時同步**:`SetTimer` 每 10ms 掃描 Tree 選取項,自動 `Requery` 右側記錄集

關鍵實作步驟

1. 標頭檔引入 DAO 支援

// Stdafx.h
#include <afxdao.h> // 關鍵:DAO 類別定義

2. Document 與 View 持有 Recordset 指標

// PppDoc.h
#include "ShengSet.h"
public: CShengSet m_ShengSet;

// PppView.h
#include "ShengSet.h"
public: CShengSet* m_ShengSet;

3. OnInitialUpdate 建立 Tree 根節點與省份節點

void CPppView::OnInitialUpdate() {
    CFormView::OnInitialUpdate();
    CPppDoc* pDoc = (CPppDoc*)GetDocument();
    m_ShengSet = &pDoc->m_ShengSet;
    
    TV_INSERTSTRUCT tv; tv.hParent = NULL;
    tv.item.mask = TVIF_TEXT; tv.item.pszText = _T("全國");
    HTREEITEM hDad = m_treectrl.InsertItem(&tv); // 根節點
    
    if (m_ShengSet->IsOpen()) m_ShengSet->Close();
    m_ShengSet->Open(); m_ShengSet->MoveFirst();
    
    CString c1; char buff[80];
    while (!m_ShengSet->IsEOF()) {
        c1 = m_ShengSet->m_column1; // 省份名稱欄位
        wsprintf(buff, _T("%s"), c1);
        tv.item.pszText = buff; tv.hParent = hDad;
        m_treectrl.InsertItem(&tv);
        m_ShengSet->MoveNext();
    }
}

4. MainFrame 分割視窗建立雙 View

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) {
    if (!m_wndSpMain.CreateStatic(this, 1, 2)) return FALSE;
    if (!m_wndSpMain.CreateView(0, 0, RUNTIME_CLASS(CPppView), CSize(180,200), pContext)) return FALSE;
    if (!m_wndSpMain.CreateView(0, 1, RUNTIME_CLASS(CShengView), CSize(100,100), pContext)) return FALSE;
    return TRUE;
}

5. Tree 選取變更通知 Document

void CIdView::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult) {
    NM_TREEVIEW* pNM = (NM_TREEVIEW*)pNMHDR;
    CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem(IDC_TREE1);
    HTREEITEM hSel = pNM->itemNew.hItem;
    CPppDoc* pDoc = (CPppDoc*)GetDocument();
    
    if (hSel) {
        HTREEITEM hParent = pTree->GetParentItem(hSel);
        pDoc->Name = pTree->GetItemText(hSel); // 寫入 Document 共享變數
    }
    *pResult = 0;
}

6. 右側 View 定時器輪詢 Document.Name 並 Requery

void CShengView::OnInitialUpdate() {
    CRecordView::OnInitialUpdate();
    SetTimer(1, 10, NULL); // 10ms 間隔
}

void CShengView::OnTimer(UINT nIDEvent) {
    CPppDoc* pDoc = (CPppDoc*)GetDocument();
    if (m_pSet->IsOpen()) {
        char filter[60];
        wsprintf(filter, _T("[省].省名稱='%s'"), pDoc->Name);
        m_pSet->m_strFilter = filter;
        m_pSet->Requery();
        UpdateData(FALSE); // DDX 更新控制項
    }
}

優缺點分析

優點缺點
架構清晰:Tree 做導覽,Form 做明細10ms Timer 輪詢浪費 CPU,建議改用 `TVN_SELCHANGED` 直接通知
DAO 簡單易用,適合 AccessDAO 不支援新版 Access,長期維護風險
Document 做資料中介,解耦 View單表設計,無主從關聯 (如縣市/鄉鎮)
分割視窗標準 MFC 寫法硬編碼欄位名 `m_column1`,缺乏泛用性

改進建議

  1. 移除 Timer,在 `OnSelchangedTree1` 中直接呼叫右側 View 的 `RefreshData(pDoc->Name)`
  2. 改用 ADO + `OpenSchema` 動態取得欄位,支援任意資料表
  3. 擴充 Tree 為多層 (省->縣->鄉),對應多層 `m_strFilter`
  4. 右側改用 `CListCtrl` + 動態欄位,而非固定 DDX 控制項
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved