MFCPropertyGridCtrl
是VC 2008 pack中的类,实现了如下功能:
(1)界面分面两栏:一栏为属性,一栏为值
如这个图
virtual BOOL Create(DWORD dwStyle,const RECT& rect,CWnd* pParentWnd,UINT nID );
Parameters
[in] rect
A bounding rectangle that specifies the size and position of the window, in client coordinates of pParentWnd.
[in] pParentWnd
Pointer to the parent window. Must not be NULL.
Remarks
To create a property grid control, first call CMFCPropertyGridCtrl::CMFCPropertyGridCtrl to construct a property grid object. Then call CMFCPropertyGridCtrl::Create.
void EnableHeaderCtrl(BOOL bEnable=TRUE,LPCTSTR
lpszLeftColumn=_T("Property"),LPCTSTR lpszRightColumn=_T("Value") );
功能:是否显示表头。
bEnable=TRUE显示表头,如下图

bEnable=FALSE,不显示表头,如下图
显而易见,后两个参数指定了表头名。
void EnableDescriptionArea(BOOL bEnable=TRUE );
功能:是事启用描述区
如下图所示

参见例子
MFCFeaturePackSample/NewControls/Page5.cpp /BOOL CPage5::OnInitDialog()
可研究CMFCPropertyGridCtrl控件。理解vs2008后的MFC新界面系统。
主要CMFCPropertyGridCtrl 数据成员
m_ToolTip | CToolTipCtrl | Tooltip control | |
m_wndHeader | CMFCHeaderCtrl | Property list header control | 如图fig-11 |
m_IPToolTip | CMFCPropertyGridToolTipCtrl | Inplace tooltip control | |
m_wndScrollVert | CScrollBar | Vertical scroll bar | |
m_cListDelimeter | TCHAR | Customized list delimeter character | |
m_rectList | CRect | Properies area | |
m_lstProps | List of top-level properties | ||
m_pSel | CMFCPropertyGridProperty | Current selection | |
Custom colors | |||
m_clrBackground | |||
m_clrText | |||
m_clrGroupBackground | |||
m_clrGroupText | |||
........................... |
功能:disable,双击,组disable
更改。
CMFCPropertyGridProperty由{name, value}组成。
界面绘制主要代码
OnPaint()
{
OnFillBackground
OnDrawList
}
void CMFCPropertyGridCtrl::OnFillBackground(CDC* pDC, CRect rectClient)
{
......
//CBrush m_brBackground;用指定好的画刷绘制背景
pDC->FillRect(rectClient, &m_brBackground);
......
}
}
void CMFCPropertyGridCtrl::OnDrawList(CDC* pDC)
{
//画中间的分隔线
pDC->MoveTo(nXCenter, m_rectList.top - 1);
pDC->LineTo(nXCenter, m_rectList.bottom);
//得到属性项的链表
const CList<CMFCPropertyGridProperty*, CMFCPropertyGridProperty*>& lst = m_bAlphabeticMode ? m_lstTerminalProps : m_lstProps;
for (POSITION pos = lst.GetHeadPosition(); pos != NULL;)
{
CMFCPropertyGridProperty* pProp = lst.GetNext(pos);
//画每个属性项
if (!OnDrawProperty(pDC, pProp))
{
break;
}
}
}
BOOL CMFCPropertyGridCtrl::OnDrawProperty(CDC* pDC, CMFCPropertyGridProperty* pProp) const
{
if (!pProp->IsEnabled())
{
clrTextOld = pDC->SetTextColor(afxGlobalData.clrGrayedText);
}
CRect rectName = pProp->m_Rect;
CRgn rgnClipName;
CRect rectNameClip = rectName;
rectNameClip.bottom = min(rectNameClip.bottom, m_rectList.bottom);
rgnClipName.CreateRectRgnIndirect(&rectNameClip);
pDC->SelectClipRgn(&rgnClipName);
pProp->OnDrawName(pDC, rectName);
CRect rectValue = pProp->m_Rect;
rectValue.left = nXCenter + 1;
CRgn rgnClipVal;
CRect rectValClip = rectValue;
rectValClip.bottom = min(rectValClip.bottom, m_rectList.bottom);
rgnClipVal.CreateRectRgnIndirect(&rectValClip);
pDC->SelectClipRgn(&rgnClipVal);
pProp->OnDrawValue(pDC, rectValue);
}
void CMFCPropertyGridProperty::OnDrawName(CDC* pDC, CRect rect)
{
int nTextHeight = pDC->DrawText(m_strName, rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS);
//计算出文字是被截断
m_bNameIsTruncated = pDC->GetTextExtent(m_strName).cx > rect.Width();
}
void CMFCPropertyGridProperty::OnDrawValue(CDC* pDC, CRect rect)
{
CString strVal = FormatProperty();
pDC->DrawText(strVal, rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS);
}
COLORREF m_clrLine; // Color of the grid lines
BOOL m_bAlphabeticMode; // Use property list in alphabetic (non-"tree") mode
没有皮肤这种概念。所有风格都靠代码画出来。
CMFCPropertyGridCtrl 代码特点。拆分成多个函数。每个函数的代码行数都少,可读性强。
The GetTextExtentPoint32 function computes the width and height of the specified string of text.
///主要事件响应代码///
左键单击
void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
CRect rectClient;
GetClientRect(rectClient);
CMFCPropertyGridProperty::ClickArea clickArea;
CMFCPropertyGridProperty* pHit = HitTest(point, &clickArea);
//与当前的属性项比较,不同则属性项变更
BOOL bSelChanged = pHit != GetCurSel();
SetCurSel(pHit);
if (pHit == NULL)
{
return;
}
switch (clickArea)
{
case CMFCPropertyGridProperty::ClickExpandBox:
pHit->Expand(!pHit->IsExpanded()); //展开/收起子项
break;
case CMFCPropertyGridProperty::ClickName:
pHit->OnClickName(point);
break;
case CMFCPropertyGridProperty::ClickValue:
if (pHit->m_bEnabled)
{
if (EditItem(pHit, &point) && pHit->m_pWndInPlace != NULL)
{
if (pHit->m_rectButton.PtInRect(point))
{
CString strPrevVal = pHit->FormatProperty();
if (::GetCapture() == GetSafeHwnd())
{
ReleaseCapture();
}
pHit->OnClickButton(point);
if (strPrevVal != pHit->FormatProperty())
{
OnPropertyChanged(pHit);
}
}
else if (!bSelChanged || pHit->IsProcessFirstClick())
{
pHit->OnClickValue(WM_LBUTTONDOWN, point);
}
}
}
break;
default:
break;
}
}
//输入鼠标点,判断鼠标点在哪个属性项的矩形边界内,进而测试出鼠标点下的属性项。
CMFCPropertyGridProperty* CMFCPropertyGridCtrl::HitTest(CPoint pt, CMFCPropertyGridProperty::ClickArea* pnArea, BOOL bPropsOnly) const
{
for (POSITION pos = lst.GetHeadPosition(); pos != NULL;)
{
CMFCPropertyGridProperty* pProp = lst.GetNext(pos);
ASSERT_VALID(pProp);
CMFCPropertyGridProperty* pHit = pProp->HitTest(pt, pnArea);
if (pHit != NULL)
{
return pHit;
}
}
}
void CMFCPropertyGridCtrl::SetCurSel(CMFCPropertyGridProperty* pProp, BOOL bRedraw)
{
m_pSel = pProp;
OnChangeSelection//是一个空的虚函数
OnChangeSelection(m_pSel, pOldSelectedItem);
if (pOldSelectedItem != NULL)
{
//CMFCPropertyGridProperty中的空的虚函数
pOldSelectedItem->OnKillSelection(pProp);
}
鼠标单击某项,编辑响应过程
void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
case CMFCPropertyGridProperty::ClickValue:
if (pHit->m_bEnabled)
{
if (EditItem(pHit, &point) && pHit->m_pWndInPlace != NULL)
}
BOOL CMFCPropertyGridCtrl::EditItem(CMFCPropertyGridProperty* pProp, LPPOINT lptClick)
{
ASSERT_VALID(this);
ASSERT_VALID(pProp);
if (!EndEditItem())
{
return FALSE;
}
if (pProp->IsGroup() && !pProp->m_bIsValueList)
{
return FALSE;
}
if (pProp->OnEdit(lptClick))
{
pProp->Redraw();
SetCurSel(pProp);
SetCapture();
}
return TRUE;
}
CMFCPropertyGridProperty
{
BOOL m_bEnabled;//是否允许编辑
CWnd* m_pWndInPlace; // Pointer to InPlace editing window
CComboBox* m_pWndCombo; // Pointer to combbox
CSpinButtonCtrl* m_pWndSpin; // Pointer to spin button
CMFCPropertyGridCtrl* m_pWndList; // Pointer to the PropertyList window
CMFCPropertyGridProperty* m_pParent; // Parent property (NULL for top-level properties)
enum ClickArea
{
ClickExpandBox,
ClickName,
ClickValue,
ClickDescription
};
};
禁止扩展
void Expand(BOOL bExpand = TRUE);
m_bEnabled
void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{ switch (clickArea)
{
case CMFCPropertyGridProperty::ClickExpandBox:
pHit->Expand(!pHit->IsExpanded());
break;
..................................
}
编辑完
virtual BOOL CMFCPropertyGridProperty::OnEndEdit();
///双击
if (m_pSel->GetRect().PtInRect(point))
{
m_pSel->OnDblClk(point);
}
出现编辑框
void CMFCPropertyGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
if (EditItem(pHit, &point) && pHit->m_pWndInPlace != NULL)
}
BOOL CMFCPropertyGridCtrl::EditItem(CMFCPropertyGridProperty* pProp, LPPOINT lptClick)
{
if (pProp->OnEdit(lptClick))
}
BOOL CMFCPropertyGridProperty::OnEdit(LPPOINT /*lptClick*/)
{
m_pWndInPlace = CreateInPlaceEdit(rectEdit, bDefaultFormat);
}
CMFCPropertyGridProperty子类
CCheckBoxProp
CPasswordProp
CSliderProp
CBoundedNumberPairProp
CBoundedNumberSubProp
CIconListProp
CComboBoxExProp
COwnerDrawDescrProp
CTwoButtonsProp
CCustomDlgProp
响应点击属性项Combox框中的下拉项事件
ON_CBN_SELENDOK(AFX_PROPLIST_ID_INPLACE, &CMFCPropertyGridCtrl::OnSelectCombo)
void CMFCPropertyGridCtrl::OnSelectCombo()
{
..............
ASSERT_VALID(m_pSel);
m_pSel->OnSelectCombo();
}
void CMFCPropertyGridProperty::OnSelectCombo()
{
ASSERT_VALID(this);
ASSERT_VALID(m_pWndCombo);
ASSERT_VALID(m_pWndInPlace);
int iSelIndex = m_pWndCombo->GetCurSel();
if (iSelIndex >= 0)
{
CString str;
m_pWndCombo->GetLBText(iSelIndex, str);
m_pWndInPlace->SetWindowText(str);
OnUpdateValue();
}
}
CComboBox ClassA
Each message-map entry takes the following form:
ON_Notification( id, memberFxn )
where id specifies the child-window ID of the combo-box control sending the notification and memberFxn is the name of the parent member function you have written to handle the notification.
The parent's function prototype is as follows:
afx_msg void memberFxn( );
ON_CBN_SELENDOK The user selects an item and then either presses the ENTER key or clicks the DOWN ARROW key to hide the list box of a combo box. This notification message is sent before the CBN_CLOSEUP message to indicate that the user's selection should be considered valid. The CBN_SELENDCANCEL or CBN_SELENDOK notification message is sent even if the CBN_CLOSEUP notification message is not sent (as in the case of a combo box with the CBS_SIMPLE style).
例子程序
截图