程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> VC操作SQL Server主從表

VC操作SQL Server主從表

編輯:關於VC++

工作之余,用VC作了一個小程序,是VC+SQL server模式的,程式內容比較簡單,主要設及以下內容:

窗口如何分割;

多視圖之間如何通信;

列表視圖的操作及事件處理;

樹形控件的操作及事件處理,利用遞歸根據數據庫動態生成目錄;

實現主從表的顯示 以下對程序細節稍作一下說明;

一、窗口如何分割

切分窗口既適用於SDI應用程序,也適宜於MDI應用程序。它通常駐是以類 CSplitterWnd來表示,對 Windows 來說,CSplitterWnd 是一個真正的窗口,它完全占用框架窗口的客戶區域而視圖占用切分窗口的窗格區域。 動態切分與靜態切分 動態切分允許用戶須任何時候對窗口進行切分,用戶既可以通過選取菜單也可以通過拖動滾動條中的切分框來進行切分。動態切分窗口使用的是一個視圖類。 靜態切分,當窗口第一次被創建時,窗格就已經被切他好了,它們不能再被改變。用戶可以移動窗格邊框,但此時不能再對窗口進行合並或再劃分。靜態切分窗口允許使用多個視圖類,並且可以創建時對這些視圖類進行配置。在靜態切分窗口中,每個窗格都有自己的滾動條。 動態切分比較簡單,不實用,下面看靜態切分。

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
   CRect rect;
   GetClientRect(&rect);
   m_wndSplitter1.CreateStatic(this,1,2);
   m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CClassTreeView),CSize(150,150),pContext);
   m_wndSplitter2.CreateStatic(&m_wndSplitter1,
   2,1,WS_CHILD|WS_VISIBLE,
   m_wndSplitter1.IdFromRowCol(0,1));

   m_wndSplitter2.CreateView(1,0,RUNTIME_CLASS(CDagDetialView),CSize(0,0),pContext);
   m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CDagView),CSize(0,0),pContext);
   m_wndSplitter2.SetRowInfo(0,rect.Height()/2,0);
   return true;
  //重載時不能調用基類的OnCreateClient()
}

以上是本程序DEMO使用的方法。關於切分詳細信息,請查閱MSDN.

二、多視圖之間的通信

本程序demo使用了三個視圖類,Winzard生成了一個,其余的是我加的。關於多視圖之間的通信主要是茯得你要訪問的視圖類的pointer,如何茯得?有兩種方法1,通過視圖類(如果有多個視圖共享一個文檔類的話)2.通過主框架茯得。由於我的程式就一個文檔類,其他視圖類是獨立的,所以就采用第二種方法了。

以下代碼是茯得CDagDetialView類指針的示例,其余類同。

CMainFrame* pFrame=static_cast<CMainFrame*>(AfxGetMainWnd());//茯得主框架
CDagDetialView* pDagDetialView =
static_cast<CDagDetialView*>(pFrame->m_wndSplitter2.GetPane(1,0));

以上有一點,我覺得最好采用以上形式,雖說通過C的強制轉換語法也行,但最好還是使用C++的語法比較好。

茯得視圖指針後你就可以do anything that you want to do

順便說一下,通信細節有一些牽連到效率的地方,一定要妥善處理。上面的demo程式,沒有考慮過多。因為我覺得這比較適合大家看明白意思,如果程式模塊分散開來,程式看起來是簡潔了不少,但不太方便看清程序流程。請見諒。

三、列表視圖的操作及事件處理

說句實話,列表的屬性參數很多,標准的、擴展的風格參數一大堆,看看那些英文文檔,在其中苦苦搜尋,找一條自己需要的特性,其中的滋味別提了。還好我很有耐心:)熟練了就好了,都記住了一大半,還怕什麼。列表控件顯示數據,要用LVS_REPORT風格,比較好看,就像DataGrid一樣。設置窗口風格需要用SetWindowLong這個API函數。這個函數是通用的。參數也一大堆。處理列表的單擊事件即是處理消息NM_CLICK,處理選擇改變時的事件即是處理LVN_ITEMCHANGED,不同的消息可能參數不同,需區別對待。

void CDagView::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
   NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
   // TODO: Add your control notification handler code here
   CListCtrl& refListCtrl=GetListCtrl();
   if(pNMListView->uNewState&LVIS_SELECTED)
  …//選取列表項時,事件觸發
   pResult=0;
}

同樣的方法處理單擊,雙擊等事件,不再嗷述。

四、樹形控件的操作及事件處理,利用遞歸根據數據庫動態生成目錄

樹形控件,和列表控件一樣,在VC數據開發中有著非常重要的地位。常用來顯示分級,分類信息。其實,提到樹,腦海裡就出現一大堆樹,什麼二叉樹,查找樹,哈夫曼樹等一大堆,也就想起了遍歷樹的常用算法—遞歸。雖然采用堆棧更有效率,但使用遞歸常使程序設計簡化。

看以下程式片段:

pRS->MoveFirst();
  _variant_t var;
  CString strTableName,strTableCode;
  HTREEITEM hChildItem;
  while(!pRS->adoEOF)
  {
    var=pRS->GetCollect("menucode");
    if(var.vt != VT_NULL)
      strTableCode = (LPCSTR)_bstr_t(var);

    //此即函數遞歸出口
    if(!strTableCode.Find(strParent,0) &&
                      strTableCode.GetLength()==strParent.GetLength()+2)
    {
      hChildItem=refTree.InsertItem(strTableName,hTreeNode,TVI_LAST);
      InitTree(refTree,hChildItem,strTableCode);
    }
    pRS->MoveNext();
  }

遞歸時充分利用樹形結構的特點。然後結合遞歸思想,融合在一起,就行了。這裡就是理論和實際的結合點。不同的開發語言提供的操作接口是不同的,如Delphi、.dotnet。我呈在在.net也實現了一個類似的樹,算法思想一樣,只是具體操作不同,因為dotnet提供的接口不同。

樹形控件的事件處理:

void CClassTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  // TODO: Add your control notification handler code here
  CTreeCtrl& refTreeCtrl=GetTreeCtrl();
  HTREEITEM hSelected=pNMTreeView->itemNew.hItem;
  if(hSelected!=NULL)
  {
    m_strMenuName=refTreeCtrl.GetItemText(hSelected);
    if(AfxGetMainWnd()->IsWindowEnabled())
    UpdateDagView();

  }
  //-----------
  *pResult = 0;
}

五、實現主從表的顯示

由於我假設不知道數據庫中有多少字段,字段名都是不知道的。所有都動態生成。所以首先要檢索主鍵。把主鍵檢索出來以後,然後得到列表當前選擇行的對應於主鍵列的數據。然後以這些主鍵列的值當作檢索條件檢索從表的數據(從表的主鍵一定多於主表)最後將結果顯示出來。看起來過程也挺簡單的,如果用dotnet中DataGrid做的話,太簡單了是吧,但VC操作起來,就有點麻煩了。就拿從列表取當前選擇行的主鍵列的數據的話,和dotnet一比,就知道VC麻煩在哪兒了。(不過我還是比較喜歡VC,嘿嘿)。一個DataGrid,如果我知道了列名,又茯取了當前行的行號(CurrentRowIndex)

如果你後台是直接綁定的一個DataTable,就可以直接取得這個值:myTable.Rows[CurrnetRowIndex][“pkey1”].ToString();當然如果你後面不是直接綁定一個DataTable,而是一個結果經過慮後的結果,那麼可能會稍煩瑣一點。這裡不對這種情況進行計討論。下面看一下VC下是怎麼處裡的,(如果有更好的方法,請通知我,先謝了)

int CDagView::GetColumnIndex(CListCtrl &ref,LPCTSTR strCol)
{
   CHeaderCtrl * pHeader=ref.GetHeaderCtrl();
   int nCount=pHeader->GetItemCount();
   TCHAR lpBuffer[256];
   bool  fFound = false;
   HDITEM hdi;
   hdi.mask = HDI_TEXT;
   hdi.pszText = lpBuffer;
   hdi.cchTextMax = 256;
   int index=-1;
   for (int i=0;!fFound && (i < nCount);i++)
   {
     pHeader->GetItem(i, &hdi);

     if (strcmp(hdi.pszText, strCol) == 0)
     {
       index=i;
       fFound = true;
     }
   }
   return index;
}
iSubItem=GetColumnIndex(refListCtrl);
CString strValue=refListCtrl.GetItemText(iCurrent,iSubItem);

先取得列號然後取得行號,最後取這個值......好了,就寫這麼多吧,具體細節再看代碼。

六、結束語

其實這個程式比較簡單,在Windows 2k下調試通過!就寫到這裡吧,不足之處,見諒!有時候,再好的技術,如果缺乏有效的示例,也會變得晦澀難懂。像本文中的列表、樹形控件參數很多,使用VC++雖然說可以發揮出他們最強勁的功能,但是有一部分參數,在MSDN中只是簡要介紹,沒有詳細的示例說明(我猜:微軟內部肯定有更加詳細的示例及文檔,或者說叫引擎,不對外公布)這就要靠廣大程序員的努力探索了,知識共享,大家共同進步。

本文配套源碼

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