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).
例子程序
截图
源码VS2008