关于属性页,这里先翻译msdn上一段关于属性页的介绍。
用户通过属性页来操作控件的属性,用户可以设置一个或多个属性页,每个属性页上可以显示控件的某些属性。这些属性既可以来自一个控件,也可以来自多个控件,也就是说一个属性页上可以显示多个控件的属性。
每个ActiveX控件属性页都是一个进程内对象,拥有它自己的CLSID,每个属性页均实现了IPropertyPage接口。IPropertyPage::SetObjects是用来将控件对象的接口指针(IUnknown)传递给属性页的。
MFC的COlePropertyPage也实现了IPropertyPage接口,它将控件对象指针的保存在一个IDispatch接口指针的数组中。该数组可以通过COlePropertyPage::GetObjectArray()访问,这样就可以通过IDispatch接口来访问控件的属性了,令人头疼的是通过IDispatch来访问控件属性,实在有够麻烦,MFC提供了COleDispatchDriver来帮助访问,可惜,也仅仅是能稍微简化一些操作而已。其实,MFC为了自己方便,在COlePropertyPage还提供了一组函数来帮助访问控件的属性,只不过这组函数没公布在msdn中罢了,下面是这组函数的声明:
// DDP_ property get/set helper routines
BOOL SetPropText(LPCTSTR pszPropName, BYTE &Value);
BOOL GetPropText(LPCTSTR pszPropName, BYTE* pValue);
BOOL SetPropText(LPCTSTR pszPropName, short &Value);
BOOL GetPropText(LPCTSTR pszPropName, short* pValue);
BOOL SetPropText(LPCTSTR pszPropName, int &Value);
BOOL GetPropText(LPCTSTR pszPropName, int* pValue);
BOOL SetPropText(LPCTSTR pszPropName, UINT &Value);
BOOL GetPropText(LPCTSTR pszPropName, UINT* pValue);
BOOL SetPropText(LPCTSTR pszPropName, long &Value);
BOOL GetPropText(LPCTSTR pszPropName, long* pValue);
BOOL SetPropText(LPCTSTR pszPropName, DWORD &Value);
BOOL GetPropText(LPCTSTR pszPropName, DWORD* pValue);
BOOL SetPropText(LPCTSTR pszPropName, CString &Value);
BOOL GetPropText(LPCTSTR pszPropName, CString* pValue);
BOOL SetPropText(LPCTSTR pszPropName, float &Value);
BOOL GetPropText(LPCTSTR pszPropName, float* pValue);
BOOL SetPropText(LPCTSTR pszPropName, double &Value);
BOOL GetPropText(LPCTSTR pszPropName, double* pValue);
BOOL SetPropCheck(LPCTSTR pszPropName, int Value);
BOOL GetPropCheck(LPCTSTR pszPropName, int* pValue);
BOOL SetPropRadio(LPCTSTR pszPropName, int Value);
BOOL GetPropRadio(LPCTSTR pszPropName, int* pValue);
BOOL SetPropIndex(LPCTSTR pszPropName, int Value);
BOOL GetPropIndex(LPCTSTR pszPropName, int* pValue);
在一般情况下,我们并不用直接访问控件的属性,一切都由框架帮助做了(框架利用了DoDateExchange,DoDataExchange又用了上面的SetPropText/GetPropText函数组)。
但是,有时候,我们希望能在控件中直接访问控件的属性和方法。对于普通属性,使用上面的GetPropText和SetPropText足以满足需要,但是对于带参数的属性和方法,就只好老老实实的用COleDispatchDriver来InvokeHelper了。
下面是在属性页中访问控件属性和方法的例子toop.
1.控件中设置了一个字符串数组CStringArray m_saItems,提供了方法long Add(LPCTSTR strItem)和get/set method属性BSTR Item(long lItem)来访问数组中的某项字符串,另外还有一个只读属性long Count(在添加属性的向导中,设置为get/set methods类型的属性,并去掉SetCount即是设置为只读属性了)
2.控件另外设置了一member variable属性OLE_COLOR Color
3.属性和方法的实现如下:
void CToppCtrl::OnColorChanged()
{
// TODO: Add notification handler code
SetModifiedFlag();
}
long CToppCtrl::Add(LPCTSTR strItem)
{
// TODO: Add your dispatch handler code here
return m_saItems.Add(strItem);
return 0;
}
BSTR CToppCtrl::GetItem(long nItem)
{
CString strResult;
// TODO: Add your property handler here
if(nItem >= 0 && nItem < m_saItems.GetSize()){
strResult = m_saItems[nItem];
}
return strResult.AllocSysString();
}
void CToppCtrl::SetItem(long nItem, LPCTSTR lpszNewValue)
{
// TODO: Add your property handler here
if(nItem >= 0 && nItem < m_saItems.GetSize()){
m_saItems[nItem] = lpszNewValue;
}
SetModifiedFlag();
}
long CToppCtrl::GetCount()
{
// TODO: Add your property handler here
return m_saItems.GetSize();
return 0;
}
控件编完后,就是属性页这个重头戏了:
1.界面,对于控件中字符串数组,添加了一编辑框和一按钮("添加项目")来调用控件的Add方法;添加了一列表框来调用控件的Item属性填充列表框。
2.界面,对于控件的Color属性,添加了一按钮("设置颜色")和一静态文本框(Caption为"看看我的颜色吧",ID为IDC_STATIC_COLOR)来设置颜色和获得颜色属性,文本框的文本背景颜色即为获得的颜色。
3.添加成员函数BOOL AddItem(LPCTSTR lpszItem)用来调用控件的Add方法添加字符串,添加CString GetItem(long lItem)函数来获得字符串数组中的lItem项对应的字符串,添加long GetCount()来获得数组中字符串的数目;添加COLORREF GetColor()函数来获得控件的Color属性,添加SetColor()函数来设置控件的Color属性,这些函数的实现如下:
BOOL CToppPropPage::AddItem(LPCTSTR lpszItem)
{
USES_CONVERSION;
COleDispatchDriver PropDispDriver;
BOOL bResult = FALSE;
ULONG nObjects = 0;
LPDISPATCH* ppDisp = GetObjectArray(&nObjects);
for (ULONG i = 0; i < nObjects; i++)
{
DISPID dwDispID;
LPCOLESTR lpOleStr = T2COLE("Add");
if (SUCCEEDED(ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
{
PropDispDriver.AttachDispatch(ppDisp[i], FALSE);
BYTE rgbParams[] = VTS_BSTR;
long lret = 0;
PropDispDriver.InvokeHelper(dwDispID, DISPATCH_METHOD, VT_I4, &lret, rgbParams, lpszItem);
PropDispDriver.DetachDispatch();
bResult = TRUE;
}
}
return bResult;
}
CString CToppPropPage::GetItem(long lItem)
{
CString str = _T("");
USES_CONVERSION;
COleDispatchDriver PropDispDriver;
ULONG nObjects = 0;
LPDISPATCH* ppDisp = GetObjectArray(&nObjects);
for (ULONG i = 0; i < nObjects; i++)
{
DISPID dwDispID;
LPCOLESTR lpOleStr = T2COLE("Item");
if (SUCCEEDED(ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
{
PropDispDriver.AttachDispatch(ppDisp[i], FALSE);
BYTE rgbParams[] = VTS_I4;
PropDispDriver.InvokeHelper(dwDispID, DISPATCH_PROPERTYGET, VT_BSTR, &str, rgbParams, lItem);
PropDispDriver.DetachDispatch();
}
}
return str;
}
COLORREF CToppPropPage::GetColor()
{
long l = 0;
GetPropText("Color", &l);
COLORREF cr = RGB(0, 0, 0);
::OleTranslateColor((OLE_COLOR)l, NULL, &cr);
return cr;
}
void CToppPropPage::SetColor(COLORREF cr)
{
SetPropText("Color", cr);
}
long CToppPropPage::GetCount()
{
long lcount = 0;
GetPropText("Count", &lcount);
return lcount;
}
4.添加按钮("添加项目")响应函数
void CToppPropPage::OnButtonAdditem()
{
// TODO: Add your control notification handler code here
UpdateData();
AddItem(m_strItem); //m_strItem为编辑框关联的CString对象
//填充列表框
long lcount = 0;
GetPropText("Count", &lcount);
m_list.ResetContent(); //m_list为列表框关联的CListBox对象
for(int i=0; i m_list.AddString(GetItem(i));
}
}
5.添加按钮("设置颜色")响应函数来设置控件的Color属性
void CToppPropPage::OnButtonSetcolor()
{
// TODO: Add your control notification handler code here
CColorDialog dlg;
if(dlg.DoModal() == IDOK){
long lcolor = dlg.GetColor();
SetPropText("Color", lcolor);
GetDlgItem(IDC_STATIC_COLOR)->Invalidate();
}
}
6.添加WM_CTLCOLOR消息响应函数,在函数里获得控件的Color属性,并用该Color设置静态文本框的文本背景颜色
HBRUSH CToppPropPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = COlePropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
if(nCtlColor == CTLCOLOR_STATIC){
COLORREF cr = GetColor();
pDC->SetBkColor(cr);
}
// TODO: Return a different brush if the default is not desired
return hbr;
}
7.OK了,编译,可以在ActiveX Control Container中测试了
下面是控件和属性页效果图,因为后添加,加上了其它的许多效果,请参考本系列后续文章