MFC ActiveX コントロール: フォントの使用
ActiveX コントロールにテキストが表示される場合は、フォント プロパティを変更することで、コントロール ユーザーがテキストの外観を変更できるようになります。 フォント プロパティは、フォント オブジェクトとして実装され、ストック型とカスタム型の 2 種類のいずれかになります。 ストック Font プロパティは、プロパティの追加ウィザードを使用して追加できる、事前に実装済みのフォント プロパティです。 カスタム Font プロパティは、コントロール開発者が動作と使用方法を決定する、事前に実装されていないプロパティです。
この記事では、次のトピックについて説明します。
ストック Font プロパティの使用
ストック Font プロパティは、クラス COleControl によって事前に実装されています。 また、標準の Font プロパティ ページも使用できるため、ユーザーは、フォント オブジェクトのさまざまな属性 (名前、サイズ、スタイルなど) を変更できます。
フォント オブジェクトには、COleControl
の GetFont、SetFont、および InternalGetFont 関数を介してアクセスします。 コントロール ユーザーは、他の Get および Set プロパティと同じ方法で、GetFont
および SetFont
関数を介してフォント オブジェクトにアクセスします。 コントロール内からフォント オブジェクトにアクセスする必要がある場合は、InternalGetFont
関数を使用します。
「MFC ActiveX コントロール: プロパティ」で説明されているように、プロパティの追加ウィザードを使用すると、ストック プロパティを簡単に追加できます。 Font プロパティを選択すると、プロパティの追加ウィザードにより、ストック Font エントリがコントロールのディスパッチ マップに自動的に挿入されます。
プロパティの追加ウィザードを使用してストック Font プロパティを追加するには
コントロールのプロジェクトを読み込みます。
[クラス ビュー] で、コントロールのライブラリ ノードを展開します。
コントロールのインターフェイス ノード (ライブラリ ノードの 2 番目のノード) を右クリックし、ショートカット メニューを開きます。
ショートカット メニューから、[追加]、[プロパティの追加] の順にクリックします。
これにより、[プロパティの追加] ウィザードが開きます。
[プロパティ名] ボックスで、[Font] をクリックします。
[完了] をクリックします。
プロパティの追加ウィザードにより、コントロール クラスの実装ファイルにあるコントロールのディスパッチ マップに次の行が追加されます。
DISP_STOCKPROP_FONT()
さらに、プロパティの追加ウィザードにより、コントロールの .IDL ファイルに次の行が追加されます。
[id(DISPID_FONT)] IFontDisp* Font;
ストック Caption プロパティは、ストック Font プロパティ情報を使用して描画できるテキスト プロパティの例です。 コントロールにストック Caption プロパティを追加するには、ストック Font プロパティに使用する手順と同様の手順を使用します。
[プロパティの追加] ウィザードを使用してストック Caption プロパティを追加するには
コントロールのプロジェクトを読み込みます。
[クラス ビュー] で、コントロールのライブラリ ノードを展開します。
コントロールのインターフェイス ノード (ライブラリ ノードの 2 番目のノード) を右クリックし、ショートカット メニューを開きます。
ショートカット メニューから、[追加]、[プロパティの追加] の順にクリックします。
これにより、[プロパティの追加] ウィザードが開きます。
[プロパティ名] ボックスで、[Caption] をクリックします。
[完了] をクリックします。
プロパティの追加ウィザードにより、コントロール クラスの実装ファイルにあるコントロールのディスパッチ マップに次の行が追加されます。
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 プロパティの特性で表示されます。
コントロールでのカスタム Font プロパティの使用
ActiveX コントロールでは、ストック Font プロパティに加えて、カスタム Font プロパティを設定できます。 カスタム Font プロパティを追加するには、次のことを行う必要があります。
プロパティの追加ウィザードを使用して、カスタム Font プロパティを実装します。
カスタム Font プロパティの実装
カスタム Font プロパティを実装するには、プロパティの追加ウィザードを使用してプロパティを追加してから、コードに変更を加えます。 次のセクションでは、カスタム HeadingFont
プロパティを Sample コントロールに追加する方法について説明します。
プロパティの追加ウィザードを使用してカスタム Font プロパティを追加するには
コントロールのプロジェクトを読み込みます。
[クラス ビュー] で、コントロールのライブラリ ノードを展開します。
コントロールのインターフェイス ノード (ライブラリ ノードの 2 番目のノード) を右クリックし、ショートカット メニューを開きます。
ショートカット メニューから、[追加]、[プロパティの追加] の順にクリックします。
これにより、[プロパティの追加] ウィザードが開きます。
[プロパティ名] ボックスにプロパティの名前を入力します。 この例では、HeadingFont を使用します。
[実装の種類] として、[Get/Set メソッド] をクリックします。
[プロパティの種類] ボックスで、プロパティの種類として [IDispatch*] を選択します。
[完了] をクリックします。
プロパティの追加ウィザードによって、HeadingFont
カスタム プロパティを CSampleCtrl
クラスと SAMPLE.IDL ファイルに追加するコードが作成されます。 HeadingFont
は Get および Set プロパティ型であるため、プロパティの追加ウィザードによって、DISP_PROPERTY_EX_IDDISP_PROPERTY_EX マクロ エントリを含めるように CSampleCtrl
クラスのディスパッチ マップが変更されます。
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();
}
最後に、プロパティの追加ウィザードによって、コントロールの .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
関数への呼び出しを追加します。 これにより、カスタム 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 プロパティ ページのプロパティ ページ ID を追加するには、BEGIN_PROPPAGEIDS マクロの後に次の行を挿入します。
PROPPAGEID(CLSID_CFontPropPage)
また、BEGIN_PROPPAGEIDS マクロのカウント パラメーターの値を 1 つ増やす必要があります。 次の行に例を示します。
BEGIN_PROPPAGEIDS(CMyAxFontCtrl, 2)
これらの変更を加えた後、プロジェクト全体をリビルドして、追加の機能を組み込みます。
フォント通知の処理
ほとんどの場合、フォント オブジェクトの特性がいつ変更されたかをコントロールに通知する必要があります。 各フォント オブジェクトは、COleControl
によって実装される IFontNotification
インターフェイスのメンバー関数を呼び出すことにより、変更されたときに通知を提供できます。
コントロールでストック Font プロパティを使用している場合、その通知は COleControl
の OnFontChanged
メンバー関数によって処理されます。 カスタム フォント プロパティを追加するときに、同じ実装を使用することができます。 前のセクションの例では、これは、m_fontHeading メンバー変数を初期化するときに &m_xFontNotification 渡すことによって実現されました。
複数のフォント オブジェクト インターフェイスの実装
上の図の実線は、両方のフォント オブジェクトが IFontNotification
の同じ実装を使用していることを示しています。 この場合、変更されたフォントを区別する際に問題が発生する可能性があります。
コントロールのフォント オブジェクト通知を区別する 1 つの方法は、コントロール内のフォント オブジェクトごとに IFontNotification
インターフェイスの個別の実装を作成することです。 この手法を使用すると、最近変更されたフォントを使用する 1 つまたは複数の文字列のみを更新することにより、描画コードを最適化できます。 次のセクションでは、2 番目の Font プロパティに個別の通知インターフェイスを実装するために必要な手順を示します。 2 番目のフォント プロパティは、前のセクションで追加された HeadingFont
プロパティであると想定します。
新しいフォント通知インターフェイスの実装
2 つ以上のフォントの通知を区別するには、コントロールで使用されるフォントごとに新しい通知インターフェイスを実装する必要があります。 次のセクションでは、コントロールのヘッダー ファイルと実装ファイルを変更して新しいフォント通知インターフェイスを実装する方法について説明します。
ヘッダー ファイルへの追加
コントロールのヘッダー ファイル (.H) で、クラス宣言に次の行を追加します。
protected:
BEGIN_INTERFACE_PART(HeadingFontNotify, IPropertyNotifySink)
INIT_INTERFACE_PART(CMyAxFontCtrl, HeadingFontNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(HeadingFontNotify)
これにより、HeadingFontNotify
という IPropertyNotifySink
インターフェイスの実装が作成されます。 この新しいインターフェイスには、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;
}
IPropertyNotifySink
インターフェイスの AddRef
メソッドと Release
メソッドでは、ActiveX コントロール オブジェクトの参照カウントを追跡します。 コントロールは、インターフェイス ポインターへのアクセスを取得すると、AddRef
を呼び出して参照カウントをインクリメントします。 コントロールは、ポインターの操作が完了すると、グローバル メモリ ブロックを解放するために GlobalFree
を呼び出すのとほぼ同じ方法で Release
を呼び出します。 このインターフェイスの参照カウントが 0 になった時点で、インターフェイスの実装を解放できます。 この例では、QueryInterface
関数は、特定のオブジェクトの IPropertyNotifySink
インターフェイスを指すポインターを返します。 この関数により、ActiveX コントロールでオブジェクトを照会して、サポートされているインターフェイスを判定できます。
これらの変更をプロジェクトに加えた後、プロジェクトをリビルドし、テスト コンテナーを使用してインターフェイスをテストします。 Test Container にアクセスする方法について詳しくは、「 テスト コンテナーでのプロパティとイベントのテスト 」をご覧ください。
関連項目
MFC ActiveX コントロール
MFC ActiveX コントロール: ActiveX コントロールにおけるピクチャの使用
MFC ActiveX コントロール: ストック プロパティ ページの使用