MFC的CMFCPropertyGridCtrl控件虽然可以把值设置成True和False,可惜的是它是以组合框来呈现的。可能某些场合中,我们更希望它可以像复选框一样。
通过子类化CMFCPropertyGridProperty完成
实现代码:
/*
MFCPropertyCheckBox.h
*/
#pragma once
#include "afxpropertygridctrl.h"
class CMFCPropertyCheckBox : public CMFCPropertyGridProperty
{
public:
CMFCPropertyCheckBox(const CString& strGroupName, bool bIsChecked = FALSE, LPCTSTR lpszDescr = NULL);
virtual void OnDrawValue(CDC* pDC, CRect rect);
virtual BOOL OnEdit(LPPOINT lptClick);
};
/*
MFCPropertyCheckBox.cpp
*/
#include "stdafx.h"
#include "MFCPropertyCheckBox.h"
CMFCPropertyCheckBox::CMFCPropertyCheckBox(const CString& strName, bool bIsChecked, LPCTSTR lpszDescr)
: CMFCPropertyGridProperty(strName, COleVariant(), lpszDescr)
{
m_varValue = _variant_t(bIsChecked);
m_varValueOrig = _variant_t(bIsChecked);
}
void CMFCPropertyCheckBox::OnDrawValue(CDC * pDC, CRect rect)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT_VALID(m_pWndList);
if (m_varValue.vt == VT_BOOL)
{
rect.right = rect.left + (rect.bottom - rect.top) * 2;
//画复选框,方法一(推荐)
CMFCVisualManager::GetInstance()->OnDrawCheckBox(pDC, rect, m_varValue.boolVal, m_varValue.boolVal, m_bEnabled);
//画复选框,方法二
/*UINT uStyle = DFCS_BUTTONCHECK;
if (m_varValue.boolVal)
uStyle |= DFCS_CHECKED ;//| DFCS_PUSHED
pDC->DrawFrameControl(rect, DFC_BUTTON, uStyle);*/
}
}
BOOL CMFCPropertyCheckBox::OnEdit(LPPOINT lptClick)
{
ASSERT_VALID(this);
ASSERT_VALID(m_pWndList);
if (m_varValue.vt == VT_BOOL)
{
if (m_varValue.boolVal)
m_varValue.boolVal = VARIANT_FALSE;
else
m_varValue.boolVal = VARIANT_TRUE;
Redraw();//重绘
this->m_pWndList->OnPropertyChanged(this);//产生值变更事件
}
return FALSE;//返回TRUE会导致其他控件可能无法获得焦点
}
原理很简单,重写OnDrawValue()和OnEdit()即可。
那为什么要重写OnDrawValue()和OnEdit()呢?
OnDrawValue()看命名就知道,功能是画"Value"(左边列的单元格为"Name",右边列的单元格为"Value")。在CMFCPropertyGridProperty中,OnDrawValue()的主要作用是画文字,重写后的功能是画一个复选框,这里给出了两种画复选框的方法,推荐使用方法一,其实在CMFCPropertyGridCtrl控件中,组合框的下拉按钮、展开折叠按钮等都是用方法一的方式画出来的。两种方法都可以画一些GUI控件,感兴趣的可以自己琢磨。
当然了,也是有OnDrawName()的,可以自己实现"Name"单元格的自定义。
OnEdit()的主要作用是在每次点击"Value"时,为"Value"所在的单元格创建一个编辑框。复选框并不需要文本编辑,同时OnEdit()是每次点击都会被执行的,正好可以用它作为点击复选框的事件处理。
在OnEdit()中m_varValue用于保存选中状态,因此可以继续延用SetValue()来设置值,调整复选框。
SetValue(_variant_t(true));//设置选中
SetValue(_variant_t(false));//取消选中
OnPropertyChanged(this)用于发送一个AFX_WM_PROPERTY_CHANGED消息。
使用示例:
CMFCPropertyGridProperty *pGroup = new CMFCPropertyGridProperty(_T("参数"));
//构造函数的第二个参数为复选框的初始状态
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性1"), TRUE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性2"), FALSE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性3"), FALSE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性4"), FALSE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性5"), FALSE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性6"), FALSE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性7"), TRUE, _T("说明")));
pGroup->AddSubItem(new CMFCPropertyCheckBox(_T("属性8"), TRUE, _T("说明")));
m_pgcCtrl.AddProperty(pGroup);
m_pgcCtrl.ExpandAll();
...
ON_REGISTERED_MESSAGE(AFX_WM_PROPERTY_CHANGED, OnPgcChanged)
//AFX_WM_PROPERTY_CHANGED消息响应
LRESULT CXXXXDlg::OnPgcChanged(WPARAM wParam, LPARAM lParam)
{
CMFCPropertyGridProperty* pPGP = (CMFCPropertyGridProperty*)lParam;
COleVariant b = pPGP->GetValue();
if (b.vt == VT_BOOL)
{
if (b.boolVal == VARIANT_TRUE)
{//选中
}
else
{//取消选中
}
return 1;
}
return 0;
}