在VB的屬性視圖中,還有一個有意思的功能是將屬性列在不同的類別,如,外觀,行為,資料等等。這種功能是怎麼來的,我自己的控制項中的自訂的屬性是不是也能列在這些類別中,我能不能建立自己的類別呢。
很簡單,在你的控制項中實現一個介面ICategorizeProperties就可以了,這個介面只有兩個方法
HRESULT MapPropertyToCategory(DISPID dispid, PROPCAT* ppropcat);
HRESULT GetCategoryName(PROPCAT propcat, LCID lcid, BSTR* pbstrName);
PROPCAT實際上就是一int,表示某種類別編號
MapPropertyToCategory就是用來設定相應dispid的屬性的類別的
GetCategoryName應是用來設定你自訂的類別(編號為propcat)的顯示字串的
看起來似乎挺簡單的,可惜的是,這個介面沒有定義,COleControl也沒有幫我們做任何的工作。幸好,對於添加介面,我們已經有了經驗了,前面的文章有過許多例子了。
我們有上一文中的例子tppb
1.在.odl上添加新介面定義
// ICategorizeProperties介面定義
[ uuid(4D07FC10-F931-11CE-B001-00AA006884E5),
helpstring("ICategorizeProperties Interface"), pointer_default (unique) ]
interface ICategorizeProperties : IUnknown
{
typedef [public] int PROPCAT;
const int PROPCAT_Nil = -1;
const int PROPCAT_Misc = -2;
const int PROPCAT_Font = -3;
const int PROPCAT_Position = -4;
const int PROPCAT_Appearance = -5;
const int PROPCAT_Behavior = -6;
const int PROPCAT_Data = -7;
const int PROPCAT_List = -8;
const int PROPCAT_Text = -9;
const int PROPCAT_Scale = -10;
const int PROPCAT_DDE = -11;
HRESULT MapPropertyToCategory(DISPID dispid, PROPCAT* ppropcat);
HRESULT GetCategoryName(PROPCAT propcat, LCID lcid, BSTR* pbstrName);
};
2.添加嵌套類,作為ICategorizeProperties介面的實作類別
a.在tppbctl.h中添加聲明
......
DECLARE_EVENT_MAP()
public:
BEGIN_INTERFACE_PART(CategorizeProperties, ICategorizeProperties)
STDMETHOD(MapPropertyToCategory)(DISPID dispid, PROPCAT* ppropcat);
STDMETHOD(GetCategoryName)(PROPCAT propcat, LCID lcid, BSTR* pbstrName);
END_INTERFACE_PART(CategorizeProperties)
DECLARE_INTERFACE_MAP()
// Dispatch and event IDs
public:
enum {
//{{AFX_DISP_ID(CTppbCtrl)
dispidWeek = 1L,
dispidParam = 2L,
//}}AFX_DISP_ID
};
......
b.在tppbctl.cpp中添加實現代碼
STDMETHODIMP_(ULONG) CTppbCtrl::XCategorizeProperties::AddRef()
{
METHOD_PROLOGUE_EX_(CTppbCtrl, CategorizeProperties)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CTppbCtrl::XCategorizeProperties::Release()
{
METHOD_PROLOGUE_EX_(CTppbCtrl, CategorizeProperties)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CTppbCtrl::XCategorizeProperties::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CTppbCtrl, CategorizeProperties)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CTppbCtrl::XCategorizeProperties::MapPropertyToCategory(DISPID dispid, PROPCAT* ppropcat)
{
METHOD_PROLOGUE_EX_(CTppbCtrl, CategorizeProperties)
if(dispid == dispidWeek){
*ppropcat = PROPCAT_Data;
return S_OK;
}
else if(dispid == dispidParam){
*ppropcat = 1;
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP CTppbCtrl::XCategorizeProperties::GetCategoryName(PROPCAT propcat, LCID lcid, BSTR* pbstrName)
{
METHOD_PROLOGUE_EX_(CTppbCtrl, CategorizeProperties)
if(propcat == 1){
*pbstrName = ::SysAllocString(L"參數");
return S_OK;
}
return E_FAIL;
}
註:這裡將Week屬性列入了資料類別(PROPCAT_Data)中,將Param屬性列入自訂的類別"參數"中,類別編號為1,對於自訂的類別編號,必須大於0
3.將ICategorizeProperties介面添加到控制項的介面映射表中
a.在tppbctl.h中添加介面映射聲明
public:
BEGIN_INTERFACE_PART(CategorizeProperties, ICategorizeProperties)
STDMETHOD(MapPropertyToCategory)(DISPID dispid, PROPCAT* ppropcat);
STDMETHOD(GetCategoryName)(PROPCAT propcat, LCID lcid, BSTR* pbstrName);
END_INTERFACE_PART(CategorizeProperties)
DECLARE_INTERFACE_MAP()
b.在tppbctl.cpp中添加ICategorizeProperties到映射表中
BEGIN_INTERFACE_MAP(CTppbCtrl, COleControl)
INTERFACE_PART(CTppbCtrl, IID_IDispatch, Dispatch)
INTERFACE_PART(CTppbCtrl, DIID__DTppb, Dispatch)
INTERFACE_PART(CTppbCtrl, IID_ICategorizeProperties, CategorizeProperties)
END_INTERFACE_MAP()
4.現在編譯的話,會發現少了很多的定義,需要從.odl中產生相應的介面定義檔案,在檔案清單中找到tppb.odl,點右鍵,選擇Settings,在Output header file name中輸入tppbuuid.h(不存在的任何檔案名稱都可),確定後,再點右鍵,選擇Compile tppb.odl,即產生tppbuuid.h檔案了。
5.在tppbctl.h檔案中#include "tppbuuid.h"
6.建立一initIIDs.cpp檔案,輸入代碼如下:
#include <ole2.h>
#include <initguid.h>
#include "tppbuuid.h"
在檔案清單中,找到initIIDs.cpp,點右鍵,在C/C++項中,選擇Category為Precompiled Headers,並設定為Not using precompiled headers
7.編譯,如果連結出現DllMain之類的錯誤,請移除initIIDs.cpp,然後再加入,並重新設定Precompiled Headers,再編譯即可。
8.好了,在VB下測試就可以了