VS2012下实现CMFCPropertyGridCtrl 内添加日期时间控件

         上图为实现的效果图。


         首先自定义一个类CMFCPropertyGridDateTimeProperty,基类是CMFCPropertyGridProperty。

class CMFCPropertyGridDateTimeProperty :
	public CMFCPropertyGridProperty
{
	DECLARE_DYNAMIC(CMFCPropertyGridDateTimeProperty)
public:
	CMFCPropertyGridDateTimeProperty(const CString& strName, const CString& dtDateTime, LPCTSTR lpszDescr = _T(""), BOOL isDate=TRUE);  
	virtual ~CMFCPropertyGridDateTimeProperty();

	// Overrides  
public:  
	virtual BOOL OnClickValue(UINT uiMsg, CPoint point);	//鼠标点击属性列表“值”的区域触发此函数
	CInnerDateTimeCtrl *m_dtCtrl;	//自定义CDateTimeCtrl类

	// Attributes  
protected:  
	BOOL    m_bIsDate;				//TRUE: 日期类型; FALSE: 时间类型
};

       cpp文件

IMPLEMENT_DYNAMIC(CMFCPropertyGridDateTimeProperty, CMFCPropertyGridProperty)
CMFCPropertyGridDateTimeProperty::CMFCPropertyGridDateTimeProperty(const CString& strName, const CString& strDateTime,   
		LPCTSTR lpszDescr, BOOL isDate) : CMFCPropertyGridProperty(strName, COleVariant(strDateTime), lpszDescr)  
{  
	m_bIsDate=isDate;  
	m_dtCtrl=NULL;  
}


CMFCPropertyGridDateTimeProperty::~CMFCPropertyGridDateTimeProperty(void)
{
}


BOOL CMFCPropertyGridDateTimeProperty::OnClickValue(UINT uiMsg, CPoint point)
{
	ASSERT_VALID(this);
	// m_pWndInPlace是浮动在属性列表上的编辑框
	ASSERT_VALID(m_pWndInPlace);  
	ASSERT(::IsWindow(m_pWndInPlace->GetSafeHwnd()));

	CString str;
	m_pWndInPlace->GetWindowText(str);

	COleDateTime oleTime;
	CString timeStr;
	if (!m_bIsDate)
		timeStr.Format(_T("2016-1-1 %s"), str);
	else
		timeStr.Format(_T("%s 0:0:0"), str);
	oleTime.ParseDateTime(timeStr);

	// m_pWndInPlace的父窗口是CMFCPropertyGridCtrl
	CWnd *pPropertyCtl = (CWnd*)(m_pWndInPlace->GetParent());

	// 需要将本CMFCPropertyGridProperty的指针传递给DateTimeCtrl控件
	m_dtCtrl= new CInnerDateTimeCtrl(this, m_bIsDate);  

	CRect rect;
	m_pWndInPlace->GetWindowRect(rect);
	pPropertyCtl->ScreenToClient(rect);

	// 将原编辑框隐藏,否则m_dtCtrl不能正确显示
	m_pWndInPlace->ShowWindow(SW_HIDE);

	// 调整m_dtCtrl的显示位置
	rect.top -= 3;
	rect.bottom += 5;
	rect.left -= 4;
	// 设置CDateTimeCtrl的显示类型
	DWORD dtsStyle = WS_VISIBLE|WS_CHILD|WS_BORDER;
	if ( !m_bIsDate )
		dtsStyle |= DTS_TIMEFORMAT;		//时间类型
	else
		dtsStyle |= DTS_SHORTDATEFORMAT|DTS_UPDOWN;		//日期类型
	m_dtCtrl->Create (  dtsStyle, rect, pPropertyCtl, 1001 );  
	::SetWindowPos(m_dtCtrl->m_hWnd, HWND_TOPMOST, 0,0,0,0 ,SWP_NOMOVE|SWP_NOSIZE);
	m_dtCtrl->SetTime(oleTime);

	// 让日期控件获得焦点
	m_dtCtrl->SetFocus();
	return TRUE;
}

        这里需要注意的是,日期类型在动态创建的时候需要带DTS_UPDOWN参数,原因我后面再说。

下面是自定义的CInnerDateTimeCtrl类,其基类是CDateTimeCtrl。

class CInnerDateTimeCtrl:public CDateTimeCtrl
{
	DECLARE_DYNAMIC(CInnerDateTimeCtrl)
public:
	CInnerDateTimeCtrl(CMFCPropertyGridProperty *editWnd, BOOL isDate=FALSE);
	virtual ~CInnerDateTimeCtrl();

private:
	CMFCPropertyGridProperty *m_editWnd;
	BOOL m_isDate;
public:
	DECLARE_MESSAGE_MAP()
	afx_msg void OnKillFocus(CWnd* pNewWnd);
	afx_msg void OnNcDestroy();
};
cpp文件
// InnerDateTimeCtrl
IMPLEMENT_DYNAMIC(CInnerDateTimeCtrl, CDateTimeCtrl)
CInnerDateTimeCtrl::CInnerDateTimeCtrl(CMFCPropertyGridProperty *editWnd, BOOL isDate)
{
	m_editWnd = editWnd;
	m_isDate = isDate;
}

CInnerDateTimeCtrl::~CInnerDateTimeCtrl()
{
}

BEGIN_MESSAGE_MAP(CInnerDateTimeCtrl, CDateTimeCtrl)
	ON_WM_KILLFOCUS()
	ON_WM_NCDESTROY()
END_MESSAGE_MAP()


void CInnerDateTimeCtrl::OnKillFocus(CWnd* pNewWnd)
{
	CDateTimeCtrl::OnKillFocus(pNewWnd);

	// TODO: Add your message handler code here
	COleDateTime oleTime;
	GetTime(oleTime);

	CString str = _T("");
	if ( m_isDate )
		str = oleTime.Format(_T("%Y-%m-%d"));
	else
		str = oleTime.Format(_T("%H:%M:%S"));

	// 修改属性列表的值
	m_editWnd->SetValue(str);

	// 自我销毁
	DestroyWindow();
}


void CInnerDateTimeCtrl::OnNcDestroy()
{
	CDateTimeCtrl::OnNcDestroy();

	// TODO: Add your message handler code here
	CDateTimeCtrl::OnNcDestroy();
	// 释放内存
	delete this;
}
这里可以看到日期控件在失去焦点后就自我销毁了,如果是日期类型显示的话,如果不使用DTS_UPDOWN类型,那么创建后控件右侧是一个倒三角的button,点击此button会弹出日历,在日历上选择日期会导致日期控件失去焦点自我销毁,从而导致出错。因此本人为了规避此错误,采用了DTS_UPDOWN类型。


使用此类的方法很简单,头文件中为你的CMFCPropertyGridCtrl声明一个变量m_property。

#include "afxpropertygridctrl.h"

CMFCPropertyGridCtrl m_property;


可以在cpp文件的OnInitDialog函数中加上如下代码:
	// 初始化属性列表
	HDITEM item; 
	item.cxy=100; 
	item.mask = HDI_WIDTH; 
	m_property.GetHeaderCtrl().SetItem(0, &item);

	CMFCPropertyGridProperty* pGroup1 = new CMFCPropertyGridProperty(_T("属性"));
	CMFCPropertyGridProperty *item1 = new CMFCPropertyGridDateTimeProperty(_T("日期"),  
		_T("2016-12-23"), _T("请选择日期"),true);  
	pGroup1->AddSubItem(item1);
	CMFCPropertyGridProperty *item2 = new CMFCPropertyGridDateTimeProperty(_T("时间"),  
		_T("09:00:00"), _T("请选择时间"),false);  
	pGroup1->AddSubItem(item2);
	m_property.AddProperty(pGroup1);
好了,实现完毕!

没有更多推荐了,返回首页