使用CDateTimeCtrl
日期和时间选择器控件(CDateTimeCtrl) 实现了一种直观且可识别的方法来输入或选择特定的日期。此控件的主接口在功能上类似于组合框。但是,如果用户展开此控件,会出现月历(MonthCalendar) 控件(默认情况下),允许用户指定特定日期。选定日期后,月历(MonthCalendar) 控件便自动消失。
注意若要在项目中同时使用CDateTimePicker类和CMonthCalCtrl类,必须包含AFXDTCTL.H(通常在项目的STDAFX.H 文件中)。
创建日期和时间选择器控件
创建日期和时间选择器控件的方式取决于是在对话框中使用此控件还是在非对话框窗口中创建此控件。
直接在对话框中使用CDateTimeCtrl
1.在对话框编辑器中,将“Date Time Picker”控件添加到对话框模板资源中。指定其控件ID。
2.使用日期和时间选择器控件的“属性”对话框指定任何所需样式。
3.使用添加成员变量向导添加带Control 属性的CDateTimeCtrl 类型的成员变量。可以使用此
成员调用CDateTimeCtrl成员函数。
4.对于需要处理的任何“Date Time Picker”控件通知消息,使用“属性”窗口在对话框类中映射处理
函数(请参见将消息映射到函数)。
5.在OnInitDialog 中设置CDateTimeCtrl对象的任何附加样式。
在非对话框窗口中使用CDateTimeCtrl
1.在视图或窗口类中声明该控件。
2.调用此控件的Create 成员函数,可能在OnInitialUpdate 中,也可能与父窗口的OnCreate
处理函数一样早(如果正在创建此控件的子类)。设置此控件的样式。
日期和时间选择器控件示例
CMNCTRL1示例将说明CDateTimeCtrl类的各种属性。单独一页包含日期和时间选择器控件,用户可以通过更改各种属性和测试控件的基本功能来操作此控件。
访问嵌入的月历(MonthCalendar) 控件
通过调用GetMonthCalCtrl 成员函数,可以从CDateTimeCtrl对象访问嵌入的月历(MonthCalendar) 控件对象。
注意只有当日期和时间选择器控件没有设置DTS_UPDOWN样式时才使用嵌入的月历控件。
这对于在显示该嵌入控件之前修改某些属性很有用。为此可处理DTN_DROPDOWN通知,检索月历(MonthCalendar) 控件(使用CDateTimeCtrl::GetMonthCalCtrl),然后进行修改。遗憾的是,月历(MonthCalendar) 控件不能持久保持。
换句话说,即当用户请求显示月历(MonthCalendar) 控件时才创建新月历(MonthCalendar) 控件(DTN_DROPDOWN通知之前)。当用户解除此控件时,它即被销毁(DTN_CLOSEUP通知之后)。这意味着显示该嵌入控件之前修改的任何属性,在该嵌入控件被解除之后都将丢失。
下面的示例使用DTN_DROPDOWN通知的处理程序说明了此过程。该代码通过调用SetMonthCalColor 将月历(MonthCalendar) 控件的背景色改为灰色。代码如下:
void CMyDlg::OnDropdown(NMHDR* pNMHDR, LRESULT* pResult)
{
//set the background color of the month to gray
COLORREF clr= RGB(100, 100, 100);
SetMonthCalColor(MCSC_MONTHBK, clr);
*pResult = 0;
}
如前所述,当解除月历(MonthCalendar) 控件时,对该嵌入控件属性所做的所有修改全都丢失,但有两个例外。第一个例外是月历(MonthCalendar) 控件的颜色,这一点已经讨论过。第二个例外是月历(MonthCalendar) 控件所使用的字体。可以通过调用CDateTimeCtrl::SetMonthCalFont 并传递现有字体的句柄来修改默认字体。下面的示例(其中m_dtPicker是日期和时间控件对象)将说明一种可能的方法:
CMonthCalCtrl* pMCCtrl= NULL;
pMCCtrl= m_dtPicker.GetMonthCalCtrl();
//create and initialize the font to be used
LOGFONT logFont;
logFont.lfHeight = -12;
logFont.lfWidth = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = FALSE;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
lstrcpy(logFont.lfFaceName, _T("Verdana"));
m_MCFont.CreateFontIndirect(&logFont);
m_dtPicker.SetMonthCalFont((HFONT)m_MCFont);
通过调用CDateTimeCtrl::SetMonthCalFont更改了字体后,将存储新字体并在下次显示月历时使用
在日期和时间选择器控件中使用自定义格式字符串
默认情况下,日期和时间选择器控件提供三种格式类型来显示当前日期或时间(每种格式对应一种唯一的样式):
?DTS_LONGDATEFORMAT以长格式显示日期,得出的输出形式为“Wednesday, January 3, 2000”。
?DTS_SHORTDATEFORMAT以短格式显示日期,得出的输出形式为“1/3/00”。
?DTS_TIMEFORMAT以长格式显示时间,得出的输出形式为“5:31:42 PM”。
不过,可以通过使用自定义格式字符串自定义日期或时间的外观。此自定义字符串由现有格式字符或非格式字符组成,或由这两者共同组成。生成自定义字符串后,调用CDateTimeCtrl::SetFormat 来传入自定义字符串。日期和时间选择器控件于是将使用自定义格式字符串显示当前值。
下面的示例代码(其中m_dtPicker为CDateTimeCtrl对象)将说明一种可能的解决方案:
CString formatStr= _T("'Today is: 'yy'/'MM'/'dd");
m_dtPicker.SetFormat(formatStr);
除了自定义格式字符串,日期和时间选择器控件还支持回调字段。
在日期和时间选择器控件中使用回调字段
除了定义日期和时间选择器字段的标准格式字符,还可以通过将自定义格式字符串中的某些部分指定为回调字段来自定义输出。若要声明回调字段,请在格式字符串体中的任何位置包含一个或多个“X”字符(ASCII 码88)。例如,以下字符串“'Today is: 'yy'/'MM'/'dd' (Day 'X')'”使日期和时间选择器控件将当前值的格式显示为年份后面跟月份、日期,最后为该日期是一年中的第几天。
注意回调字段中X 的数目与将要显示的字符数不对应。
可以通过重复“X”字符来区分自定义字符串中的多个回调字段。因此,格式字符串“XXddddMMMdd',
'yyyXXX”包含两个唯一的回调字段“XX”和“XXX”。
注意回调字段被视为有效字段,因此应用程序必须准备处理DTN_WMKEYDOWN通知消息。
日期和时间选择器控件中的回调字段实现由三部分组成:
?初始化自定义格式字符串
?处理DTN_FORMATQUERY通知
?处理DTN_FORMAT通知
初始化自定义格式字符串
调用CDateTimeCtrl::SetFormat初始化自定义字符串。有关更多信息,请参见在日期和时间选择器控件中使用自定义格式字符串。通常在包含对话框类的OnInitDialog函数或包含视图类的OnInitalUpdate函数中设置自定义格式字符串。
处理DTN_FORMATQUERY 通知
如果控件在分析格式字符串的过程中遇到回调字段,应用程序将发送DTN_FORMAT和
DTN_FORMATQUERY通知消息。通知中包含回调字段字符串,因此可以确定正查询的回调字段。
发送DTN_FORMATQUERY通知以检索当前回调字段中将要显示的字符串所允许的最大大小(以像素为单位)。
若要正确计算此值,必须使用控件的显示字体计算要替换此字段的字符串的高度和宽度。调用GetTextExtentPoint32 Win32 函数可以很容易地对字符串进行实际计算。确定大小后,将值传回应用程序并退出处理函数。
下面的示例是一种提供回调字符串大小的方法:
复制代码
NMDATETIMEFORMATQUERY* pDTFormatQuery= (NMDATETIMEFORMATQUERY *)pNMHDR;
CDC* pDC;
CFont* pFont;
CFont* pOrigFont;
// Prepare the device context for the GetTextExtentPoint32 call.
pDC= GetDC();
pFont= GetFont();
if(!pFont)
pFont->CreateStockObject(DEFAULT_GUI_FONT);
pOrigFont = pDC->SelectObject(pFont);
// Check to see if this is the callback segment desired. If so,
// use the longest text segment to determine the maximum
// width of the callback field, and then place the information into
// the NMDATETIMEFORMATQUERY structure.
if(!lstrcmp("X",pDTFormatQuery->pszFormat))
::GetTextExtentPoint32 (pDC->m_hDC, "366",
3, &pDTFormatQuery->szMax);
// Reset the font in the device context then release the context.
pDC->SelectObject(pOrigFont);
ReleaseDC(pDC);
*pResult = 0;
计算出当前回调字段的大小后,必须为该字段提供值。这在DTN_FORMAT通知的处理程序中完成。处理DTN_FORMAT 通知
应用程序使用DTN_FORMAT通知请求将被替换的字符串。下面的示例将说明一种可能的方法:
复制代码
NMDATETIMEFORMAT* pDTFormat= (NMDATETIMEFORMAT *)pNMHDR;
COleDateTime oCurTime;
m_dtPicker.GetTime(oCurTime);
wsprintf(pDTFormat->pszDisplay,
"%d",oCurTime.GetDayOfYear());
*pResult = 0;
注意通过将通知处理程序的第一个参数的类型转换为适当的类型,找到NMDATETIMEFORMAT结构的指针。
处理日期和时间选择器控件中的通知消息
用户与日期和时间选择器控件交互时,控件(CDateTimeCtrl) 将通知消息发送到它的父窗口,该窗口通常是视图或对话框对象。如果要进行某种响应,请处理这些消息。例如,当用户打开日期和时间选择器显示嵌入的月历(MonthCalendar) 控件时,发送DTN_DROPDOWN通知。
使用“属性”窗口为要实现的那些消息的父类添加通知处理程序。
以下列表描述了日期和时间选择器控件发送的各种通知。
?DTN_DROPDOWN通知父级将要显示嵌入的月历控件。只有当尚未设置DTS_UPDOWN 样式时才发送此通知。有关此通知的更多信息,请参见访问嵌入的月历(MonthCalendar) 控件。
?DTN_CLOSEUP通知父级将要关闭嵌入的月历控件。只有当尚未设置DTS_UPDOWN样式时才发送此通知。
?DTN_DATETIMECHANGE通知父级控件已经发生了更改。
?DTN_FORMAT通知父级需要在回调字段中显示文本。有关此通知和回调字段的更多信息,请参见在日期和时间选择器控件中使用回调字段。
?DTN_FORMATQUERY请求父级提供将在回调字段中显示的字符串所允许的最大大小。处理此通知使控件在任何时候都能正确地显示输出,并减少控件显示范围内的闪烁。有关此通知的更多信息,请参见在日期和时间选择器控件中使用回调字段。
?DTN_USERSTRING通知父级用户已完成编辑日期和时间选择器控件的内容。只有当设置了DTS_APPCANPARSE样式时才发送此通知。
?DTN_WMKEYDOWN用户在回调字段中键入时通知父级。处理此通知以便为日期和时间选择器控件中所支持的非回调字段模拟相同的键盘响应。有关此通知的更多信息,请参见Platform SDK 中的支持DTP 控件中的回调字段。