您的位置:首页 > 数据库

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

2017-01-12 21:31 232 查看
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) //第(0,0)格
{
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);

}


效果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Gridctrl sql mfc