MFC ActiveX 控件:使用字体
如果 Activex 控件显示文本,可以允许用户控件通过更改字体属性更改文本的外观。 字体属性实现为字体对象,可以为以下两种类型之一:股票或自定义。 常用字体属性用于添加属性向导中,可以添加的 preimplemented 字体属性。 自定义字体属性不 preimplemented,并且控件开发人员确定属性的行为和用法。
本文包含以下主题:
使用常用字体属性
使用在控件的自定义字体属性
使用常用字体属性
常用字体属性由类 COleControlpreimplemented。 此外,标准字体属性页还可用,允许用户更改字体对象的各个属性,如名称、大小和样式。
访问字体对象。 COleControl的 GetFont、 SetFont和 InternalGetFont 功能。 控件用户通过 GetFont 和 SetFont 函数将访问字体对象与其他 get/set 属性相同。 当对字体对象的访问需要从控件内部时,请使用 InternalGetFont 功能。
如 MFC Activex 控件:属性所述,添加常用属性设置为 添加属性向导非常容易。 您自动选择字体属性并添加属性向导插入常用字体项添加到控件的计划映射中。
使用 " 添加属性向导 ",添加常用字体属性
加载您的控件的项目中。
在 " 类视图 " 中,展开您的控件库节点。
右击您的控件 (库节点的第二个节点接口节点) 打开快捷菜单。
从快捷菜单上,单击 添加 然后单击 添加属性。
这将打开 " 添加属性向导 "。
在 属性名 框中,单击 Font。
单击**“完成”**。
添加属性向导将以下行添加到控件的计划映射,位于控件类实现文件:
DISP_STOCKPROP_FONT()
此外, " 添加属性向导 " 将以下行添加到控件 .IDL 文件:
[id(DISPID_FONT)] IFontDisp*Font;
股票声明属性是使用常用字体属性信息,可以绘制文本特性的示例。 添加股票声明属性设置为该控件使用步骤类似于用于常用字体属性的参数。
使用 " 添加属性向导 ",添加股票 description 属性
加载您的控件的项目中。
在 " 类视图 " 中,展开您的控件库节点。
右击您的控件 (库节点的第二个节点接口节点) 打开快捷菜单。
从快捷菜单上,单击 添加 然后单击 添加属性。
这将打开 " 添加属性向导 "。
在 属性名 框中,单击 标题。
单击**“完成”**。
添加属性向导将以下行添加到控件的计划映射,位于控件类实现文件:
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 函数使用字体对象后,在控件中的所有文本显示与控件常用字体属性的特征。
使用在控件的自定义字体属性
除了常用字体属性外, Activex 控件可以具有自定义字体属性。 若要添加自定义字体属性必须:
使用 " 添加属性向导 " 实现自定义字体属性。
处理字体通知。
实现一个新的字体通知接口。
实现自定义字体属性
若要实现自定义字体属性,可以使用来添加属性向导将该属性然后对代码进行这些修改。 以下各节介绍如何将自定义 HeadingFont 属性设置为示例控件。
使用 " 添加属性向导 ",添加自定义字体属性
加载您的控件的项目中。
在 " 类视图 " 中,展开您的控件库节点。
右击您的控件 (库节点的第二个节点接口节点) 打开快捷菜单。
从快捷菜单上,单击 添加 然后单击 添加属性。
这将打开 " 添加属性向导 "。
在 属性名 框中,键入一个名称属性。 对于此示例,请使用 HeadingFont。
为 Implementation Type,单击 Get/Set Methods。
在 属性类型 框中,为属性类型选择 IDispatch* 。
单击**“完成”**。
添加属性向导 " 创建代码添加 HeadingFont 自定义属性。 CSampleCtrl 类和 SAMPLE.IDL 文件。 由于 HeadingFont 是 get/set 属性类型, " 添加属性向导 " 修改 CSampleCtrl 类的计划映射由 DISP_PROPERTY_EX_IDDISP_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 功能。 对于您的自定义字体属性提供初始化和持久性。
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);
在自定义字体属性实现后,应实现标准字体属性页,控件允许用户更改控件的当前字体。 若要添加属性调用标准字体属性页中,插入 ID 在 BEGIN_PROPPAGEIDS 宏后的代码行:
PROPPAGEID(CLSID_CFontPropPage)
您必须以还提高 BEGIN_PROPPAGEIDS 宏的计数参数。 下面的行阐释了这一点:
BEGIN_PROPPAGEIDS(CMyAxFontCtrl, 2)
在这些更改后,重新生成整个项目合并的其他功能。
处理字体通知
在许多情况下需要知道何时更改了字体对象的特征。 每个字体对象能够提供通知,则通过调用 IFontNotification 接口的成员函数发生更改时,实现由 COleControl。
如果控件使用常用字体属性,其通知由 COleControl的 OnFontChanged 成员函数处理。 在添加自定义字体属性时,可以让它们使用相同实现。 在上一节中的示例中,这通过将 &m_xFontNotification 完成,则在初始化 m_fontHeading 的成员变量。
实现多个字体对象接口
在上图显示的实线这两种字体对象使用 IFontNotification相同的实现。 这会导致出现问题,如果字体更改的要区分。
一种区分控件的字体对象通知之间将创建 IFontNotification 接口的一个单独实现每个字体对象在控件上 此方法允许您通过仅更新该字符串优化您的绘图代码或字符串,则使用最近修改的字体。 以下各节演示需的步骤实现第二个字体属性的单独通知接口。 第二个字体属性假定为上一节中添加的 HeadingFont 属性。
实现一个新的字体通知接口
为了区分两个或多个字体的通知之间,必须提供用于控件的每个字体实现一个新的通知接口。 以下各节描述如何通过修改控件标头和实现文件实现一个新的字体通知接口。
为头文件添加
在控件头文件 (。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 会递增引用计数。 在控件完成于指针时,将调用 Release,按照与 GlobalFree 调用释放全局内存块。 当此接口的引用计数为时为零,接口实现可以被释放。 在此示例中, QueryInterface 函数返回指向在特定对象的一 IPropertyNotifySink 接口。 此功能允许 Activex 控件查询对象确定它支持哪些界面。
在这些更改了项目后,请重新生成项目,并使用测试容器接口。 有关如何访问测试容器的信息,请参见用测试容器测试属性和事件。
请参见
参考
MFC ActiveX 控件:使用在 ActiveX 控件的图片