第11课 日历应用程序

时间:2022-09-17 19:45:54

简介

本教程将演示如何使用UltimateGrid,以生成一个非常快速和准确的日历应用程序。此应用程序允许用户一个月一个月或一年一年的前后翻页。允许用户输入特定的月份或年份而跳转到那个特定的时间。

下图显示了完成后的的日历应用程序。

第11课 日历应用程序

图4.22 – 日历应用程序


第1步– 启动一个新的MFC项目

启动MFC应用程序向导创建一个新的MFC项目,命名为:'Calendar5' 。

第11课 日历应用程序

图 4.23 – MFC应用程序向导


选择基于对话框的选项,如下图。

第11课 日历应用程序

图 4.24 – MFC应用程序向导的第一步


第2步– 添加源文件

添加两个必须的Ultimate Grid文件到项目,他们是Skel目录下的: mycug.cppmycug.h,然后再把source 目录的UG*.cpp添加到项目里,如下图。

第11课 日历应用程序


第3步 –设计对话框界面

修改IDD_CALENDAR5_DLG对话框界面,如图4.25。
左键单击组合框的下拉列表按钮(倒三角),这时显示了组合框包括扩展列表框的大小,然后调整它的高度。

第11课 日历应用程序

图 4.25 - IDD_CALENDAR5_DLG界面

参阅下表分配控件的名称

控件

控件名

组合框

IDC_MONTH

编辑框

IDC_YEAR

Set按钮

IDSET

Close按钮

IDCANCEL

主static区域(日历显示区域)

IDC_GRID



第4步– 创建一个CCalendar5Dlg类成员

主对话框是CCalendar5Dlg类。在其中添加一个新的MyCug类的成员变量m_grid。在CCalendar5Dlg类的头文件的前面包含MyCug.h。

[cpp] view plaincopyprint?
  1. /**********************************************************************************/ 
  2. //******* Add the mycug.h file 
  3. #include "Mycug.h" 
  4. #if _MSC_VER >= 1000 
  5. #pragma once 
  6. #endif // _MSC_VER >= 1000 
  7. class CCalendar5Dlg : public CDialog 
  8.     // Construction 
  9. public
  10.     //****** Create a new object 
  11.     MyCug m_grid; 


第5步– 在对话框界面上建立网格

贴附Ultimate Grid到对话框界面。添加下列代码到CCalendar5Dlg::OnInitDialog()函数。

[cpp] view plaincopyprint?
  1. /*********************************************************************************/ 
  2. BOOL CCalendar5Dlg::OnInitDialog() 
  3.     CDialog::OnInitDialog(); 
  4.     m_grid.AttachGrid(this, IDC_GRID); 
  5.     //**** MORE CODE 


第6步– 设计日历外表

由于这是一个日历程序,只能有5行7列。我们必须在OnSetup()函数中确定行列的宽和高。

可以没有侧标题栏,但会有多个顶部标题栏。星期几的名称被保存在'Days'字符串类数组中。'Days'数组的元素将填充相应的顶部标题。

最上面的标题栏将包含箭头单元格类型,这些单元格类型只有外表没有实际功能。

因此添加以下几行代码到MyCug类的OnSetup函数中。在代码片段中有额外的详细的注释。

[cpp] view plaincopyprint?
  1. /*************************************************************************************/ 
  2. void MyCug::OnSetup() 
  3.     //******* 声明所有的变量 
  4.     CString days[7] = {"Sunday","Monday", "Tuesday","Wednesday", "Thursday","Friday", "Saturday"}; 
  5.     CUGCell cell; 
  6.     //******* 配置行和列 
  7.     SetNumberCols(7); 
  8.     SetNumberRows(5); 
  9.     //******配置行高!! 
  10.     for (int v = 0; v < 5; v++) 
  11.     { 
  12.         SetRowHeight(v, 40); 
  13.     } 
  14.     //****** 配置列宽!! 
  15.     for (int vv = 0; vv < 7; vv++) 
  16.     { 
  17.         SetColWidth(vv, 80); 
  18.     } 
  19.     //********* 消除侧边标题栏 
  20.     SetSH_Width(0); 
  21.     //********* 配置两个顶部标题栏 
  22.     SetTH_NumberRows(2); 
  23.     //******** 配置两个顶部标题栏的大小 
  24.     SetTH_Height(50); 
  25.     SetTH_RowHeight(-1, 25); 
  26.     SetTH_RowHeight(-2, 25); 
  27.     //***** 在顶部标题栏显示星期 
  28.     for (int zz = 0; zz < 7; zz++) 
  29.     { 
  30.         QuickSetText(zz, -1, days[zz]); 
  31.     } 
  32.     //********* 合并顶部标题栏的几个单元格!!!! 
  33.     JoinCells(2, -2, 4, -2); 
  34.     //******** 配置顶部标题栏箭头单元格类型 
  35.     GetCell(6, -2, &cell); 
  36.     cell.SetCellType(UGCT_ARROW); 
  37.     cell.SetCellTypeEx(64); 
  38.     SetCell(6, -2, &cell); 
  39.     GetCell(0, -2, &cell); 
  40.     cell.SetCellType(UGCT_ARROW); 
  41.     cell.SetCellTypeEx(128); 
  42.     SetCell(0, -2, &cell); 
  43.     GetCell(1, -2, &cell); 
  44.     cell.SetCellType(UGCT_ARROW); 
  45.     cell.SetCellTypeEx(32); 
  46.     SetCell(1, -2, &cell); 
  47.     GetCell(5, -2, &cell); 
  48.     cell.SetCellType(UGCT_ARROW); 
  49.     cell.SetCellTypeEx(16); 
  50.     SetCell(5, -2, &cell); 
  51. /********************************************************************************************************************/ 

当您添加了上面的代码,你应该能够执行应用程序。下面的图应该是这个结果。

第11课 日历应用程序

图 4.26 – 一个没有功能的日历应用程序

第7步– 修改网格属性

有几个属性必须修改。第一项任务是不允许用户调整行和列的大小。

7.1 – 修改OnCanSizeCol()

默认情况下,列的宽度是能够调整的。当改变这个消息函数的返回值TRUE为FALSE后,用户无法调整列的宽度。

[cpp] view plaincopyprint?
  1. int MyCug::OnCanSizeCol(int col){  
  2.     return FALSE;  

7.2 – 修改OnCanSizeRow()

默认情况下,行的高度是能够调整的。当改变这个消息函数的返回值TRUE为FALSE后,用户无法调整行的高度。

[cpp] view plaincopyprint?
  1. int MyCug::OnCanSizeRow(long row){  
  2.     return FALSE;  

7.3 – 修改OnCanSizeTopHdg()

当改变这个消息函数的返回值TRUE为FALSE后,用户无法调整顶部标题栏。

[cpp] view plaincopyprint?
  1. int MyCug::OnCanSizeTopHdg(){  
  2.     return FALSE;  

第8步– 创建MyCug 类成员变量

这个类的三个新的成员变量为m_current_month ,m_current_year和m_months。m_current_year成员变量与当前年保持关联,m_current_month成员变量与当前的月保持关联,m_months成员变量与存放每月有多少天的整数数组保持关联。

在MyCug头文件中添加以下几行代码。

[cpp] view plaincopyprint?
  1. /*************************************************************************************/ 
  2. class MyCug: public CUGCtrl 
  3. public
  4.     MyCug(); 
  5.     ~MyCug(); 
  6.     int m_current_month, m_current_year; 
  7.     int m_months[15] ; 

第9步– 给新的成员变量赋以适当的值

在MyCug的构造函数中,你必须给这三个成员函数赋以适当的值。

在这代码片段中所完成的另外的一项重要任务是创建一个'time'的COleDateTime对象。调用time.GetMonth()和time.GetYear()对两个成员变量m_current_month和m_current_year赋值。

[cpp] view plaincopyprint?
  1. /***********************************************************************************/ 
  2. MyCug::MyCug() 
  3.     //*******给月份变量数组赋值 
  4.     m_months[0] = 30; 
  5.     m_months[1] = 28; 
  6.     m_months[2] = 31; 
  7.     m_months[3] = 30; 
  8.     m_months[4] = 31; 
  9.     m_months[5] = 30; 
  10.     m_months[6] = 31; 
  11.     m_months[7] = 31; 
  12.     m_months[8] = 30; 
  13.     m_months[9] = 31; 
  14.     m_months[10] = 30; 
  15.     m_months[11] = 31; 
  16.     //*******创建一个COleDateTime对象 
  17.     COleDateTime time = COleDateTime::GetCurrentTime(); 
  18.     //*******给当前月份的成员变量赋值 
  19.     m_current_month = time.GetMonth(); 
  20.     //*******给当前年份的成员变量赋值 
  21.     m_current_year = time.GetYear(); 

第10步– 创建一个MyCug 类成员函数

在MyCug类中添加一个名字为Date()返回类型为void的成员函数。这个函数负责跟踪日期,并往网格里放入正确的月份值。

在MyCug::Date()中添加后面的代码。

[cpp] view plaincopyprint?
  1. /************************************************************************************/ 
  2. void MyCug::Date() 
  3.     //****** 声明所有的变量 
  4.     int row = 0; 
  5.     int numberofdays, dayofweek; 
  6.     CString today; 
  7.     CString nameMonths[13] = {"January","February", "March","April", "May","June", "July"
  8.                               "August","September", "October","November", "December" 
  9.                              }; 
  10.     CUGCell cell; 
  11.     CString days; 
  12.     /****** 创建一个Time对象, 保存当前月份和当前年份和本月的第一天 *****/ 
  13.     COleDateTime time(m_current_year, m_current_month, 1, 0, 0, 0); 
  14.     /***** 这个变量获取本月第一天的列值,作为循环嵌套For..Loop的索引,后面用来填充网格*****/ 
  15.     dayofweek = time.GetDayOfWeek() - 1; 
  16.     /****** Cstring对象today保存当前月份,当前年份 ***** /
  17.     today.Format("%s, %d", nameMonths[m_current_month -1], m_current_year);
  18.     /******* 在合并单元格的顶部标题栏上显示CString 变量Today值 ********/ 
  19.     GetCell(2, -2, &cell); 
  20.     cell.SetText(today); 
  21.     SetCell(2, -2, &cell); 
  22.     RedrawCell(2, -2); 
  23.     /******* 计算本月份中的天数 ********/ 
  24.     numberofdays = m_months[m_current_month - 1 ]; 
  25.     //******* 闰年的测试!!!!! 
  26.     if ((m_current_month == 2) && ( m_current_year % 4 == 0)) 
  27.         numberofdays++; 
  28.     //******** 清除整个网格 
  29.     int numrows = GetNumberRows(); 
  30.     int numcols = GetNumberCols(); 
  31.     for (int z = 0 ; z < numcols; z++) 
  32.     { 
  33.         for (int x = 0; x < numrows; x++) 
  34.         { 
  35.             QuickSetBackColor(z, -1, RGB(200, 200, 200)); 
  36.             QuickSetText(z, x, ""); 
  37.         } 
  38.     } 
  39.     RedrawAll(); 
  40.     /********** 用正确的日期重新填充网格,注意星期几的变量作为列的索引值******/ 
  41.     for (int index2 = 1; index2 <= numberofdays; index2++) 
  42.     { 
  43.         days.Format("%d", index2); 
  44.         QuickSetText(dayofweek, row, days); 
  45.         dayofweek++; 
  46.         if (dayofweek == 7) 
  47.         { 
  48.             dayofweek = 0; 
  49.             row++; 
  50.         } 
  51.     } 
  52.     RedrawAll(); 
  53.     //********* 完工 !!!!! 
  54. /*********************************************************************************************************/ 


在CCalendar5Dlg:: OnPaint ()函数里面添加下面这一行。

m_grid.Date();

现在,所有的工作就结束了,你可以执行程序了,这将是一个全功能的应用程序,当然只显示当前月,请记住在MyCug 的构造函数中m_current_month变量分配月份,m_current_year变量分配年份。

现在,您的应用程序应该类似于下图。

第11课 日历应用程序

图 4.27 – 一个全功能的日历应用程序

第11步– 修改OnTH_Lclicked消息函数

当用户左键单击指向右侧的双箭头按钮时(在顶部标题栏中),我们希望转到下一个年份。当用户左键单击指向右侧的单箭头按钮时,我们希望转到下一个月份。当用户左键单击指向左侧的单箭头按钮时,我们希望转到上一个月份。当用户左键单击指向左侧的双箭头按钮时,我们希望转到上一个年份。

添加下面的代码到 OnTH_LClicked()。

[cpp] view plaincopyprint?
  1. /*************************************************************************************/ 
  2. void MyCug::OnTH_LClicked(int col, longrow,int updn, RECT *rect, POINT *point, BOOL processed) 
  3.     if(!updn) 
  4.     { 
  5.         //******* 下一个月!!! 
  6.         if((col == 5) && (row == -2)) 
  7.         { 
  8.             m_current_month++; 
  9.             if(m_current_month > 12) 
  10.             { 
  11.                 m_current_month = 1; 
  12.                 m_current_year++; 
  13.             } 
  14.             Date(); 
  15.         } 
  16.         //******* 上一个月 
  17.         if((col == 1) && (row == -2)) 
  18.         { 
  19.             m_current_month--; 
  20.             if(m_current_month < 1) 
  21.             { 
  22.                 m_current_month = 12; 
  23.                 m_current_year--; 
  24.             } 
  25.             Date(); 
  26.         } 
  27.         //******* 下一年!!! 
  28.         if((col == 6) && (row == -2)) 
  29.         { 
  30.             m_current_year++; 
  31.             Date(); 
  32.         } 
  33.         //******** 上一年!!! 
  34.         if((col == 0) && (row == -2)) 
  35.         { 
  36.             m_current_year--; 
  37.             Date(); 
  38.         } 
  39.     } 


第12步– 创建自定义日期控件

你必须在CCalendar5Dlg类中添加一个成员变量,它是IDC_MONTH组合控件的实例化对象。用类向导创建一个m_month成员变量。请确保它是组合控件的实例化对象。

对m_month对象赋值

打开CCalendar5Dlg::OnInitDialog()添加下列代码行。

[cpp] view plaincopyprint?
  1. //********* 往组合框里用月份的名字赋值 
  2. m_month.AddString("January");  
  3. m_month.AddString("February");  
  4. m_month.AddString("March");  
  5. m_month.AddString("April");  
  6. m_month.AddString("May");  
  7. m_month.AddString("June");  
  8. m_month.AddString("July");  
  9. m_month.AddString("August");  
  10. m_month.AddString("September");  
  11. m_month.AddString("October");  
  12. m_month.AddString("November");  
  13. m_month.AddString("December"); 

第13步– 创建一个CCalendar5Dlg 类的成员函数

用类向导创建一个新的IDSET控件的消息函数,默认情况下这个消息函数为CCalendar5Dlg::OnSet()。

添加下列代码行到消息函数中。

[cpp] view plaincopyprint?
  1. /*********************************************************************************/ 
  2. void CCalendar5Dlg::OnSet() 
  3.     //******** 声明所有变量 
  4.     int current_year, current_month; 
  5.     CString year, month; 
  6.     //******* 向两个字符串对象赋值 
  7.     GetDlgItemText(IDC_YEAR, year); 
  8.     GetDlgItemText(IDC_MONTH, month); 
  9.     //******* 获取月份的值!!!! 
  10.     if (month == "January"
  11.         current_month = 1; 
  12.     if (month == "February"
  13.         current_month = 2; 
  14.     if (month == "March"
  15.         current_month = 3; 
  16.     if (month == "April"
  17.         current_month = 4; 
  18.     if (month == "May"
  19.         current_month = 5; 
  20.     if (month == "June"
  21.         current_month = 6; 
  22.     if (month == "July"
  23.         current_month = 7; 
  24.     if (month == "August"
  25.         current_month = 8; 
  26.     if (month == "September"
  27.         current_month = 9; 
  28.     if (month == "October"
  29.         current_month = 10; 
  30.     if (month == "November"
  31.         current_month = 11; 
  32.     if (month == "December"
  33.         current_month = 12; 
  34.     //******** 填充日历!!!!!! 
  35.     current_year = atoi(year); 
  36.     m_grid.m_current_year = current_year; 
  37.     m_grid.m_current_month = current_month; 
  38.     //****** 调用日期函数 
  39.     m_grid.Date(); 

第14步– 创建和编辑OnCancel消息处理函数

当用户点击“关闭”按钮时,此消息函数将被调用。添加下面代码行。

[cpp] view plaincopyprint?
  1. /********************************************************************************************************************/ 
  2. void CCalendar5Dlg::OnCancel(){  
  3.     OnOK();