分享方式:


MFC ActiveX 控制項:使用字型

如果您的 ActiveX 控制件顯示文字,您可以變更字型屬性,讓控件使用者變更文字外觀。 字型屬性會實作為字型物件,而且可以是兩種類型之一:股票或自定義。 Stock Font 屬性是您可以使用 [新增屬性精靈] 新增的預先實作字型屬性。 不會預先實作自定義字型屬性,而且控件開發人員會決定屬性的行為和使用方式。

本文涵蓋下列主題:

使用 Stock Font 屬性

Stock Font 屬性是由 COleControl 類別預先實作。 此外,您也可以使用標準 Font 屬性頁,讓使用者變更字型對象的各種屬性,例如其名稱、大小和樣式。

透過的 COleControlGetFont、SetFontInternalGetFont 函式存取字型物件。 控件使用者會透過和 SetFont 函式,以GetFont與任何其他 Get/Set 屬性相同的方式存取字型物件。 需要從控件記憶體取字型物件時,請使用 函 InternalGetFont 式。

如 MFC ActiveX 控制件:屬性中所述,使用 [新增屬性精靈] 即可輕鬆新增庫存屬性。 您選擇 [字型] 屬性,[新增屬性精靈] 會自動將 [字型] 專案插入控件的分派對應中。

使用 [新增屬性精靈] 新增 stock Font 屬性

  1. 載入控制項專案。

  2. 在 [類別檢視] 中,展開控制項的程式庫節點。

  3. 在控制項的介面節點 (程式庫節點的第二個節點) 上按一下滑鼠右鍵,開啟捷徑功能表。

  4. 從快捷方式功能表中,按兩下 [新增 ],然後按下 [ 新增屬性]。

    這會開啟 [新增屬性精靈]。

  5. 在 [ 屬性名稱] 方塊中,按兩下 [ 字型]。

  6. 按一下完成

[新增屬性精靈] 會將下列這一行新增至控件的分派對應,該對應位於控件類別實作檔案中:

DISP_STOCKPROP_FONT()

此外,[新增屬性精靈] 會將下列這一行新增至 控件。IDL 檔案:

[id(DISPID_FONT)] IFontDisp* Font;

stock Caption 屬性是可使用 stock Font 屬性資訊繪製的文字屬性範例。 將 stock Caption 屬性新增至控件時,會使用與用於 stock Font 屬性的步驟類似。

使用 [新增屬性精靈] 新增 stock Caption 屬性

  1. 載入控制項專案。

  2. 在 [類別檢視] 中,展開控制項的程式庫節點。

  3. 在控制項的介面節點 (程式庫節點的第二個節點) 上按一下滑鼠右鍵,開啟捷徑功能表。

  4. 從快捷方式功能表中,按兩下 [新增 ],然後按下 [ 新增屬性]。

    這會開啟 [新增屬性精靈]。

  5. 在 [ 屬性名稱] 方塊中,按兩下 [ 標題]。

  6. 按一下完成

[新增屬性精靈] 會將下列這一行新增至控件的分派對應,該對應位於控件類別實作檔案中:

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 式以使用字型對象之後,控件內的任何文字都會以控件的 stock Font 屬性的特性顯示。

在控件中使用自定義字型屬性

除了 stock Font 屬性之外,ActiveX 控件也可以有自定義的 Font 屬性。 若要新增自定義字型屬性,您必須:

實作自定義字型屬性

若要實作自定義 Font 屬性,您可以使用 [新增屬性精靈] 來新增 屬性,然後對程式代碼進行一些修改。 下列各節說明如何將自定義 HeadingFont 屬性新增至範例控件。

使用 [新增屬性精靈] 新增自定義 Font 屬性
  1. 載入控制項專案。

  2. 在 [類別檢視] 中,展開控制項的程式庫節點。

  3. 在控制項的介面節點 (程式庫節點的第二個節點) 上按一下滑鼠右鍵,開啟捷徑功能表。

  4. 從快捷方式功能表中,按兩下 [新增 ],然後按下 [ 新增屬性]。

    這會開啟 [新增屬性精靈]。

  5. 在 [ 屬性名稱] 方塊中,輸入屬性的名稱。 在此範例中,請使用 HeadingFont

  6. 在 [實作類型] 中,按一下 [Get/Set 方法]

  7. 在 [ 屬性類型] 方塊中,選取 屬性類型的 [IDispatch* ]。

  8. 按一下完成

[新增屬性精靈] 會建立程序代碼, HeadingFont 將自定義屬性新增至 CSampleCtrl 類別和 SAMPLE。IDL 檔案。 因為 HeadingFont 是 Get/Set 屬性類型,[新增屬性精靈] 會CSampleCtrl修改類別的分派對應,以包含DISP_PROPERTY_EX_ID DISP_PROPERTY_EX宏專案:

DISP_PROPERTY_EX_ID(CMyAxFontCtrl, "HeadingFont", dispidHeadingFont,
   GetHeadingFont, SetHeadingFont, VT_DISPATCH)

DISP_PROPERTY_EX宏會將 HeadingFont 屬性名稱與其對應的 CSampleCtrl 類別 Get 和 Set 方法產生關聯, GetHeadingFont 以及 SetHeadingFont。 也會指定屬性值的類型;在此情況下,VT_FONT。

[新增屬性精靈] 也會在控件頭檔 () 中新增宣告。和函式的 GetHeadingFont SetHeadingFont H),並在控件實作檔案中新增其函式範本。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();
}

最後,[新增屬性精靈] 會修改 控制項 。新增 屬性的專案 HeadingFont 來新增 IDL 檔案:

[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 呼叫。 這會提供自定義 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 屬性之後,應該實作標準 Font 屬性頁,讓控件用戶能夠變更控件的目前字型。 若要新增標準 Font 屬性頁的屬性頁識別碼,請在BEGIN_PROPPAGEIDS宏後面插入下列這一行:

PROPPAGEID(CLSID_CFontPropPage)

您也必須將BEGIN_PROPPAGEIDS宏的 count 參數遞增一個。 下面這行程式碼可說明這點:

BEGIN_PROPPAGEIDS(CMyAxFontCtrl, 2)

進行這些變更之後,請重建整個專案以納入其他功能。

處理字型通知

在大部分情況下,控件必須知道字型物件的特性何時已修改。 每個字型物件都能夠藉由呼叫 介面的成員函 IFontNotification 式,由實 COleControl作,提供通知。

如果控件使用 stock Font 屬性,則會由 OnFontChanged 的成員函 COleControl式處理其通知。 當您新增自定義字型屬性時,您可以讓它們使用相同的實作。 在上一節的範例中,這是藉由在初始化m_fontHeading成員變數時傳遞 &m_xFontNotification 來完成。

Implementing multiple font object interfaces.
實作多個字型物件介面

上圖中的實線顯示,這兩個字型物件都使用相同的 實作 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)

這會建立稱為HeadingFontNotifyIPropertyNotifySink介面實作。 這個新介面包含稱為 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中的 IPropertyNotifySinkRelease 方法會追蹤 ActiveX 控制件物件的參考計數。 當控件取得介面指標的存取權時,控件會呼叫 AddRef 以遞增參考計數。 當控件完成指標時,它會呼叫 Release,方式 GlobalFree 與呼叫 以釋放全域記憶體區塊的方式大致相同。 當這個介面的參考計數移至零時,可以釋放介面實作。 在此範例中,函 QueryInterface 式會傳回特定物件上介面的指標 IPropertyNotifySink 。 此函式可讓 ActiveX 控制件查詢物件,以判斷其支援哪些介面。

對專案進行這些變更之後,請重建專案,並使用測試容器來測試介面。 如需測試容器存取方法的詳細資訊,請參閱 以測試容器測試屬性和事件

另請參閱

MFC ActiveX 控制項
MFC ActiveX 控制項:在 ActiveX 控制項中使用圖片
MFC ActiveX 控制項:使用內建屬性頁