在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下測試了