MFC ODBC数据库操作编程(二)

5. 编写报表向导操作代码

报表向导操作包括三个步骤:报表字段的选择、格式的设置以及设置信息的确认,因此制作向导时需要三个对话框。6.3.2节已经完成了报表向导的界面设计,下面我们首先介绍PropertySheetPropertyPage的创建方法,然后分别介绍三个步骤的实现代码。

·       创建报表向导的CPropertySheet

创建CPropertySheet类的操作步骤:

(1) 执行菜单命令“Insert>New Class…,VC++弹出“New Class 对话框,如图6-18所示。

6-18  New Class对话框

(2) 在“New Class 对话框里保持Class Type项为MFC Class,在Name编辑框里输入“CReportWizard”,然后在Base Class下拉列表框里选择派生的父类CPropertySheet,如图6-19所示。

(3) 单击对话框的OK按钮,VC++CReportWizard类添加到工程里。此后,我们就可以在这个类里添加PropertyPage了。在后面我们完成了所有的PropertyPage创建以后,我们将在该类的实现代码里添加PropertyPage插入操作。

·       创建报表向导的CPropertyPage

6-19  设置派生的类名称与父类

这里需要创建三个CPropertyPage类,分别代表IDD_WZDFIELDIDD_WZDFORMATIDD_WZDPREVIEW对话框。这三个类的名称分别是CReportWzdFieldCReportWzdFormatCReportWzdPreview,它们的创建方法是相同的,这里只介绍CReportWzdField类的创建方法。

操作步骤:

(1) 执行菜单命令“Insert>New Class…,VC++弹出“New Class 对话框,如图6-18所示。

(2) 在“New Class 对话框里保持Class Type项为MFC Class,在Name编辑框里输入“CReportWzdField”,然后在Base Class下拉列表框里选择派生的父类CPropertyPage,在Dialog ID组合框里选择IDD_WZDFIELDS项,如图6-20所示。注意,在创建CReportWzdFormat类时需要选择IDD_WZDFORMAT,在 创建CReportWzdPreview类时需要选择IDD_WZDPREVIEW

6-20  设置派生的类名称与父类

(3) 单击对话框的OK按钮,VC++CReportWzdField类添加到工程里。

·       编写报表向导CPropertySheet类的实现代码

CPropertySheet类的实现代码主要是在类的构造函数里将三个PropertyPage插入到PropertySheet里,同时设置PropertySheet为向导方式。我们首先在ReportWizard.h文件里添加下面的头文件引用代码:

#include "ReportWzdField.h"

#include "PreviewWnd.h"

#include "ReportWzdPreview.h"

然后在类的声明代码里添加如下声明代码:

public:

         CReportWzdField m_Page1;

         CReportWzdFormat m_Page2;

         CReportWzdPreview m_Page3;

在构造函数里,我们添加如下实现代码:

         AddPage(&m_Page1);

         AddPage(&m_Page2);

         AddPage(&m_Page3);

                   SetWizardMode();

前三个函数将三个PropertyPage插入到PropertySheetSetWizardMode()函数设置PropertySheet为向导方式。

·       编写CReportWzdField类的实现代码

(1) 首先需要创建类里与对话框中控件相关联的变量,这些变量可以通过ClassWizard工具添加。通过ClassWizard工具添加变量的方法,本书已经在6.3.2节作了介绍,这里将添加变量的名称、类型、关联的控件ID及其意义罗列出来,如表6-14所示。

6-14 CReportWzdField类的变量

名称

类型

关联的控件ID

意义

m_LBFieldCandi

ClistBox

IDC_LISTPRE

候选的报表字段列表

m_LBSelected

CListBox

IDC_LISTSEL

选用的报表字段列表

m_strReportTitle

CString

IDC_MAINTITLE

报表标题

m_strFieldTitle

CString

IDC_FIELDTITLE

报表字段标题

m_strReportFooter

CString

IDC_FOOTER

报表注脚标题

m_CBPageType

CComboBox

IDC_CBPNFORMAT

页码类型列表

m_fUsePageNum

BOOL

IDC_CHKPAGENUM

是否使用页码复选框

(2) 编写OnSetActive()消息响应函数

该函数在属性页被激活时执行,将该属性页的向导按钮只显示出“下一步”,需要在该函数里添加如下代码:

   CPropertySheet* psheet = (CPropertySheet*) GetParent();  

   psheet->SetWizardButtons(PSWIZB_NEXT);

SetWizardButtons()的作用即是令本属性页的向导按钮只显示“下一步”。

(3) 编写属性页的OnInitDialog()函数

该函数实现本属性页的初始化操作。初始化时,需要将当前显示在视图里的报表信息字段名称罗列在候选列表框里,实现代码如下:

         if(!m_pCommonRS->IsOpen()) return TRUE; 

         int nFieldCount = m_pCommonRS->GetODBCFieldCount();            

         m_LBFieldCandi.ResetContent();

         CODBCFieldInfo fieldinfo;

         for(int n=0;n

                 m_pCommonRS->GetODBCFieldInfo(n, fieldinfo);

                 m_LBFieldCandi.InsertString(-1, fieldinfo.m_strName);

         }

         UpdateData(FALSE);

代码通过m_pCommonRS实例的GetODBCFieldInfo函数获取记录集的字段信息。

(4) 编写选择按钮“>”的响应函数OnSelect()

可以通过ClassWizard工具为ID_SELECT按钮添加消息响应函数,使用ClassWizard工具为按钮添加消息响应函数的方法,本书在6.3.2的第5节已经作了介绍,这里不再赘述。该函数实现将候选列表里的字段送到选用字段列表里,它的实现代码如下:

         UpdateData();

         CString strFieldName;

         UINT nSel = m_LBFieldCandi.GetCurSel();

         if(nSel == LB_ERR) return;

         int nSelected;

         m_LBFieldCandi.GetText(nSel, strFieldName);

         nSelected = m_LBSelected.AddString(strFieldName);

         m_LBFieldCandi.DeleteString(nSel);

         m_saFieldTitle.Add(strFieldName);

         UpdateData(FALSE);

代码首先使用UpdateData()函数将界面上输入的变量内容保存到变量里,然后取m_LBFieldCandi控件的当前选择项索引,并通过该索引将项的文本保存到strFieldName变量里,接下来将该文本作为LBSelected`控件的一个项添加进去,并删除m_LBFieldCandi控件的选择项。变量m_saFieldTitle是存放字段标题的CstringArray类型变量,这里需要为该变量添加一个新元素。最后再次调用UpdateData()函数将变量内容显示到界面上。

(5) 编写选择按钮“<”的响应函数OnDeselect()

同样使用ClassWizard工具为ID_DESELECT按钮添加消息响应函数OnDeselect(),该函数将选用字段列表里的选择项“删除”并送回候选字段列表里,它的实现代码如下:

         UpdateData();    

         CString strFieldName;

         UINT nSel = m_LBSelected.GetCurSel();

         if(nSel == LB_ERR) return;

         int nDeselected;

         m_LBSelected.GetText(nSel, strFieldName);

         nDeselected = m_LBFieldCandi.AddString(strFieldName);

         m_LBSelected.DeleteString(nSel);

         int nArrayCount = m_saFieldTitle.GetSize();

         if(nDeselected < nArrayCount)   m_saFieldTitle.RemoveAt(nDeselected);

         m_strFieldTitle.Empty(); 

         UpdateData(FALSE); 

代码同OnSelect()函数大致相似,不同之处是,将m_LBSelected列表里的选择项删除,并将该项恢复到m_LBFieldCandi列表里,同时需要将m_saFieldTitle变量里相应的项删除。

(6) 编写选择按钮“>|”的响应函数OnSelectall ()

该函数将候选字段里的所有字段送到选用字段列表里,它的实现代码如下:

         UpdateData();

         CString strFieldName;

         UINT nCount = m_LBFieldCandi.GetCount();

         if(nCount <= 0) return;

         for(UINT iIdx = 0; iIdx

                 strFieldName.Empty();

                            m_LBFieldCandi.GetText(0, strFieldName);

                            m_LBSelected.AddString(strFieldName);

                            m_LBFieldCandi.DeleteString(0); 

                            m_saFieldTitle.Add(strFieldName);

         }

         UpdateData(FALSE);

代码同OnSelect()函数大致相似,不同之处是,使用循环将所有候选字段送到选用字段列表里。

(7) 编写选择按钮“|<”的响应函数OnDeselectall ()

该函数将选用字段里的所有字段恢复到候选字段列表里,它的实现代码如下:

         UpdateData();    

         CString strFieldName;

         UINT nCount = m_LBSelected.GetCount();

         if(nCount <= 0) return;

         for(UINT iIdx = 0; iIdx

                   strFieldName.Empty();

                   m_LBSelected.GetText(0, strFieldName);

                   m_LBFieldCandi.AddString(strFieldName);

                   m_LBSelected.DeleteString(0);      

         }

         m_saFieldTitle.RemoveAll();

         m_strFieldTitle.Empty(); 

         UpdateData(FALSE);

代码同OnDeselect()函数大致相似,不同之处是,使用循环将所有选用字段恢复到候选字段列表里。

(8) IDC_LISTSEL列表控件编写LBN_SELCHANGE消息响应函数OnSelchangeListsel(),该函数在IDC_LISTSEL列表控件选择项发生改变时执行,它的执行代码如下:

         UpdateData();

         UINT nSel = m_LBSelected.GetCurSel();

         if(nSel == LB_ERR) return;

         UINT nArrayCount = m_saFieldTitle.GetSize();

         if(nSel >= nArrayCount) return;

         CString strFieldTitle;

         strFieldTitle = m_saFieldTitle.GetAt(nSel);

         m_strFieldTitle = strFieldTitle;

         m_uSelIndex = nSel;

         UpdateData(FALSE);

代码通过取得选用字段的索引,从字段标题变量m_saFieldTitle里读取文本,并显示在IDC_FIELDTITLE编辑控件里。

(9) IDC_FIELDTITLE编辑控件编写EN_KILLFOCUS消息响应函数OnKillfocusFieldtitle (),该函数在IDC_FIELDTITLE编辑控件失去输入焦点时执行,它的执行代码如下:

         UpdateData();

         UINT nArrayCount = m_saFieldTitle.GetSize();

         if(m_uSelIndex < nArrayCount)

                           m_saFieldTitle.SetAt(m_uSelIndex, m_strFieldTitle);

代码将控件当前内容保存到字段标题变量m_saFieldTitle里。

(10) IDC_CHKPAGENUM复选控件编写BN_CLICKED消息响应函数OnChkpagenum (),该函数在IDC_CHKPAGENUM复选控件被单击时执行,它的执行代码如下:

         UpdateData();

         if(m_fUsePageNum){

                 GetDlgItem(IDC_PAGECAP)->EnableWindow(TRUE);

                            GetDlgItem(IDC_CBPNFORMAT)->EnableWindow(TRUE);

         }

         else{

                 GetDlgItem(IDC_PAGECAP)->EnableWindow(FALSE);

                            GetDlgItem(IDC_CBPNFORMAT)->EnableWindow(FALSE);

         }

代码在控件被选中时将IDC_PAGECAP标签和IDC_CBPNFORMAT列表框设置为有效,否则相反。

(11) 编写“下一步”按钮的消息响应函数OnWizardNext()

该函数在单击了“下一步”按钮时执行,它的执行代码如下:

         UpdateData();

         CReportWizard *psheet = (CReportWizard *) GetParent();  

         psheet->m_strReportTitle = m_strReportTitle;

         psheet->m_strReportFooter = m_strReportFooter;

         psheet->m_fHavePage = m_fUsePageNum;

         psheet->m_uPageType = m_CBPageType.GetCurSel();

         CString strFieldName;

         for(int i=0;i

                 m_LBSelected.GetText(i, strFieldName);

                           psheet->m_saSelectedFields.Add(strFieldName);

         }

         for(i=0;i

                            psheet->m_saSelectedFieldsTitle.Add(m_saFieldTitle.GetAt(i));

代码将当前属性页里的设置保存到CReportWizard类的相应变量里。

·       编写CReportWzdFormat类的实现代码

(1) 首先创建类里与对话框中控件相关联的变量,这些变量可以通过ClassWizard工具添加, 如表6-15所示,为添加变量的名称、类型、关联的控件ID及其意义。

6-15 CReportWzdFormat类的变量

名称

类型

关联的控件ID

意义

m_CBFontTitle

CFontCombo

IDC_CBTITLEFONT

标题字体列表

m_CBFontContentHead

CFontCombo

IDC_CBHEADFONT

字段标题字体列表

m_CBFontContent

CFontCombo

IDC_CBNORMALFONT

正文字体列表

m_CBFontFooter

CFontCombo

IDC_CBFOOTERFONT

注脚字体列表

CFontCombo类是一个第三方开发类,它的声明代码以及实现代码分别在文件FontCombo.hFontCombo.cpp里,我们只要将这两个文件添加到工程里就可以使用。使用时,需要在CFontCombo类使用的地方加入头文件,有如下代码:

#include "FontCombo.h"

(2) 编写OnSetActive()消息响应函数

该函数在属性页被激活时执行,需要该属性页的向导按钮显示出“上一步”和“下一步”,在该函数里添加如下代码:

   CPropertySheet* psheet = (CPropertySheet*) GetParent();  

   psheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);

(3) 编写属性页的OnInitDialog()函数

该函数实现本属性页的初始化操作。初始化操作包括:四个字体列表框的初始化,四个字号大小组合框的初始化,实现代码如下:

         m_CBFontTitle.SubclassDlgItem(IDC_CBTITLEFONT, this);

         m_CBFontContentHead.SubclassDlgItem(IDC_CBHEADFONT, this);

         m_CBFontContent.SubclassDlgItem(IDC_CBNORMALFONT, this);

         m_CBFontFooter.SubclassDlgItem(IDC_CBFOOTERFONT, this);

         m_CBFontFooter.Initialize();

         m_CBFontContentHead.Initialize();

         m_CBFontContent.Initialize();

         m_CBFontTitle.Initialize();

        

         int nIndex = 0;

         nIndex = m_CBFontFooter.FindStringExact(0, "宋体");

         m_CBFontFooter.SetCurSel(nIndex);

         nIndex = m_CBFontContentHead.FindStringExact(0, "宋体");

         m_CBFontContentHead.SetCurSel(nIndex);

         nIndex = m_CBFontContent.FindStringExact(0, "宋体");

         m_CBFontContent.SetCurSel(nIndex);

         nIndex = m_CBFontTitle.FindStringExact(0, "宋体");

         m_CBFontTitle.SetCurSel(nIndex);

         ((CComboBox *)GetDlgItem(IDC_CBTITLESIZE))->SetCurSel(0);

         ((CComboBox *)GetDlgItem(IDC_CBHEADSIZE))->SetCurSel(0);

         ((CComboBox *)GetDlgItem(IDC_CBNORMALSIZE))->SetCurSel(0);

         ((CComboBox *)GetDlgItem(IDC_CBFOOTERSIZE))->SetCurSel(0);

(4) IDC_CBTITLEFONT(IDC_CBNORMALFONTIDC_CBHEADFONTIDC_CBFOOTERFONTIDC_CBTITLESIZEIDC_CBNORMALSIZEIDC_ CBFOOTERSIZEIDC_CBHEADSIZE组合控件编写CBN_SELCHANGE消息响应函数OnSelchangeCbTitlefont()OnSelchangeCbNormalfont ()OnSelchangeCbheadfont ()OnSelchangeCbFooterfont ()OnSelchangeCbTitlesize ()OnSelchangeCbNormalsize ()OnSelchangeCbFootersize ()OnSelchangeCbheadsize (),这些函数在组合控件选择项发生改变时执行,都是调用RefreshDisplay()函数刷新预览区域的显示,执行代码相同,如下:

         UpdateData();

         RefreshDisplay();                 

(5) 编写RefreshDisplay()函数

该函数根据八个列表框里字体和字体大小的选择,重新显示预览内容,执行代码如下:

        // 取显示设备环境DC

         CDC *pDC = GetDlgItem(IDC_PREVIEWAREA)->GetDC();

         if(!pDC) return; 

        // 填充区域

         CRect rect;

         GetDlgItem(IDC_PREVIEWAREA)->GetClientRect(rect);

         CBrush brush;

         brush.CreateSolidBrush(RGB(255,255,255));

         pDC->FillRect(rect, &brush);

         // 显示

         CString line;        // 显示内容

         TEXTMETRIC metrics;       //Font measurements

         int y = 0;             //Current y position on report

        // 创建字体

         CFont TitleFont;          //Font for Title

         CFont HeadingFont;    //Font for headings

         CFont DetailFont;        //Font for detail lines

         CFont FooterFont;       //Font for footer lines

         // 设置TAB间隔

         int TabStops[] = {100, 275, 650};

         CString strFontName;

         CString strSize;

         UINT         uFontSize;

         CComboBox *pSizeCB;

         // 为标题设置粗体

         m_CBFontTitle.GetLBText(m_CBFontTitle.GetCurSel(), strFontName);

         pSizeCB = (CComboBox *)GetDlgItem(IDC_CBTITLESIZE);

         pSizeCB->GetLBText(pSizeCB->GetCurSel(), strSize);

         uFontSize = atoi(strSize);

         TitleFont.CreateFont(uFontSize, 0, 0, 0, FW_BOLD, FALSE, TRUE, 0,

                           ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                            DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,

                            strFontName);

         // 为字段标题设置粗体和下划线

         m_CBFontContentHead.GetLBText(m_CBFontContentHead.GetCurSel(),

                           strFontName);

         pSizeCB = (CComboBox *)GetDlgItem(IDC_CBHEADSIZE);

         pSizeCB->GetLBText(pSizeCB->GetCurSel(), strSize);

         uFontSize = atoi(strSize);

         HeadingFont.CreateFont(uFontSize, 0, 0, 0, FW_BOLD, FALSE, TRUE, 0,

                   ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                   DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,

                   strFontName);

         // 正文字体

         m_CBFontContent.GetLBText(m_CBFontContent.GetCurSel(), strFontName);

         pSizeCB = (CComboBox *)GetDlgItem(IDC_CBNORMALSIZE);

         pSizeCB->GetLBText(pSizeCB->GetCurSel(), strSize);

         uFontSize = atoi(strSize);

         DetailFont.CreateFont(uFontSize, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,

                 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                           DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,

                           strFontName);   

         // 注脚字体

         m_CBFontFooter.GetLBText(m_CBFontFooter.GetCurSel(), strFontName);

         pSizeCB = (CComboBox *)GetDlgItem(IDC_CBFOOTERSIZE);

         pSizeCB->GetLBText(pSizeCB->GetCurSel(), strSize);

         uFontSize = atoi(strSize);

         FooterFont.CreateFont(uFontSize, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,

                            ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                            DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,

                            strFontName);

        // 开始显示

         CFont* OldFont = pDC->SelectObject(&TitleFont);

         // 取显示文本尺寸

         pDC->GetTextMetrics(&metrics);

         // 计算高度

         int LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         // 显示标题

         y = 2;        

         pDC->TextOut(rect.Width()/2 - 70, y, "   ");

         // 显示列标题

         pDC->GetTextMetrics(&metrics);

         LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         y += LineHeight + 1;   //Adjust y position

         pDC->SelectObject(&HeadingFont);

         line.Format("%s\t%s\t%s","1","2","3");

         pDC->TabbedTextOut(10, y, line, 2, TabStops, 0);

         // 显示正文

         pDC->GetTextMetrics(&metrics);

         LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         y += LineHeight + 1;   //Adjust y position

         pDC->SelectObject(&DetailFont);

         line.Format("%s\t%s\t%s", "1","2","3");

         pDC->TabbedTextOut(10, y, line, 2, TabStops, 0);

         // 显示注脚

         pDC->GetTextMetrics(&metrics);

         LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         y += LineHeight + 1;   //Adjust y position

         pDC->SelectObject(&FooterFont);

         line = _T("注脚");

         pDC->TextOut(rect.Width() - 40, y, line);

         // 恢复设备环境里的字体

         pDC->SelectObject(OldFont);

上述代码首先取得显示的设备环境的显示尺寸,然后,用白色将显示区域填充;接着创建四种字体,并分别用四种字体显示与预览文本,最后恢复显示设备环境里的字体信息。这里要注意的是,TextOut()函数值将文本简单显示在指定区域,而TabbedTextOut ()函数可以显示TAB文本,即在文本里插入了TAB字符。GetTextMetrics()函数用于取得当前显示设备环境的文字尺寸。

(6) 编写“下一步”按钮的消息响应函数OnWizardNext()

该函数在单击“下一步”按钮时执行,它的执行代码如下:

         UpdateData();

         CReportWizard *psheet = (CReportWizard *) GetParent();  

         // 保存字体信息

         CString strFontName;

         m_CBFontTitle.GetLBText(m_CBFontTitle.GetCurSel(), strFontName) ;

         psheet->m_strFontTitle = strFontName;

         m_CBFontContentHead.GetLBText(m_CBFontContentHead.GetCurSel(),

                                                                                          strFontName) ;

         psheet->m_strFontContentHead = strFontName;

         m_CBFontContent.GetLBText(m_CBFontContent.GetCurSel(), strFontName) ;

         psheet->m_strFontContent = strFontName;

         m_CBFontFooter.GetLBText(m_CBFontFooter.GetCurSel(), strFontName) ;

         psheet->m_strFontFooter = strFontName;

         // 保存字体大小信息

         UINT         uFontSize;

         CString strSize;

         CComboBox *pCombo;

         pCombo = (CComboBox *)GetDlgItem(IDC_CBTITLESIZE);

         pCombo->GetLBText(pCombo->GetCurSel(), strSize); 

         uFontSize = atoi(strSize);

         psheet->m_uSizeTitle = uFontSize;

         pCombo = (CComboBox *)GetDlgItem(IDC_CBHEADSIZE);

         pCombo->GetLBText(pCombo->GetCurSel(), strSize); 

         uFontSize = atoi(strSize);

         psheet->m_uSizeContentHead = uFontSize;

         pCombo = (CComboBox *)GetDlgItem(IDC_CBNORMALSIZE);

         pCombo->GetLBText(pCombo->GetCurSel(), strSize); 

         uFontSize = atoi(strSize);

         psheet->m_uSizeContent = uFontSize;

         pCombo = (CComboBox *)GetDlgItem(IDC_CBFOOTERSIZE);

         pCombo->GetLBText(pCombo->GetCurSel(), strSize); 

         uFontSize = atoi(strSize);

         psheet->m_uSizeFooter = uFontSize;

该函数用于保存设定的字体信息。

·       编写CReportWzdPreview类的实现代码

(1) 首先创建类里与对话框中控件相关联的变量,这些变量通过ClassWizard工具添加,如表6-16所示,为添加变量的名称、类型、关联的控件ID及其意义。

6-16 CReportWzdPreview类的变量

名称

类型

关联的控件ID

意义

m_strReportInfo

CString

IDC_REPORTINFO

报表设置信息显示

(2) 编写OnSetActive()消息响应函数

该函数在属性页被激活时执行,将该属性页的向导按钮显示出“上一步”和“完成”,同时还要显示报表设置信息。我们需要在该函数里添加如下代码:

         // 设置属性页的向导按钮

      CReportWizard *psheet = (CReportWizard *) GetParent();  

         psheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);

         // 显示报表设置信息

         CString strReportFields;

         strReportFields.Empty();

         for(int i=0;im_saSelectedFields.GetSize();i++){

                 strReportFields += psheet->m_saSelectedFields.GetAt(i);

                            if(i+1 < psheet->m_saSelectedFields.GetSize())

                                     strReportFields += _T("");

         }

         CString strPageInfo;

         if(psheet->m_fHavePage){

                           strPageInfo = _T("使用页码,");

                           switch(psheet->m_uPageType){

                                      case 0: strPageInfo += _T("底部左对齐"); break;

                                      case 1: strPageInfo += _T("底部左居中"); break;

                                      case 2: strPageInfo += _T("底部右对齐"); break;

                            }

         }

         else strPageInfo = _T("不使用页码");

         m_strReportInfo.Format("您设置的报表格式如下:\n报表标题: %s, \

                         字体名称: %s 字体大小: %d\n\

                         报表字段: %s, 字体名称: %s \

                         字体大小: %d\n报表注脚: %s, \

                         字体名称: %s 字体大小: %d\n\n%s",

                                                                psheet->m_strReportTitle,

                                                                psheet->m_strFontTitle,

                                                                 psheet->m_uSizeTitle,

                                                                  strReportFields,psheet->m_strFontContent,

                                                                psheet->m_uSizeContent,

                                                                  psheet->m_strReportFooter,psheet->m_strFontFooter,

                                                                psheet->m_uSizeFooter,

                                                                 strPageInfo);

         UpdateData(FALSE);

·       编写“完成”按钮消息响应函数OnWizardFinish()

该函数在“完成”按钮按下时执行,需要保存所有设置到CODBCDemo2View类的相应变量里。在该函数里添加如下代码:

         CMainFrame *pMainFrm = (CMainFrame *)AfxGetMainWnd();

         CODBCDemo2View *pView =  \

                                              (CODBCDemo2View *)pMainFrm->GetActiveView();

         int nCount = psheet->m_saSelectedFields.GetSize();

         for(int i=0;i

                 pView->m_saSelectedFields.Add(psheet->m_saSelectedFields.GetAt(i));

                           pView->m_saSelectedFieldsTitle.Add(

                                                       psheet->m_saSelectedFieldsTitle.GetAt(i));

         }

         pView->m_fHavePage = psheet->m_fHavePage;

         pView->m_uPageType = psheet->m_uPageType;

         pView->m_strReportTitle = psheet->m_strReportTitle;

         pView->m_strFontTitle = psheet->m_strFontTitle;

         pView->m_uSizeTitle = psheet->m_uSizeTitle;

         pView->m_strFontContentHead = psheet->m_strFontContentHead;

         pView->m_uSizeContentHead = psheet->m_uSizeContentHead;

         pView->m_strFontContent = psheet->m_strFontContent;

         pView->m_uSizeContent = psheet->m_uSizeContent;

         pView->m_strReportFooter = psheet->m_strReportFooter;

         pView->m_strFontFooter = psheet->m_strFontFooter;

         pView->m_uSizeFooter = psheet->m_uSizeFooter;

·       编写报表代码

报表代码在菜单项“报表>打印预览”和“报表>打印”里执行,这两个命令都调用OnPrint()函数,我们在该函数里加入如下代码:

         OutputReport(pDC, pInfo);

OutputReport()函数负责报表信息的打印,它的实现代码同前面的RefreshDisplay()函数类似,不同的是,此函数是在打印设备环境下运行的,函数在CODBCDemo2View类里的声明代码如下:

public:

         void OutputReport(CDC* pDC, CPrintInfo* pInfo=NULL);

13.     ODBCDemo2View.cpp文件里,该函数的实现代码如下:

void CODBCDemo2View::OutputReport(CDC* pDC, CPrintInfo* pInfo)

{

        // 检测结果集对象的有效性

         if(!m_pCommonRS) return;

        if(!m_pCommonRS->IsOpen()) return;

        //

         CString line;

         TEXTMETRIC metrics;      

         int y = 0;

         CFont TitleFont, HeadingFont, DetailFont, FooterFont;

         int TabStops[] = {100, 400, 700, 1000, 1300, 1600,

                                                       1900, 2200, 2500, 2800, 3100};

         int FooterTabStops[] = {350};

         if (!pInfo || pInfo->m_nCurPage == 1) {

                          m_pCommonRS->Requery();

         }

         TitleFont.CreateFont(m_uSizeTitle, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0,

                                                        ANSI_CHARSET, OUT_DEFAULT_PRECIS,

                                                       CLIP_DEFAULT_PRECIS,

                                                       DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,

                                                       m_strFontTitle);

         HeadingFont.CreateFont(m_uSizeContentHead, 0, 0, 0,

                                                                FW_BOLD, FALSE, TRUE, 0,

                                                                 ANSI_CHARSET, OUT_DEFAULT_PRECIS,

                                                                CLIP_DEFAULT_PRECIS,

                                                                 DEFAULT_QUALITY,

                                                                DEFAULT_PITCH | FF_ROMAN,

                                                                 m_strFontContentHead);

         DetailFont.CreateFont(m_uSizeContent, 0, 0, 0, FW_NORMAL,

                                                                FALSE, FALSE, 0,

                                                                 ANSI_CHARSET, OUT_DEFAULT_PRECIS,

                                                                CLIP_DEFAULT_PRECIS,

                                                                  DEFAULT_QUALITY,

                                                                DEFAULT_PITCH | FF_ROMAN,

                                                                 m_strFontContent);

         FooterFont.CreateFont(m_uSizeFooter, 0, 0, 0, FW_NORMAL,

                                                                FALSE, FALSE, 0,

                                                                 ANSI_CHARSET, OUT_DEFAULT_PRECIS,

                                                                CLIP_DEFAULT_PRECIS,

                                                                 DEFAULT_QUALITY,

                                                                DEFAULT_PITCH | FF_ROMAN,

                                                                 m_strFontFooter);

         // 打印标题

         CFont* OldFont = pDC->SelectObject(&TitleFont);

         pDC->GetTextMetrics(&metrics);

         int LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         y += LineHeight;         

         pDC->TextOut(200, 0, m_strReportTitle);

         // 打印字段标题

         pDC->SelectObject(&HeadingFont);

         if(0

                           for(int i=0;i

                                     line += m_saSelectedFieldsTitle.GetAt(i);

                                     line += _T("\t");

                           }

                           line += m_saSelectedFieldsTitle.GetAt(i);

         }

         pDC->TabbedTextOut(0, y, line, m_saSelectedFieldsTitle.GetSize(),

                                                                TabStops, 0);

         // 打印正文

         LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         y += LineHeight;

         pDC->SelectObject(&DetailFont);

         pDC->GetTextMetrics(&metrics);

         LineHeight = metrics.tmHeight + metrics.tmExternalLeading;

         while (!m_pCommonRS->IsEOF()) {

                           if (pInfo && abs(y) > 1000) {

                                     pInfo->SetMaxPage(pInfo->m_nCurPage + 1);

                                     break;

                           }

                           line.Empty();

                            CString strValue;

                           if(0

                                     for(int j=0;j

                                              m_pCommonRS->GetFieldValue(m_saSelectedFields.GetAt(j),

                                                                           strValue);

                                              line += strValue;

                                               line += _T("\t");

                                     }

                            m_pCommonRS->GetFieldValue(m_saSelectedFields.GetAt(j), strValue);

                            line += strValue;

                   }

                   pDC->TabbedTextOut(0, y, line, m_saSelectedFields.GetSize(), TabStops, 0);

                   y += LineHeight;          //Adjust y position

                   m_pCommonRS->MoveNext();

         }

         // 打印注脚

         if (pInfo) {

                           pDC->SelectObject(&FooterFont);

                            line.Format("%s \tPage: %d \tJackie", m_strReportFooter,

                                                       pInfo->m_nCurPage);

                           pDC->TabbedTextOut(0, 1025, line, 2, FooterTabStops, 0);

         }

         // 恢复设备环境字体

         pDC->SelectObject(OldFont);

}

6.3.3 编译并运行ODBCDemo2工程

现在我们完成了ODBCDemo2工程代码的编写,可以编译并运行应用程序了。

编译并运行ODBCDemo2工程的操作步骤:

(1) 执行“Build>Build ODBCDemo2.exe”菜单项,或者按下快捷键【F7】,VC++开始编译ODBCDemo2工程,产生ODBCDemo2.exe可执行程序。

(2) 执行“Build>Execute ODBCDemo2.exe”菜单项,或者按下快捷键【Ctrl+F5】,VC++开始运行ODBCDemo2.exe应用程序,启动界面如图6-21所示。

6-21 ODBCDemo2.exe应用程序启动界面

(3) 执行“销售报告>按产品”菜单命令,运行结果如图6-22所示。

6-22 执行“销售报告>按产品”菜单命令

(4) 执行“销售报告>按客户”菜单命令,运行结果如图6-23所示。

6-23 执行“销售报告>按客户”菜单命令

(5) 执行“销售报告>按雇员”菜单命令,运行结果如图6-24所示。

6-24 执行“销售报告>按雇员”菜单命令

(6) 执行“产品>产品信息”菜单命令,运行结果如图6-25所示。

6-25 执行“产品>产品信息”菜单命令

(7) 执行“客户>客户信息”菜单命令,运行结果如图6-26所示。

6-26 执行“客户>客户信息”菜单命令

(8) 执行“雇员>雇员信息”菜单命令,运行结果如图6-27所示。

6-27 执行“雇员>雇员信息”菜单命令

(9) 执行“供应商>供应商信息”菜单命令,运行结果如图6-28所示。

6-28 执行“供应商>供应商信息”菜单命令

(10) 执行“运货商>运货商信息”菜单命令,运行结果如图6-29所示。

6-29 执行“运货商>运货商信息”菜单命令

(11) 执行“产品>产品信息”菜单命令,将产品信息显示在视图里。执行“报表>设置”菜单命令,报表设置向导开始执行第一步,报表字段选择。运行结果如图6-30所示。

6-30 报表设置向导的第一步

(12) 在“报表标题”编辑区域输入“公司产品报表”,将所有字段选择到选用列表里,完成信息输入后,按下“下一步”按钮,报表设置向导开始执行第二步,报表格式设置。运行结果如图6-31所示。

6-31 报表设置向导的第二步

(13) 选择所有字体为“宋体”,选择标题字体大小为48,选择列头字体大小为28,选择正文字体大小为28,选择注脚字体大小为18,完成信息设置后,按下“下一步”按钮,报表设置向导开始执行第三步,显示报表设置信息。运行结果如图6-32所示。

6-32 报表设置向导的第三步

(14) 单击“完成”按钮,完成报表设置,返回系统界面。执行“报表>打印预览”菜单命令,将显示打印预览结果如图6-33所示。

(15) 单击“放大”按钮,将报表预览界面放大,如图6-34所示。

(16) 单击“打印”按钮,即可将报表内容打印出来。

(17) 执行“文件>退出”菜单命令,结束应用程序的运行。

6-33 报表预览

6-34 放大后的报表预览

6.3.4 ODBCDemo2实例小结

本实例着重介绍了MFCCRecordset类实现对数据库的操作,用到的主要函数有:

·       Open(),打开结果集。

·       Close(),关闭结果集。

·       GetODBCFieldCount(),取得结果集的字段数。

·       GetODBCFieldInfo(),取得结果集的字段信息。

·       IsEOF(),判断结果集是否检索到末尾。

·       MoveNext(),移动结果集游标到下一行。

·       Requery(),再次请求结果集。

本实例另一个重点是介绍报表的生成,VC++生成报表没有现成的控件,不如VB容易,必须通过字符打印操作将信息显示在打印设备环境里。这里用到了CDC的两个重要的打印函数:

·       TextOut(),将文本简单打印到指定位置。

·       TabbedTextOut(),将文本格式打印到指定位置。

另外,本实例还演示了PropertySheetPropertyPage的使用方法,对读者设置其信息会有帮助。

本实例源代码在随书光盘的code\ ODBCDemo2目录下。

6.4 本 章 小 结

本章介绍了MFC ODBC编程方法和过程。与ODBC API编程相比,MFC编程更适用于界面型数据库应用程序的开发,由于MFC的广泛支持,ODBC编程可以对数据进行很好地表示。然而MFCCDatabase类和CRecordset类提供的数据库操作函数非常有限,支持的游标类型也很有限,限制了高效的数据库开发。从编程层次上,ODBCMFC编程则属于高级编程。

转载:点击打开链接

你可能感兴趣的:(数据库)