现在的位置: 首页 > 综合 > 正文

MFCPropertyGridCtrl分析

2017年12月11日 ⁄ 综合 ⁄ 共 8343字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.