MFC ActiveX 控件:使用字体
如果 ActiveX 控件显示文本,您可以让用户控件通过更改字体属性更改文本的外观。 字体属性实现为字体对象,可以为以下两种类型之一:常用或自定义。 常用字体属性是使用添加属性向导"可以将 preimplemented 的字体属性。 自定义字体属性不 preimplemented,控件开发人员确定的行为属性和用法。
本文涵盖以下主题:
使用栈字体属性
使用控件中自定义字体属性
使用栈字体属性
常用字体属性由类 preimplemented COleControl。 此外,标准字体属性可用,页还允许用户更改字体对象的各种特征,例如文件的名称、大小和样式。
通过 GetFont、SetFont和 COleControl的函数 InternalGetFont 字体访问对象。 控件用户通过 GetFont 将访问字体对象,并且使用与其他任何相同的 SetFont 函数获取/设置属性。 当对字体对象的访问权。需要控件中时,请使用 InternalGetFont 函数。
如 MFC ActiveX 控件:属性所述,将库存属性对 添加属性向导非常容易。 您选择字体属性,并且,添加属性向导自动插入常用字体输入控件的计划映射。
使用"添加属性向导,将库存 Font 属性
加载控件项目。
在类视图中,展开控件的库节点。
右击控件的接口节点 (库节点的第二个节点) ,打开快捷菜单。
从快捷菜单中,单击**“添加”,然后单击“添加属性”**。
这会打开 添加属性向导。
在 属性名 框中,单击 字体。
单击**“完成”**。
添加属性向导以下行添加到的控件映射计划,位于控件类实现文件:
DISP_STOCKPROP_FONT()
此外,添加属性向导以下行添加到 .idl 控件文件:
[id(DISPID_FONT)] IFontDisp*Font;
股票的 caption 属性是使用常用字体属性信息,可以绘制文本属性的示例。 添加股票标题属性绑定到控件使用单步执行类似于用于常用字体属性的那些开关。
使用"添加属性向导,将库存 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 函数使用字体对象后,控件内的所有文本显示与股票控制字体属性的特性。
使用控件中自定义字体属性
除了常用字体属性,ActiveX 控件可以具有自定义字体属性。 若要添加自定义字体属性必须:
使用添加属性向导实现自定义字体属性。
通知处理字体。
实现一个新字体通知接口。
实现自定义字体属性
若要实现自定义字体属性,则使用将属性添加属性向导然后对代码进行一些修改。 以下各节描述如何将自定义 HeadingFont 的示例属性设置为控件。
使用"添加属性向导,Font 添加自定义属性
加载控件项目。
在类视图中,展开控件的库节点。
右击控件的接口节点 (库节点的第二个节点) ,打开快捷菜单。
从快捷菜单中,单击**“添加”,然后单击“添加属性”**。
这会打开 添加属性向导。
在“属性名称”框中,键入新属性的名称。 对于此示例,使用 HeadingFont。
对于 Implementation Type,单击 Get/Set Methods。
在 属性类型 框,为属性类型选择 IDispatch*。
单击**“完成”**。
添加属性向导创建代码添加 HeadingFont 自定义属性。CSampleCtrl 类和 SAMPLE.IDL 文件。 由于 HeadingFont 是 get/set 特性类型,"添加属性向导"中修改 CSampleCtrl 类计划映射以包含 DISP_PROPERTY_EX_IDDISP_PROPERTY_EX 宏 Enter:
DISP_PROPERTY_EX_ID(CMyAxFontCtrl, "HeadingFont", dispidHeadingFont,
GetHeadingFont, SetHeadingFont, VT_DISPATCH)
DISP_PROPERTY_EX 宏与 HeadingFont 属性名与其对应的 CSampleCtrl 类获取和设置方法,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)
创建 IPropertyNotifySink interface called 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;
}
在 IPropertyNotifySink 接口的 AddRef 和 Release 方法记录 ActiveX 控件对象的引用计数。 如果控件获得对接口指针的访问权限时,控件调用 AddRef 递增引用计数。 在控件完成对指针时,它将调用 Release,在类似情况下释放 GlobalFree 可能会调用一种全局存储区。 在此接口的引用计数转到零时,接口实现中释放。 在此示例中,QueryInterface 函数返回指向在特定对象的 IPropertyNotifySink 接口。 此函数使 ActiveX 控件查询对象确定它支持哪些界面。
在这些更改对项目后,请重新生成项目并使用测试容器测试接口。 有关如何访问测试容器的信息,请参见用测试容器测试属性和事件。
请参见
参考
MFC ActiveX 控件:在 ActiveX 控件中使用图片