基于MFC对话框的GridfCtrl显示SQL表格

本文介绍如何使用MFC中的GridCtrl控件显示SQL数据库中的表格数据,并提供了从数据库读取数据到GridCtrl的具体步骤及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mfc对话框显示表格有那么几种方法:使用微软的CListCtrl控件,使用Joe和chris编写的GridCtrl控件等。

GridCtrl更专业些。这款控件出世将近20年,使用也很广泛。但是用于显示SQL表格的帮助文件较少。在网上找到10年前Mazdak写的教程,尝试并实现,对他表示感谢。
Mazdak-Binding MFC Grid to database

一、首先介绍GridCtrl应用于简单表格的建立。

GridCtrl原文教程和源码地址

1、新建MFC对话框 IDD_DataOut,类名CDataOut,生成DataOut.h和DataOut.cpp;
2、将GridCtrl.cpp、GridCtrl.h等文件加到工程中,并编译
添加GridCtrl_src下文件后,VS2010编译报错:
gridctrltest\memdc.h(26): error C2011: “CMemDC”:“class”类型重定义
解决办法重命名CMemDC为GCMemDC,记得同时修改MemDC.h及GridCtrl.cpp所有用到的CMemDC项。
编译通过。
3、在对话框IDD_DataOut中增加Custom Control,如下

这里写图片描述
控件属性如下,Class项要写MFCGridCtrl
控件属性
4、在文件DataOut.h中增加成员

#pragma once
#include "GridCtrl.h"
class CDataOut : public CDialogEx
{
    DECLARE_DYNAMIC(CDataOut)

public:
    CDataOut(CWnd* pParent = NULL);   // 标准构造函数
    virtual ~CDataOut();
    CGridCtrl m_pGrid;
    void GridCtrlInit();
// 对话框数据
    enum { IDD = IDD_DataOut };

5、在DataOut.cpp文件里的函数DoDataExchange增加映射:

void CDataOut::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_datagrid, m_pGrid);
}

6、在对话框初始化函数中实现控件的显示,若没有控件显示程序,整个对话框都无法显示,这点困扰了我好长时间。

BOOL CDataOut::OnInitDialog()
    {
     CDialogEx::OnInitDialog();

    // TODO:  在此添加额外的初始化
     SetIcon(m_hIcon, TRUE);   // 设置大图标
     SetIcon(m_hIcon, FALSE);  // 设置小图标
     GridCtrlInit();//调用函数
     return TRUE;  // return TRUE unless you set the focus to a control
    // 异常: OCX 属性页应返回 FALSE
    }

调用函数如下:

void CDataOut::GridCtrlInit()
    {
    m_pGrid.SetEditable(true);
    m_pGrid.SetTextBkColor(RGB(0xFF, 0xFF, 0xE0));//黄色背景
    m_pGrid.SetRowCount(8); //初始为10行
    m_pGrid.SetColumnCount(8); //初始化为11列
    m_pGrid.SetFixedRowCount(1); //表头为一行
    m_pGrid.SetFixedColumnCount(1); //表头为一列
    for (int row = 0; row < m_pGrid.GetRowCount(); row++)
        for (int col = 0; col < m_pGrid.GetColumnCount(); col++)
        { 
            //设置表格显示属性
            GV_ITEM Item; 
            Item.mask = GVIF_TEXT|GVIF_FORMAT;
            Item.row = row;
            Item.col = col;
            m_pGrid.SetRowHeight(row,25); //设置各行高          
            m_pGrid.SetColumnWidth(0,64); //设置0列宽 
            m_pGrid.SetColumnWidth(col,64); //设置各列宽
            if(row==0&&col==0) //第(00)格
            {
                Item.nFormat = DT_CENTER|DT_WORDBREAK;
                Item.strText.Format(_T("报表显示"),col);
            }
            else if (row < 1) //设置0行表头显示
            {        
                Item.nFormat = DT_CENTER|DT_WORDBREAK;
                Item.strText.Format(_T(" 项目%d"),col);
            }
            else if (col < 1) //设置0列表头显示
            {
                if(row< m_pGrid.GetRowCount())
                {
                    Item.nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
                    Item.strText.Format(_T("第%d次"),row);
                }
            }
            else
            {
                Item.nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
                Item.strText.Format(_T(""),2);
            }
            m_pGrid.SetItem(&Item); 
        }
    }

二、显示SQL表格并复制某些行记录

前三步骤同上。
4、在DataOut.h中

#include "GridCtrl_src\GridCtrl.h"
#include "math.h"
// CDataOut 对话框

class CDataOut : public CDialogEx
{
    DECLARE_DYNAMIC(CDataOut)

public:
    CDataOut(CWnd* pParent = NULL);   // 标准构造函数
    virtual ~CDataOut();

//  CDataOut* m_dataout;

    void GridCtrlInit();
// 对话框数据
    enum { IDD = IDD_DataOut };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    HICON m_hIcon;
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    CGridCtrl m_pGrid;
    CString m_strDataSource;
    CString m_strQuery;

    int FillGrid(void);

    _RecordsetPtr pRecordset;
private:
    void CheckVariant(_variant_t vtFld,int propType);
    double dval;
    long lval;
    CY cyVal;
    CList<int,int> m_listIntegerCol;
    CList<int,int> m_listDateCol;
    _bstr_t str;
    COleDateTime date;
    BOOL bdate;
    BOOL bCY;
    BOOL blong;
    BOOL bfloat;
public:
    afx_msg void OnBnClickedCopy();

    };

第5步同上文
6、ADO方式连接数据库,简单介绍如下:
在stdafx.h中加入:#import “c:/program files/common files/system/ado/msado15.dll” no_namespace rename (“EOF”, “adoEOF”)

在项目头文件中添加

    _ConnectionPtr  m_pConnection;      //+ ADO连接变量指针

在项目cpp文件中添加

CoInitialize(NULL);                                          //初始化Com组件
m_pConnection.CreateInstance(__uuidof(Connection)); 
    try
    {
        m_pConnection->Open("Provider=SQLOLEDB.1; Data Source=10.**.**.**\\SQLEXPRESS,1433;Database=maintenance;Persist Security Info=False;UID=sa;PWD=123456;","","",NULL);//连接字符串
        }
    catch(_com_error e)                                              //捕捉异常
    {
        AfxMessageBox(e.ErrorMessage());
    }
    CoUninitialize();                                                   //释放com组件

具体mfc连接sql中注意问题和连接字符串相关内容,后续补充补充内容链接
然后在DataOut.cpph中调用Fillgrid()函数

BOOL CDataOut::OnInitDialog()
    {
     CDialogEx::OnInitDialog();

    // TODO:  在此添加额外的初始化
     SetIcon(m_hIcon, TRUE);   // 设置大图标
     SetIcon(m_hIcon, FALSE);  // 设置小图标
    // CDataOut m_gridctrl;//定义对象

     FillGrid();//调用函数

    // GridCtrlInit();
     return TRUE;  // return TRUE unless you set the focus to a control
    // 异常: OCX 属性页应返回 FALSE
    }
int CDataOut::FillGrid(void)
{
    CString sqlStr;
    sqlStr = "select * from maintenance_record_tb";
    //+打开数据库
    pRecordset.CreateInstance(__uuidof(Recordset));

    try
    {
        pRecordset->Open((_variant_t)sqlStr,            
        theApp.m_pConnection.GetInterfacePtr(),         
        adOpenDynamic,
        adLockOptimistic,
        adCmdText);
    }
    catch(_com_error *e)
    {
        AfxMessageBox(e->ErrorMessage());
    }

    m_pGrid.DeleteAllItems();
    m_pGrid.SetListMode(true);
    m_pGrid.SetHeaderSort(true);

    try
    {
          FieldsPtr fs = pRecordset->GetFields();
          int iCol = fs->Count+1;
          m_pGrid.SetColumnCount(iCol);
          m_pGrid.SetFixedRowCount();
          m_pGrid.SetFixedColumnCount();
          m_pGrid.SetColumnWidth(0,20);
          iCol = m_pGrid.GetColumnCount();

          for(int i = 0 ; i < (int)fs->GetCount() ; i++)
          {
              _variant_t index;
              index.Clear();
              index.vt = VT_I2;
              index.iVal = i ;
              CString str = (LPSTR) fs->GetItem(index)->GetName();
              m_pGrid.SetItemText(0,i+1,str);
          }

          int iRow = 1;
          while(!pRecordset->adoEOF)
          {

            m_pGrid.InsertRow("");
            for(int i = 0 ; i < (int)fs->GetCount() ; i++)
            {
               _variant_t index;
              index.Clear();
              index.vt = VT_I2;
              index.iVal = i ;
              _variant_t vtFld;
              vtFld.Clear();
              vtFld =pRecordset->Fields->GetItem(fs->GetItem(index)->GetName())->Value;
              int propType = (int)fs->GetItem(index)->GetType();

              bdate=false;
              blong = false;
              bfloat = false;
              bCY= false;

              CheckVariant(vtFld,propType);//下文实现

              if(blong!=false || bfloat!=false)
              {
                CString str1;
                if(blong)
                {
                    m_pGrid.SetCellType(iRow,i+1, RUNTIME_CLASS(CGridCell));
                    str1.Format("%d",lval);
                }

                else
                    str1.Format("%f",dval);


                m_pGrid.SetItemText(iRow,i+1,str1);
                m_listIntegerCol.AddTail((i+1));
              }
              else if(bdate)
              {
                  CString str1 = date.Format(_T("%d/ %m/ %Y"));
                  m_listDateCol.AddTail(i+1);
                  m_pGrid.SetItemText(iRow,i+1,str1);
              }
              else if(bCY)
              {
                  COleCurrency cur = (COleCurrency)cyVal;
                  m_listIntegerCol.AddTail((i+1));
                 m_pGrid.SetItemText(iRow,i+1,cur.Format());
              }
              else 
              {
                  m_pGrid.SetItemText(iRow,i+1,str);
                  str = "";
              }


            }
            iRow++;

            pRecordset->MoveNext();
          }

    }
    catch(_com_error e)
    {
        AfxMessageBox(e.ErrorMessage());
        return E_FAIL;
    }
    return 0;


}

CheckVariant()函数

void CDataOut::CheckVariant(_variant_t vtFld, int propType)
{
              switch(vtFld.vt)
              {
                case VT_CY:
                {
                    cyVal = vtFld.cyVal;
                    bCY = true;
                    break;
                }
                case VT_R4:
                {
                    dval = vtFld.fltVal;
                    bfloat=true;
                break;
                }
                case VT_R8:
                {
                    dval = vtFld.dblVal;
                    bfloat=true;
                break;
                }
                case VT_DECIMAL:
                {
                    if(adDecimal==propType || adNumeric==propType)
                    {
                        dval = vtFld.decVal.Lo32;
                        dval *= (vtFld.decVal.sign == 128)? -1 : 1;
                        dval /= pow(10.0, vtFld.decVal.scale); 
                        bfloat=true;
                    }
                    else
                    {
                        lval = vtFld.decVal.Lo32;
                        lval *= (vtFld.decVal.sign == 128)? -1 : 1;
                        lval /= pow(10*1.0, vtFld.decVal.scale); 
                        blong=true;
                    }

                break;
                }
                case VT_UI1:
                {
                    lval = vtFld.iVal;
                    blong=true;
                break;
                }
                case VT_BOOL:
                {
                    lval = vtFld.boolVal;
                    if(lval==-1)
                        lval = 1;
                    blong=true;
                break;
                }
                case VT_I2:
                {
                    lval = vtFld.iVal;
                    blong=true;
                break; 
                }
                case VT_I4:
                {
                    lval = vtFld.lVal;
                    blong=true;
                break;
                }
                case VT_INT:
                {
                    lval = vtFld.intVal;
                    blong=true;
                break;
                }
                case VT_DATE:
                {
                    date = (COleDateTime)vtFld.date;
                    bdate = true;
                break;
                }
                case VT_NULL:
                case VT_EMPTY:
                    {
                    break;
                    }
                default:
                    str = vtFld.bstrVal;
                //break;
               }

    }

记录复制函数如下,可以选中内容复制到excel中

void CDataOut::OnBnClickedCopy()
    {
    // TODO: 在此添加控件通知处理程序代码
    COleDataSource* pSource = m_pGrid.CopyTextFromGrid();
    if (!pSource)
        return;

    pSource->SetClipboard();
    MessageBox("复制成功,粘贴至别处","",0);

    }

效果图:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值