今天懷著虞城的心來探索打印CListCtrl的方法,可惜忙到現(xiàn)在被老掉牙的數(shù)據(jù)加載給絆倒。但是從中卻學(xué)到了不少新東西,以前沒有遇到過的。現(xiàn)在就寫出來和大家分享。
ODBC數(shù)據(jù)源與CListCtrl的連接已經(jīng)算是老生常談的事情了。
1、先建立數(shù)據(jù)庫(這里以一個PrintTest為數(shù)據(jù)源名來處理,該數(shù)據(jù)庫包含一張表info,里面有四個字段,ID,NAME,GROUP,AGE,只是測試用因此隨便列出幾個字段,其中ID為數(shù)字類型,其余為文本,采用Access數(shù)據(jù)庫來建立。方法就是添加一張表,然后分別對表中填充一些數(shù)據(jù),這里就不再講述!)
2、ODBC數(shù)據(jù)源與程序的連接
???a.在stdafx.h文件的尾部添加#include "afxdb.h"
???b.針對于整個工程的全局函數(shù)CDatabase db;
???c.在APP文件的初始化進(jìn)程中添加打開數(shù)據(jù)庫的語句
?????????
????CWinApp::InitInstance();????
//
此句為系統(tǒng)自動生成的;
????
if
?(
!
db.IsOpen())
????????db.Open(
"
PrintTest;
"
);
????
else
????????AfxMessageBox(
"
數(shù)據(jù)庫連接失敗!
"
);

????AfxEnableControlContainer();????
//
此句為系統(tǒng)自動生成的;
至此,與數(shù)據(jù)庫的連接基本上完成了,也正是因?yàn)檫@個db.Open("PrintTest;");才有了這篇文章。
3、向記錄集(CRecordset)填充數(shù)據(jù),在這里我們必須要談到(數(shù)據(jù)庫和記錄集對象之間的)記錄字段交換 (RFX)。(大家可以在MSDN中查閱相關(guān)信息。)現(xiàn)在只將步驟做一個簡述:
???a.在“類視圖”中添加類,然后選擇“MFC ODBC 使用者”;
???b.在向?qū)е校瑪?shù)據(jù)源按鈕后選擇“機(jī)器數(shù)據(jù)源”選擇我們設(shè)置的ODBC數(shù)據(jù)源,這里為PrintTest;確定;
???c.在彈出的對話框中選擇info表,確定;
???d.修改類名,文件名(如果有必要的話),這里改為CInfoRS,InfoRS.h,InfoRS.cpp
???e.注意下面的選擇是“動態(tài)集”,確定。(警告關(guān)閉)
這時候你可以在類向?qū)е锌吹教砑拥男骂悾珻InfoRS
4、在初始化對話框的時候進(jìn)行數(shù)據(jù)的讀入。
值得注意的是:我們剛才定義的是全局的變量,但是定義的語句是在APP文件中寫入的,因此在Dlg文件中調(diào)用的時候我們?nèi)匀恍枰ヂ暶饕幌滤侨肿兞浚簿褪菍lg來說,它是在外部已經(jīng)定義過的變量。因此在Dlg.cpp的開頭我們補(bǔ)充extern CDatabase db;
在BOOL CPrintListCtrlDlg::OnInitDialog()中添加
????
//
?TODO:?在此添加額外的初始化代碼
//
注意找到該函數(shù)中的這句話,在其后添加以下代碼
????m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);??????
//
設(shè)置ListCtrl的風(fēng)格
????
int
?nWidth
=
110
;
????m_cList.InsertColumn(
0
,
"
會員編號
"
,LVCFMT_LEFT,nWidth
*
2
/
3
);
????m_cList.InsertColumn(
1
,
"
會員姓名
"
,LVCFMT_LEFT,nWidth);
????m_cList.InsertColumn(
2
,
"
會員組織
"
,LVCFMT_LEFT,nWidth
*
3
/
2
);
????m_cList.InsertColumn(
3
,
"
年齡
"
,LVCFMT_LEFT,nWidth
/
2
);
????CInfoRS?rs(
&
db);

????UpdateList(rs);
在這個應(yīng)用程序中同樣要注意到,因?yàn)槲覀冃枰氖且粡堫愃艫ccess表的表格,而不是類似我的電腦的圖標(biāo)形式的風(fēng)格,因此我們需要在添加的ListControl的時候,將其屬性中的View設(shè)置為Report。
?UpdateList(rs);是我們自己添加的一個函數(shù),再此我再介紹一下使用類向?qū)砑雍瘮?shù)的方法。
在類視圖中,右鍵,添加->添加函數(shù),然后添加相關(guān)參數(shù),比如返回值類型,參數(shù)類型等,記得添加參數(shù)的時候按“添加”將其添加到參數(shù)列表中。
下面列出UpdateList的代碼:
void
?CPrintListCtrlDlg::UpdateList(CInfoRS
&
?rs)

{
????
int
?i
=
0
;
????CString?strID;
????rs.Open();
????m_cList.DeleteAllItems();
????
while
(
!
rs.IsEOF())

????
{
????????m_cList.InsertItem(i,
""
);
????????strID.Format(
"
%d
"
,rs.m_ID);
????????m_cList.SetItemText(i,
0
,strID);
????????m_cList.SetItemText(i,
1
,rs.m_NAME?);
????????m_cList.SetItemText(i,
2
,rs.m_GROUP);
????????m_cList.SetItemText(i,
3
,rs.m_AGE);
????????rs.MoveNext();
????????i
++
;
????}
????rs.Close();
}
至此這個程序基本上就編寫完成了,但是使用Ctrl+F5調(diào)試的時候出現(xiàn)了錯誤。錯誤具體就不再描述,只告訴解決的方法。
1、一個是CInfoRS類中一句#error Security Issue: The connection string may contain a password
解決方法:注釋掉
2、類型不匹配:
??m_cList.SetItemText(i,1,rs.m_NAME );
??m_cList.SetItemText(i,2,rs.m_GROUP);
??m_cList.SetItemText(i,3,rs.m_AGE);
將提示rs.m_NAME,rs.m_GROUP,rs.m_AGE不能從“CStringW”轉(zhuǎn)換為“LPCTSTR”
解決方法:在類視圖中定位到CInfoRS,在其變量(藍(lán)色方塊后),隨便點(diǎn)一個進(jìn)入。按以下方法修改:
//將以下代碼:
????long????m_ID;
????CStringW????m_NAME;
????CStringW????m_GROUP;
????CStringW????m_AGE;
//修改為:
????long????m_ID;
????CString????m_NAME;
????CString????m_GROUP;
????CString????m_AGE;
//即將這里的CStringW替換為CString
//其實(shí)可以注意到之前的一大段話:以下字符串類型(如果存在)反映數(shù)據(jù)庫字段(ANSI 數(shù)據(jù)類型的 CStringA 和 Unicode數(shù)據(jù)類型的 CStringW)的實(shí)際數(shù)據(jù)類型。這是為防止 ODBC 驅(qū)動程序執(zhí)行可能不必要的轉(zhuǎn)換。如果希望,可以將這些成員更改為CString 類型,ODBC 驅(qū)動程序?qū)?zhí)行所有必要的轉(zhuǎn)換。(注意: 必須使用 3.5 版或更高版本的 ODBC 驅(qū)動程序以同時支持 Unicode 和這些轉(zhuǎn)換)。
至此,編譯通過。
但是,隨后彈出錯誤:ODBC數(shù)據(jù)源不支持動態(tài)集
修正這個問題的方法有二:
一、在剛才添加的時候,將動態(tài)集(默認(rèn))改為快照,在這里,將不會出現(xiàn)錯誤。
二、令人慶幸的是我曾經(jīng)做過一個例子,里面確實(shí)是使用動態(tài)集,但并沒有出現(xiàn)這個錯誤,于是我找到了另一個程序,再次調(diào)試通過。于是就很是郁悶。于是用斷點(diǎn)調(diào)試,最終確定問題是發(fā)生在rs.Open();的位置。
于是查找MSDN發(fā)現(xiàn)(For CRecordset, the default value is CRecordset::snapshot.翻譯:對于CRecordset默認(rèn)值類對象,默認(rèn)值是 CRecordset::snapshot,也就是快照模式),而我們所用的是動態(tài)集的模式。這里可以將rs.Open();改為rs.Open(CRecordset::forwardOnly);再次編譯就可以通過了。
另外可以將最初的db.Open("PrintTest;");改為db.OpenEx("DSN=PrintTest;");就可以解決問題了。這其中的奧妙就不是很清楚,只能當(dāng)作經(jīng)驗(yàn)來和大家分享一下。也希望有知道的人能夠留言告訴我。謝謝先~!
以下將本示例的代碼以及數(shù)據(jù)庫打包供大家學(xué)習(xí)下載!
http://www.shnenglu.com/Files/mymsdn/PrintListCtrl.rar
附錄:
1、編譯調(diào)試:Visual Studio.NET 2003中文版
2、在主對話框需要添加一個ListControl的控件。(下載的代碼可能還多包括一個打印控件,但該控件的功能并未實(shí)現(xiàn),只是一個預(yù)留的測試功能。大家自行練習(xí)的時候可以不添加該按鈕。)