zoukankan      html  css  js  c++  java
  • CListCtrl(List Control)绑定ODBC数据库的方法。(附加:CRecordset::Open()与CRecordset::OpenEx()区别之真实体验~)

    今天怀着虞城的心来探索打印CListCtrl的方法,可惜忙到现在被老掉牙的数据加载给绊倒。但是从中却学到了不少新东西,以前没有遇到过的。现在就写出来和大家分享。
    ODBC数据源与CListCtrl的连接已经算是老生常谈的事情了。
    1、先建立数据库(这里以一个PrintTest为数据源名来处理,该数据库包含一张表info,里面有四个字段,ID,NAME,GROUP,AGE,只是测试用因此随便列出几个字段,其中ID为数字类型,其余为文本,采用Access数据库来建立。方法就是添加一张表,然后分别对表中填充一些数据,这里就不再讲述!)
    2、ODBC数据源与程序的连接
       a.在stdafx.h文件的尾部添加#include "afxdb.h"
       b.针对于整个工程的全局函数CDatabase db;
       c.在APP文件的初始化进程中添加打开数据库的语句
             

        CWinApp::InitInstance();     // 此句为系统自动生成的;

        
    if  ( ! db.IsOpen())
            db.Open(
    " PrintTest; " );
        
    else
            AfxMessageBox(
    " 数据库连接失败! " );

        AfxEnableControlContainer();    
    // 此句为系统自动生成的;

    至此,与数据库的连接基本上完成了,也正是因为这个db.Open("PrintTest;");才有了这篇文章。
    3、向记录集(CRecordset)填充数据,在这里我们必须要谈到(数据库和记录集对象之间的)记录字段交换 (RFX)。(大家可以在MSDN中查阅相关信息。)现在只将步骤做一个简述:
       a.在“类视图”中添加类,然后选择“MFC ODBC 使用者”;
       b.在向导中,数据源按钮后选择“机器数据源”选择我们设置的ODBC数据源,这里为PrintTest;确定;
       c.在弹出的对话框中选择info表,确定;
       d.修改类名,文件名(如果有必要的话),这里改为CInfoRS,InfoRS.h,InfoRS.cpp
       e.注意下面的选择是“动态集”,确定。(警告关闭)
    这时候你可以在类向导中看到添加的新类,CInfoRS
    4、在初始化对话框的时候进行数据的读入。
    值得注意的是:我们刚才定义的是全局的变量,但是定义的语句是在APP文件中写入的,因此在Dlg文件中调用的时候我们仍然需要去声明一下它是全局变量,也就是对Dlg来说,它是在外部已经定义过的变量。因此在Dlg.cpp的开头我们补充extern CDatabase db;
    在BOOL CPrintListCtrlDlg::OnInitDialog()中添加

         //  TODO: 在此添加额外的初始化代码 // 注意找到该函数中的这句话,在其后添加以下代码
        m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);       // 设置ListCtrl的风格
         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);


    在这个应用程序中同样要注意到,因为我们需要的是一张类似Access表的表格,而不是类似我的电脑的图标形式的风格,因此我们需要在添加的ListControl的时候,将其属性中的View设置为Report。

     UpdateList(rs);是我们自己添加的一个函数,再此我再介绍一下使用类向导添加函数的方法。
    在类视图中,右键,添加->添加函数,然后添加相关参数,比如返回值类型,参数类型等,记得添加参数的时候按“添加”将其添加到参数列表中。
    下面列出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调试的时候出现了错误。错误具体就不再描述,只告诉解决的方法。
    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”转换为“LPCTSTR”
    解决方法:在类视图中定位到CInfoRS,在其变量(蓝色方块后),随便点一个进入。按以下方法修改:
    //将以下代码:
        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


    //其实可以注意到之前的一大段话:以下字符串类型(如果存在)反映数据库字段(ANSI 数据类型的 CStringA 和 Unicode数据类型的 CStringW)的实际数据类型。这是为防止 ODBC 驱动程序执行可能不必要的转换。如果希望,可以将这些成员更改为CString 类型,ODBC 驱动程序将执行所有必要的转换。(注意: 必须使用 3.5 版或更高版本的 ODBC 驱动程序以同时支持 Unicode 和这些转换)。
    至此,编译通过。
    但是,随后弹出错误:ODBC数据源不支持动态集
    修正这个问题的方法有二:
    一、在刚才添加的时候,将动态集(默认)改为快照,在这里,将不会出现错误。
    二、令人庆幸的是我曾经做过一个例子,里面确实是使用动态集,但并没有出现这个错误,于是我找到了另一个程序,再次调试通过。于是就很是郁闷。于是用断点调试,最终确定问题是发生在rs.Open();的位置。
    于是查找MSDN发现(For CRecordset, the default value is CRecordset::snapshot.翻译:对于CRecordset默认值类对象,默认值是 CRecordset::snapshot,也就是快照模式),而我们所用的是动态集的模式。这里可以将rs.Open();改为rs.Open(CRecordset::forwardOnly);再次编译就可以通过了。
    另外可以将最初的db.Open("PrintTest;");改为db.OpenEx("DSN=PrintTest;");就可以解决问题了。这其中的奥妙就不是很清楚,只能当作经验来和大家分享一下。也希望有知道的人能够留言告诉我。谢谢先~!


    以下将本示例的代码以及数据库打包供大家学习下载!
    http://www.cppblog.com/Files/mymsdn/PrintListCtrl.rar

    附录:
    1、编译调试:Visual Studio.NET 2003中文版
    2、在主对话框需要添加一个ListControl的控件。(下载的代码可能还多包括一个打印控件,但该控件的功能并未实现,只是一个预留的测试功能。大家自行练习的时候可以不添加该按钮。)
    3、本文同步发布于本人的另外一个BLOG,www.cppblog.com/mymsdn

  • 相关阅读:
    vmware ubuntu 异常关机无法连接到网络
    Speed up GCC link
    常用的一些解压命令
    Log4j 漏洞复现
    Test Case Design method Boundary value analysis and Equivalence partitioning
    CCA (Citrix Certified Administrator) exam of “Implementing Citrix XenDesktop 4”
    What is Key Word driven Testing?
    SAP AGS面试小结
    腾讯2013终端实习生一面
    指针的引用
  • 原文地址:https://www.cnblogs.com/volnet/p/506988.html
Copyright © 2011-2022 走看看