简介
本教程将演示如何使用UltimateGrid,以生成一个非常快速和准确的日历应用程序。此应用程序允许用户一个月一个月或一年一年的前后翻页。允许用户输入特定的月份或年份而跳转到那个特定的时间。
下图显示了完成后的的日历应用程序。
图4.22 – 日历应用程序
第1步– 启动一个新的MFC项目
启动MFC应用程序向导创建一个新的MFC项目,命名为:'Calendar5' 。
图 4.23 – MFC应用程序向导
选择基于对话框的选项,如下图。
图 4.24 – MFC应用程序向导的第一步
第2步– 添加源文件
添加两个必须的Ultimate Grid文件到项目,他们是Skel目录下的: mycug.cpp和mycug.h,然后再把source 目录的UG*.cpp添加到项目里,如下图。
第3步 –设计对话框界面
修改IDD_CALENDAR5_DLG对话框界面,如图4.25。
左键单击组合框的下拉列表按钮(倒三角),这时显示了组合框包括扩展列表框的大小,然后调整它的高度。
图 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。
- /**********************************************************************************/
- //******* Add the mycug.h file
- #include "Mycug.h"
- #if _MSC_VER >= 1000
- #pragma once
- #endif // _MSC_VER >= 1000
- class CCalendar5Dlg : public CDialog
- {
- // Construction
- public:
- //****** Create a new object
- MyCug m_grid;
第5步– 在对话框界面上建立网格
贴附Ultimate Grid到对话框界面。添加下列代码到CCalendar5Dlg::OnInitDialog()函数。
- /*********************************************************************************/
- BOOL CCalendar5Dlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
- m_grid.AttachGrid(this, IDC_GRID);
- //**** MORE CODE
- }
第6步– 设计日历外表
由于这是一个日历程序,只能有5行7列。我们必须在OnSetup()函数中确定行列的宽和高。
可以没有侧标题栏,但会有多个顶部标题栏。星期几的名称被保存在'Days'字符串类数组中。'Days'数组的元素将填充相应的顶部标题。
最上面的标题栏将包含箭头单元格类型,这些单元格类型只有外表没有实际功能。
因此添加以下几行代码到MyCug类的OnSetup函数中。在代码片段中有额外的详细的注释。
- /*************************************************************************************/
- void MyCug::OnSetup()
- {
- //******* 声明所有的变量
- CString days[7] = {"Sunday","Monday", "Tuesday","Wednesday", "Thursday","Friday", "Saturday"};
- CUGCell cell;
- //******* 配置行和列
- SetNumberCols(7);
- SetNumberRows(5);
- //******配置行高!!
- for (int v = 0; v < 5; v++)
- {
- SetRowHeight(v, 40);
- }
- //****** 配置列宽!!
- for (int vv = 0; vv < 7; vv++)
- {
- SetColWidth(vv, 80);
- }
- //********* 消除侧边标题栏
- SetSH_Width(0);
- //********* 配置两个顶部标题栏
- SetTH_NumberRows(2);
- //******** 配置两个顶部标题栏的大小
- SetTH_Height(50);
- SetTH_RowHeight(-1, 25);
- SetTH_RowHeight(-2, 25);
- //***** 在顶部标题栏显示星期
- for (int zz = 0; zz < 7; zz++)
- {
- QuickSetText(zz, -1, days[zz]);
- }
- //********* 合并顶部标题栏的几个单元格!!!!
- JoinCells(2, -2, 4, -2);
- //******** 配置顶部标题栏箭头单元格类型
- GetCell(6, -2, &cell);
- cell.SetCellType(UGCT_ARROW);
- cell.SetCellTypeEx(64);
- SetCell(6, -2, &cell);
- GetCell(0, -2, &cell);
- cell.SetCellType(UGCT_ARROW);
- cell.SetCellTypeEx(128);
- SetCell(0, -2, &cell);
- GetCell(1, -2, &cell);
- cell.SetCellType(UGCT_ARROW);
- cell.SetCellTypeEx(32);
- SetCell(1, -2, &cell);
- GetCell(5, -2, &cell);
- cell.SetCellType(UGCT_ARROW);
- cell.SetCellTypeEx(16);
- SetCell(5, -2, &cell);
- }
- /********************************************************************************************************************/
当您添加了上面的代码,你应该能够执行应用程序。下面的图应该是这个结果。
图 4.26 – 一个没有功能的日历应用程序
第7步– 修改网格属性
有几个属性必须修改。第一项任务是不允许用户调整行和列的大小。
7.1 – 修改OnCanSizeCol()
默认情况下,列的宽度是能够调整的。当改变这个消息函数的返回值TRUE为FALSE后,用户无法调整列的宽度。
- int MyCug::OnCanSizeCol(int col){
- return FALSE;
- }
7.2 – 修改OnCanSizeRow()
默认情况下,行的高度是能够调整的。当改变这个消息函数的返回值TRUE为FALSE后,用户无法调整行的高度。
- int MyCug::OnCanSizeRow(long row){
- return FALSE;
- }
7.3 – 修改OnCanSizeTopHdg()
当改变这个消息函数的返回值TRUE为FALSE后,用户无法调整顶部标题栏。
- int MyCug::OnCanSizeTopHdg(){
- return FALSE;
- }
第8步– 创建MyCug 类成员变量
这个类的三个新的成员变量为m_current_month ,m_current_year和m_months。m_current_year成员变量与当前年保持关联,m_current_month成员变量与当前的月保持关联,m_months成员变量与存放每月有多少天的整数数组保持关联。
在MyCug头文件中添加以下几行代码。
- /*************************************************************************************/
- class MyCug: public CUGCtrl
- {
- public:
- MyCug();
- ~MyCug();
- int m_current_month, m_current_year;
- int m_months[15] ;
第9步– 给新的成员变量赋以适当的值
在MyCug的构造函数中,你必须给这三个成员函数赋以适当的值。
在这代码片段中所完成的另外的一项重要任务是创建一个'time'的COleDateTime对象。调用time.GetMonth()和time.GetYear()对两个成员变量m_current_month和m_current_year赋值。
- /***********************************************************************************/
- MyCug::MyCug()
- {
- //*******给月份变量数组赋值
- m_months[0] = 30;
- m_months[1] = 28;
- m_months[2] = 31;
- m_months[3] = 30;
- m_months[4] = 31;
- m_months[5] = 30;
- m_months[6] = 31;
- m_months[7] = 31;
- m_months[8] = 30;
- m_months[9] = 31;
- m_months[10] = 30;
- m_months[11] = 31;
- //*******创建一个COleDateTime对象
- COleDateTime time = COleDateTime::GetCurrentTime();
- //*******给当前月份的成员变量赋值
- m_current_month = time.GetMonth();
- //*******给当前年份的成员变量赋值
- m_current_year = time.GetYear();
- }
第10步– 创建一个MyCug 类成员函数
在MyCug类中添加一个名字为Date()返回类型为void的成员函数。这个函数负责跟踪日期,并往网格里放入正确的月份值。
在MyCug::Date()中添加后面的代码。
- /************************************************************************************/
- void MyCug::Date()
- {
- //****** 声明所有的变量
- int row = 0;
- int numberofdays, dayofweek;
- CString today;
- CString nameMonths[13] = {"January","February", "March","April", "May","June", "July",
- "August","September", "October","November", "December"
- };
- CUGCell cell;
- CString days;
- /****** 创建一个Time对象, 保存当前月份和当前年份和本月的第一天 *****/
- COleDateTime time(m_current_year, m_current_month, 1, 0, 0, 0);
- /***** 这个变量获取本月第一天的列值,作为循环嵌套For..Loop的索引,后面用来填充网格*****/
- dayofweek = time.GetDayOfWeek() - 1;
- /****** Cstring对象today保存当前月份,当前年份 ***** /
- today.Format("%s, %d", nameMonths[m_current_month -1], m_current_year);
- /******* 在合并单元格的顶部标题栏上显示CString 变量Today值 ********/
- GetCell(2, -2, &cell);
- cell.SetText(today);
- SetCell(2, -2, &cell);
- RedrawCell(2, -2);
- /******* 计算本月份中的天数 ********/
- numberofdays = m_months[m_current_month - 1 ];
- //******* 闰年的测试!!!!!
- if ((m_current_month == 2) && ( m_current_year % 4 == 0))
- numberofdays++;
- //******** 清除整个网格
- int numrows = GetNumberRows();
- int numcols = GetNumberCols();
- for (int z = 0 ; z < numcols; z++)
- {
- for (int x = 0; x < numrows; x++)
- {
- QuickSetBackColor(z, -1, RGB(200, 200, 200));
- QuickSetText(z, x, "");
- }
- }
- RedrawAll();
- /********** 用正确的日期重新填充网格,注意星期几的变量作为列的索引值******/
- for (int index2 = 1; index2 <= numberofdays; index2++)
- {
- days.Format("%d", index2);
- QuickSetText(dayofweek, row, days);
- dayofweek++;
- if (dayofweek == 7)
- {
- dayofweek = 0;
- row++;
- }
- }
- RedrawAll();
- //********* 完工 !!!!!
- }
- /*********************************************************************************************************/
在CCalendar5Dlg:: OnPaint ()函数里面添加下面这一行。
m_grid.Date();
现在,所有的工作就结束了,你可以执行程序了,这将是一个全功能的应用程序,当然只显示当前月,请记住在MyCug 的构造函数中m_current_month变量分配月份,m_current_year变量分配年份。
现在,您的应用程序应该类似于下图。
图 4.27 – 一个全功能的日历应用程序
第11步– 修改OnTH_Lclicked消息函数
当用户左键单击指向右侧的双箭头按钮时(在顶部标题栏中),我们希望转到下一个年份。当用户左键单击指向右侧的单箭头按钮时,我们希望转到下一个月份。当用户左键单击指向左侧的单箭头按钮时,我们希望转到上一个月份。当用户左键单击指向左侧的双箭头按钮时,我们希望转到上一个年份。
添加下面的代码到 OnTH_LClicked()。
- /*************************************************************************************/
- void MyCug::OnTH_LClicked(int col, longrow,int updn, RECT *rect, POINT *point, BOOL processed)
- {
- if(!updn)
- {
- //******* 下一个月!!!
- if((col == 5) && (row == -2))
- {
- m_current_month++;
- if(m_current_month > 12)
- {
- m_current_month = 1;
- m_current_year++;
- }
- Date();
- }
- //******* 上一个月
- if((col == 1) && (row == -2))
- {
- m_current_month--;
- if(m_current_month < 1)
- {
- m_current_month = 12;
- m_current_year--;
- }
- Date();
- }
- //******* 下一年!!!
- if((col == 6) && (row == -2))
- {
- m_current_year++;
- Date();
- }
- //******** 上一年!!!
- if((col == 0) && (row == -2))
- {
- m_current_year--;
- Date();
- }
- }
- }
第12步– 创建自定义日期控件
你必须在CCalendar5Dlg类中添加一个成员变量,它是IDC_MONTH组合控件的实例化对象。用类向导创建一个m_month成员变量。请确保它是组合控件的实例化对象。
对m_month对象赋值
打开CCalendar5Dlg::OnInitDialog()添加下列代码行。
- //********* 往组合框里用月份的名字赋值
- m_month.AddString("January");
- m_month.AddString("February");
- m_month.AddString("March");
- m_month.AddString("April");
- m_month.AddString("May");
- m_month.AddString("June");
- m_month.AddString("July");
- m_month.AddString("August");
- m_month.AddString("September");
- m_month.AddString("October");
- m_month.AddString("November");
- m_month.AddString("December");
第13步– 创建一个CCalendar5Dlg 类的成员函数
用类向导创建一个新的IDSET控件的消息函数,默认情况下这个消息函数为CCalendar5Dlg::OnSet()。
添加下列代码行到消息函数中。
- /*********************************************************************************/
- void CCalendar5Dlg::OnSet()
- {
- //******** 声明所有变量
- int current_year, current_month;
- CString year, month;
- //******* 向两个字符串对象赋值
- GetDlgItemText(IDC_YEAR, year);
- GetDlgItemText(IDC_MONTH, month);
- //******* 获取月份的值!!!!
- if (month == "January")
- current_month = 1;
- if (month == "February")
- current_month = 2;
- if (month == "March")
- current_month = 3;
- if (month == "April")
- current_month = 4;
- if (month == "May")
- current_month = 5;
- if (month == "June")
- current_month = 6;
- if (month == "July")
- current_month = 7;
- if (month == "August")
- current_month = 8;
- if (month == "September")
- current_month = 9;
- if (month == "October")
- current_month = 10;
- if (month == "November")
- current_month = 11;
- if (month == "December")
- current_month = 12;
- //******** 填充日历!!!!!!
- current_year = atoi(year);
- m_grid.m_current_year = current_year;
- m_grid.m_current_month = current_month;
- //****** 调用日期函数
- m_grid.Date();
- }
第14步– 创建和编辑OnCancel消息处理函数
当用户点击“关闭”按钮时,此消息函数将被调用。添加下面代码行。
- /********************************************************************************************************************/
- void CCalendar5Dlg::OnCancel(){
- OnOK();
- }