MFC ActiveX 控制項: 使用字型
如果您的 ActiveX 控制項顯示文字時,您可以允許控制項使用者藉由變更字型屬性,變更文字外觀。字型屬性實作為字型物件,而且可以是下列其中一種: 內建或自訂。內建 Font 屬性會是預先實作的字型屬性,您可以使用加入屬性精靈來新增。自訂 Font 屬性不 preimplemented,和控制項開發人員決定屬性的行為及用途。
本文涵蓋下列主題:
使用內建 Font 屬性
在控制項中使用自訂字型屬性
使用內建 Font 屬性
內建 Font 屬性由類別 preimplemented COleControl。此外,標準的字型屬性頁也是可用,允許使用者變更 font 物件,例如其名稱、 大小和樣式的各種不同的屬性。
存取字型物件,可透過 GetFont, SetFont,以及 InternalGetFont 函式的COleControl。控制項使用者可存取的 font 物件,透過GetFont和SetFont中相同的方式來取得或設定任何其他屬性的函式。在控制項中需要字型物件的存取權時,請使用InternalGetFont函式。
所討論的 MFC ActiveX 控制項: 屬性,將內建屬性就很簡單的事 加入屬性精靈。您選擇 [字型] 屬性,並加入屬性精靈會自動插入控制項的分派對應到內建 Font 項目。
若要新增內建的字型屬性,使用加入屬性精靈
載入控制項專案。
在 [類別檢視中,展開您的控制項程式庫節點。
您的控制項 (程式庫節點的第二個節點) 的 [介面] 節點上按一下滑鼠右鍵來開啟快顯功能表。
從快速鍵功能表中,按一下 [ 新增 ,然後按一下 [ 加入屬性。
如此會開啟 [加入屬性精靈。
在屬性名稱 方塊中,按一下 字型。
按一下 [完成]。
加入屬性精靈會將下列這一行加入控制項的分派對應,位於控制項類別實作檔:
DISP_STOCKPROP_FONT()
此外,加入屬性精靈會將下面這一行加入控制項。IDL 檔:
[id(DISPID_FONT)] IFontDisp*Font;
內建的 [標題] 屬性是可以使用內建的字型屬性資訊來繪製的文字屬性的範例。控制項中加入內建的 [標題] 屬性會使用類似於用於內建 Font 屬性的步驟。
若要新增內建的標題屬性使用加入屬性精靈
載入控制項專案。
在 [類別檢視中,展開您的控制項程式庫節點。
您的控制項 (程式庫節點的第二個節點) 的 [介面] 節點上按一下滑鼠右鍵來開啟快顯功能表。
從快速鍵功能表中,按一下 [ 新增 ,然後按一下 [ 加入屬性。
如此會開啟 [加入屬性精靈。
在屬性名稱 方塊中,按一下 標題。
按一下 [完成]。
加入屬性精靈會將下列這一行加入控制項的分派對應,位於控制項類別實作檔:
DISP_STOCKPROP_CAPTION()
修改 OnDraw 函式
預設實作的OnDraw的所有控制項中顯示的文字使用的 Windows 系統字型。這表示您必須修改OnDraw藉由選取字型物件放入裝置內容的程式碼。若要執行這項操作,呼叫 COleControl::SelectStockFont ,並傳遞控制項的裝置內容,如下列範例所示:
CFont* pOldFont;
TEXTMETRIC tm;
const CString& strCaption = InternalGetText();
pOldFont = SelectStockFont(pdc);
pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH )GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
pdc->GetTextMetrics(&tm);
pdc->SetTextAlign(TA_CENTER | TA_TOP);
pdc->ExtTextOut((rcBounds.left + rcBounds.right) / 2,
(rcBounds.top + rcBounds.bottom - tm.tmHeight) / 2,
ETO_CLIPPED, rcBounds, strCaption, strCaption.GetLength(), NULL);
pdc->SelectObject(pOldFont);
後OnDraw函式已修改為適用於該字型物件、 在控制項中的任何文字會顯示從控制項的內建 Font 屬性的特性。
在控制項中使用自訂字型屬性
除了內建的字型屬性,ActiveX 控制項可以有自訂 Font 屬性。若要加入自訂 font 屬性,您必須:
使用加入屬性精靈來實作自訂 Font 屬性。
處理字型告知。
實作新字型告知介面。
實作自訂 Font 屬性
若要實作自訂 Font 屬性,您可以使用 [加入屬性精靈來加入屬性,然後修改一些程式碼。下列章節說明如何加入自訂HeadingFont範例控制項的屬性。
若要加入自訂 Font 屬性使用加入屬性精靈
載入控制項專案。
在 [類別檢視中,展開您的控制項程式庫節點。
您的控制項 (程式庫節點的第二個節點) 的 [介面] 節點上按一下滑鼠右鍵來開啟快顯功能表。
從快速鍵功能表中,按一下 [ 新增 ,然後按一下 [ 加入屬性。
如此會開啟 [加入屬性精靈。
在屬性名稱方塊中,輸入屬性的名稱。例如,使用 HeadingFont。
對於實作類型,按一下 [ Get/Set 方法。
在屬性型別 ] 方塊中選取 IDispatch 1 的屬性的型別。
按一下 [完成]。
加入屬性精靈會建立程式碼,以將HeadingFont自訂屬性,以CSampleCtrl類別和範例。IDL 檔。因為HeadingFont會取得或設定屬性的型別,加入屬性精靈會修改CSampleCtrl類別的分派對應,以包含DISP_PROPERTY_EX_IDDISP_PROPERTY_EX巨集項目:
DISP_PROPERTY_EX_ID(CMyAxFontCtrl, "HeadingFont", dispidHeadingFont,
GetHeadingFont, SetHeadingFont, VT_DISPATCH)
DISP_PROPERTY_EX巨集建立關聯HeadingFont與它相對應的屬性名稱CSampleCtrl類別取得和設定方法, GetHeadingFont和SetHeadingFont。指定了屬性值的型別 ; 如此一來, VT_FONT。
加入屬性精靈還會在控制項標頭檔 (。H) 中的GetHeadingFont和SetHeadingFont ,並將其函式樣板加入在控制項實作檔 (。CPP):
IDispatch* CWizardGenCtrl::GetHeadingFont(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your dispatch handler code here
return NULL;
}
void CWizardGenCtrl::SetHeadingFont(IDispatch* /*pVal*/)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your property handler code here
SetModifiedFlag();
}
最後,加入屬性精靈會修改控制項。IDL 檔,藉由新增的項目HeadingFont屬性:
[id(1)] IDispatch* HeadingFont;
修改控制項程式碼
既然您已新增HeadingFont控制項的屬性,您必須變更某些控制項標頭及實作檔的完整支援新的屬性。
在控制項標頭檔 (。H) 中,加入下列受保護的成員變數的宣告:
protected:
CFontHolder m_fontHeading;
在控制項實作檔 (。CPP) 裡,執行下列動作:
初始化m_fontHeading控制項的建構函式中。
CMyAxFontCtrl::CMyAxFontCtrl() : m_fontHeading(&m_xFontNotification) { InitializeIIDs(&IID_DNVC_MFC_AxFont, &IID_DNVC_MFC_AxFontEvents); }
宣告為靜態 FONTDESC 結構包含字型的預設屬性。
static const FONTDESC _fontdescHeading = { sizeof(FONTDESC), OLESTR("MS Sans Serif"), FONTSIZE( 12 ), FW_BOLD, ANSI_CHARSET, FALSE, FALSE, FALSE };
在控制項中DoPropExchange成員函式、 結尾加入對PX_Font函式。這會提供初始化及自訂字型屬性的保存性。
void CMyAxFontCtrl::DoPropExchange(CPropExchange* pPX) { ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); COleControl::DoPropExchange(pPX); // [...other PX_ function calls...] PX_Font(pPX, _T("HeadingFont"), m_fontHeading, &_fontdescHeading); }
完成實作控制GetHeadingFont成員函式。
IDispatch* CMyAxFontCtrl::GetHeadingFont(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return m_fontHeading.GetFontDispatch(); }
完成實作控制SetHeadingFont成員函式。
void CMyAxFontCtrl::SetHeadingFont(IDispatch* pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_fontHeading.InitializeFont(&_fontdescHeading, pVal); OnFontChanged(); //notify any changes SetModifiedFlag(); }
將控制項修改OnDraw成員函式來定義變數,以保留之前選取的字型。
CFont* pOldHeadingFont;
將控制項修改OnDraw成員函式來將自訂字型選取放入裝置內容,藉由新增下列程式行會無論是要使用的字型。
pOldHeadingFont = SelectFontObject(pdc, m_fontHeading);
將控制項修改OnDraw成員函式以之前的字型選取放入裝置內容上一步,由已使用字型之後加入下列這一行。
pdc->SelectObject(pOldHeadingFont);
尚未實作自訂 Font 屬性之後,標準字型屬性頁應該實作,允許控制項使用者變更控制項的目前的字型。若要加入屬性頁 ID 為標準的字型屬性頁,請插入下的面這一行之後BEGIN_PROPPAGEIDS巨集:
PROPPAGEID(CLSID_CFontPropPage)
您也必須遞增的計數參數您BEGIN_PROPPAGEIDS巨集的原因。下面這一行可說明這點:
BEGIN_PROPPAGEIDS(CMyAxFontCtrl, 2)
在進行這些變更之後,請重建整個專案以加入其他功能。
處理字型告知
在大多數情況下,控制項需要知道何時修改過的 font 物件的特性。每個 font 物件所能提供通知,它會藉由呼叫成員函式的變更時 IFontNotification 所實作的介面COleControl。
如果控制項是使用內建 Font 屬性,其通知由OnFontChanged成員函式的COleControl。當您加入自訂 font 屬性時,您可以讓它們使用相同的實作。在前述範例中,這透過傳遞 &m_xFontNotification 初始化時 m_fontHeading 成員變數。
實作多個字型物件介面
如上圖所示的實線顯示這兩個字型物件正在使用相同的實作 IFontNotification。如果您想要分辨哪個字型變更,這可能會造成問題。
區別控制項的字型物件告知的方法之一是,若要建立的個別實作 IFontNotification 在控制項中的每個字型物件介面。這項技術可讓您最佳化您的繪圖程式碼,藉由升級只有字串或使用最近修改的字型的字串。下列章節將說明實作個別告知介面,則為第二個字型屬性的必要步驟。第二個 font 屬性會被假設為HeadingFont在前一節中所加入的屬性。
實作新字型告知介面
若要區別兩個或多個字型的告知,必須為每個控制項中使用的字型實作新的告知介面。下列章節說明如何藉由修改控制項標頭及實作檔實作新字型告知介面。
加入標頭檔的項目
在控制項標頭檔 (。H) 中,在類別宣告中加入下列行:
protected:
BEGIN_INTERFACE_PART(HeadingFontNotify, IPropertyNotifySink)
INIT_INTERFACE_PART(CMyAxFontCtrl, HeadingFontNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(HeadingFontNotify)
這會建立的實作IPropertyNotifySink介面稱為HeadingFontNotify。這個新介面包含方法呼叫OnChanged。
新增至實作檔
在程式碼,以初始化標題中的字型 (控制項的建構函式) 中,變更&m_xFontNotification到&m_xHeadingFontNotify。然後加入下列程式碼:
STDMETHODIMP_(ULONG) CMyAxFontCtrl::XHeadingFontNotify::AddRef()
{
METHOD_MANAGE_STATE(CMyAxFontCtrl, HeadingFontNotify)
return 1;
}
STDMETHODIMP_(ULONG) CMyAxFontCtrl::XHeadingFontNotify::Release()
{
METHOD_MANAGE_STATE(CMyAxFontCtrl, HeadingFontNotify)
return 0;
}
STDMETHODIMP CMyAxFontCtrl::XHeadingFontNotify::QueryInterface(REFIID iid, LPVOID FAR* ppvObj)
{
METHOD_MANAGE_STATE(CMyAxFontCtrl, HeadingFontNotify)
if( IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IPropertyNotifySink))
{
*ppvObj= this;
AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP CMyAxFontCtrl::XHeadingFontNotify::OnChanged(DISPID)
{
METHOD_MANAGE_STATE(CMyAxFontCtrl, HeadingFontNotify)
pThis->InvalidateControl();
return NOERROR;
}
STDMETHODIMP CMyAxFontCtrl::XHeadingFontNotify::OnRequestEdit(DISPID)
{
return NOERROR;
}
AddRef和Release中的方法IPropertyNotifySink追蹤的介面,ActiveX 控制項物件的參考次數。當控制項取得存取介面指標時,控制項就會呼叫AddRef要遞增參考次數。將指標移完成控制項時,它會呼叫Release,我認為,就像 GlobalFree 可能會被呼叫,以釋放全域記憶體區塊。當這個介面的參考次數歸零時,就可以釋出介面實作。在這個範例中, QueryInterface函式會傳回變數的指標, IPropertyNotifySink的特定物件上的介面。這項功能可讓您一種 ActiveX 控制項來查詢物件以判斷哪個介面。
您的專案進行這些變更之後,請重建專案,並使用測試容器來測試介面。如需存取測試容器的詳細資訊,請參閱用測試容器測試屬性和事件。
請參閱
參考
MFC ActiveX 控制項: 使用 ActiveX 控制項中的圖片