在VB和类似的包容器在属性视图中显示控件的属性,特别是枚举类型的属性时,会有一个下拉按钮,当点击该按钮时,会弹出一个列表框,显示一些友好的文字,供用户选择。而对于某些特殊的属性,如字体等,还会弹出一个对话框来供用户设置属性。
要添加这种功能,你必须实现 IPerPropertyBrowsing接口,
幸运的是,在用MFC设计ActiveX控件时,COleControl已经帮我们实现了这个接口,我们只需要重载COleControl的一些函数就可以实现我们所需要的功能了。这些函数是
virtual BOOL OnGetDisplayString(DISPID dispid, CString& strValue);
virtual BOOL OnGetPredefinedStrings(DISPID dispid, CStringArray* pStringArray, CDWordArray* pCookieArray);
virtual BOOL OnGetPredefinedValue(DISPID dispid, DWORD dwCookie, VARIANT* lpvarOut);
virtual BOOL OnMapPropertyToPage(DISPID dispid, LPCLSID lpclsid, BOOL* pbPageOptional);
分别和IPerPropertyBrowsing的四个接口方法一一对应。其中,前三个就是用来显示友好文字的列表框式的属性设置的,最后一个则是用来显示属性页对话框式的属性设置的。
注:VB首先查询控件的IPerPropertyBrowsing接口,以获得一个属性的显示字符串。当查询失败时,如果可能的话,VB会装载类型库并找到在IDL文件中为这个属性指定的枚举值。如果再次失败,VB会显示实际属性值。
1.建立控件Tppb,添加属性long Week
2.添加连续的7个字符串资源
IDS_WEEK_MONDAY,IDS_WEEK_TUESDAY,......IDS_WEEK_SUNDAY;
相应的字符串分别是
星期一,星期二,......星期日。
3.重载OnGetDisplayString,OnGetPredefinedStrings和OnGetPredefinedValue。
BOOL CTppbCtrl::OnGetDisplayString(DISPID dispid, CString& strValue)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidWeek){
strValue.LoadString(IDS_WEEK_MONDAY+m_week);
return TRUE;
}
return COleControl::OnGetDisplayString(dispid, strValue);
}
BOOL CTppbCtrl::OnGetPredefinedStrings(DISPID dispid, CStringArray* pStringArray, CDWordArray* pCookieArray)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidWeek){
for(int i=0; i<7; i++){
CString str;
str.LoadString(IDS_WEEK_MONDAY+i);
pStringArray->Add(str);
pCookieArray->Add(i);
}
return TRUE;
}
return COleControl::OnGetPredefinedStrings(dispid, pStringArray, pCookieArray);
}
BOOL CTppbCtrl::OnGetPredefinedValue(DISPID dispid, DWORD dwCookie, VARIANT* lpvarOut)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidWeek){
VariantInit(lpvarOut);
lpvarOut->vt = VT_I4;
//和dwCookie一一对应,0号位值就是0,......,6号位的值就是6
lpvarOut->lVal = dwCookie;
return TRUE;
}
return COleControl::OnGetPredefinedValue(dispid, dwCookie, lpvarOut);
}
4.在VB中测试就可以看到Week属性会列出从星期一到星期日共七个选项的列表选择框。
5.添加属性long Param和固有属性Caption
6.新建一属性页(资源为IDD_PROPPAGE_TEST,类为CTestPropPage),属性页中只有一个编辑框IDC_EDIT_CAPTION,和固有属性Caption关联。(新建属性页的步骤不详述,请参考本系列其它文章)
7.重载OnMapPropertyToPage以在设置Param属性时显示对话框
BOOL CTppbCtrl::OnMapPropertyToPage(DISPID dispid, LPCLSID lpclsid, BOOL* pbPageOptional)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidParam){
*lpclsid = CTestPropPage::guid;
*pbPageOptional = TRUE;
return TRUE;
}
return COleControl::OnMapPropertyToPage(dispid, lpclsid, pbPageOptional);
}
注:为什么不在属性页中设置Param属性,而是Caption属性呢,主要是想解释一下,从哪个属性设置中弹出属性页和在该属性页中设置哪个属性并无关联,你也可以在弹出的属性页对话框中设置多个属性。
8.简单修饰一下控件,为控件添加一些初始值
void CTppbCtrl::OnResetState()
{
COleControl::OnResetState(); // Resets defaults found in DoPropExchange
// TODO: Reset any other control state here.
m_week = 0;
m_param = 0;
}
9.可以在VB下测试了
要添加这种功能,你必须实现 IPerPropertyBrowsing接口,
typedef struct tagCALPOLESTR {
ULONG cElems;
OLECHAR ** pElems;
} CALPOLESTR;
typedef struct tagCADWORD {
ULONG cElems;
DWORD * pElems;
} CADWORD;
interface IPerPropertyBrowsing : IUnknown
{
HRESULT GetDisplayString(DISPID dispid, BSTR * lpbstr);
HRESULT MapPropertyToPage(DISPID dispid, CLSID *lpclsid);
HRESULT GetPredefinedStrings(DISPID dispid, CALPOLESTR *lpcasz,
CADWORD *lpcadw);
HRESULT GetPredefinedValue(DISPID dispid, DWORD dwCookie,
VARIANT *lpvarOut);
}
幸运的是,在用MFC设计ActiveX控件时,COleControl已经帮我们实现了这个接口,我们只需要重载COleControl的一些函数就可以实现我们所需要的功能了。这些函数是
virtual BOOL OnGetDisplayString(DISPID dispid, CString& strValue);
virtual BOOL OnGetPredefinedStrings(DISPID dispid, CStringArray* pStringArray, CDWordArray* pCookieArray);
virtual BOOL OnGetPredefinedValue(DISPID dispid, DWORD dwCookie, VARIANT* lpvarOut);
virtual BOOL OnMapPropertyToPage(DISPID dispid, LPCLSID lpclsid, BOOL* pbPageOptional);
分别和IPerPropertyBrowsing的四个接口方法一一对应。其中,前三个就是用来显示友好文字的列表框式的属性设置的,最后一个则是用来显示属性页对话框式的属性设置的。
注:VB首先查询控件的IPerPropertyBrowsing接口,以获得一个属性的显示字符串。当查询失败时,如果可能的话,VB会装载类型库并找到在IDL文件中为这个属性指定的枚举值。如果再次失败,VB会显示实际属性值。
1.建立控件Tppb,添加属性long Week
2.添加连续的7个字符串资源
IDS_WEEK_MONDAY,IDS_WEEK_TUESDAY,......IDS_WEEK_SUNDAY;
相应的字符串分别是
星期一,星期二,......星期日。
3.重载OnGetDisplayString,OnGetPredefinedStrings和OnGetPredefinedValue。
BOOL CTppbCtrl::OnGetDisplayString(DISPID dispid, CString& strValue)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidWeek){
strValue.LoadString(IDS_WEEK_MONDAY+m_week);
return TRUE;
}
return COleControl::OnGetDisplayString(dispid, strValue);
}
BOOL CTppbCtrl::OnGetPredefinedStrings(DISPID dispid, CStringArray* pStringArray, CDWordArray* pCookieArray)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidWeek){
for(int i=0; i<7; i++){
CString str;
str.LoadString(IDS_WEEK_MONDAY+i);
pStringArray->Add(str);
pCookieArray->Add(i);
}
return TRUE;
}
return COleControl::OnGetPredefinedStrings(dispid, pStringArray, pCookieArray);
}
BOOL CTppbCtrl::OnGetPredefinedValue(DISPID dispid, DWORD dwCookie, VARIANT* lpvarOut)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidWeek){
VariantInit(lpvarOut);
lpvarOut->vt = VT_I4;
//和dwCookie一一对应,0号位值就是0,......,6号位的值就是6
lpvarOut->lVal = dwCookie;
return TRUE;
}
return COleControl::OnGetPredefinedValue(dispid, dwCookie, lpvarOut);
}
4.在VB中测试就可以看到Week属性会列出从星期一到星期日共七个选项的列表选择框。
5.添加属性long Param和固有属性Caption
6.新建一属性页(资源为IDD_PROPPAGE_TEST,类为CTestPropPage),属性页中只有一个编辑框IDC_EDIT_CAPTION,和固有属性Caption关联。(新建属性页的步骤不详述,请参考本系列其它文章)
7.重载OnMapPropertyToPage以在设置Param属性时显示对话框
BOOL CTppbCtrl::OnMapPropertyToPage(DISPID dispid, LPCLSID lpclsid, BOOL* pbPageOptional)
{
// TODO: Add your specialized code here and/or call the base class
if(dispid == dispidParam){
*lpclsid = CTestPropPage::guid;
*pbPageOptional = TRUE;
return TRUE;
}
return COleControl::OnMapPropertyToPage(dispid, lpclsid, pbPageOptional);
}
注:为什么不在属性页中设置Param属性,而是Caption属性呢,主要是想解释一下,从哪个属性设置中弹出属性页和在该属性页中设置哪个属性并无关联,你也可以在弹出的属性页对话框中设置多个属性。
8.简单修饰一下控件,为控件添加一些初始值
void CTppbCtrl::OnResetState()
{
COleControl::OnResetState(); // Resets defaults found in DoPropExchange
// TODO: Reset any other control state here.
m_week = 0;
m_param = 0;
}
9.可以在VB下测试了