读书人

ActiveX控件怎样在程序中通过代码改变

发布时间: 2012-03-24 14:00:46 作者: rapoo

ActiveX控件怎样在程序中通过代码改变显示字体?
自己做了一个ActiveX控件,但不想通过属性页方式设置字体,控件都是动态创建的,可是调用SetFont方法不知道该传入什么参数,提示不能转换城struct IDispatch *,还有控件里面我加了Font库存属性,在OnDraw里面加了一句SelectStockFont ( pdc ) ;不知道这样够不够,希望各位大侠来帮我看看

[解决办法]
MFC ActiveX 控件:使用字体

如果 ActiveX 控件显示文本,则可以允许控件用户通过更改字体属性来更改文本外观。字体属性作为字体对象实现,并且可以是两种类型之一:常用或自定义。Stock Font 属性是预实现的字体属性,可使用“添加属性向导”添加。Custom Font 属性没有预实现,其行为和用法由控件开发人员决定。

本文阐述了以下主题:

使用 Stock Font 属性
在控件中使用自定义字体属性
使用 Stock Font 属性
Stock Font 属性由 COleControl 类预实现。另外还有一个标准“字体”属性页,它使用户得以更改字体对象的各种属性,如字体对象的名称、大小和样式。

通过 COleControl 的 GetFont、SetFont 和 InternalGetFont 函数访问字体对象。控件用户通过 GetFont 和 SetFont 函数,像访问任何其他 Get/Set 属性那样访问字体对象。当需要从控件内部访问字体对象时,使用 InternalGetFont 函数。

如 MFC ActiveX 控件:属性中的讨论,使用添加属性向导添加常用属性非常容易。选择 Font 属性后,“添加属性向导”自动将常用 Font 项插入到控件的调度映射中。

使用“添加属性向导”添加常用 Font 属性

加载控件的项目。
在“类视图”中展开控件的库节点。
右击控件的接口节点(库节点的第二个节点)打开快捷菜单。
在快捷菜单中单击“添加”,然后单击“添加属性”。
此操作将打开“添加属性向导”。

在“属性名”框中,单击“Font”。
单击“完成”。
“添加属性向导”将下面一行代码添加到控件的调度映射(位于控件类的实现文件中):

DISP_STOCKPROP_FONT()
另外,“添加属性向导”将下列代码行添加到控件的 .IDL 文件:

[id(DISPID_FONT), bindable, requestedit] IFontDisp* Font;
常用 Caption 属性是可使用常用 Font 属性信息绘制的文本属性的一个示例。将常用 Caption 属性添加到控件的步骤与添加常用 Font 属性的步骤相似。

使用“添加属性向导”添加常用 Caption 属性

加载控件的项目。
在“类视图”中展开控件的库节点。
右击控件的接口节点(库节点的第二个节点)打开快捷菜单。
在快捷菜单中单击“添加”,然后单击“添加属性”。
此操作将打开“添加属性向导”。

在“属性名”框中,单击“Caption”。
单击“完成”。
“添加属性向导”将下面一行代码添加到控件的调度映射(位于控件类的实现文件中):

DISP_STOCKPROP_CAPTION()
修改 OnDraw 函数
OnDraw 的默认实现对控件中显示的所有文本使用 Windows 系统字体。这意味着必须通过将字体对象选择到设备上下文中来修改 OnDraw 代码。为此,请调用 COleControl::SelectStockFont 并传递控件的设备上下文,如下例所示:

void CSampleCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
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 属性
除了常用 Font 属性外,ActiveX 控件还可以有自定义 Font 属性。若要添加自定义 Font 属性,必须:

使用“添加属性向导”实现自定义 Font 属性。
处理字体通知。
实现新的字体通知接口。
实现自定义 Font 属性
若要实现自定义 Font 属性,请使用“添加属性向导”添加该属性,然后对代码进行一些修改。下一节介绍如何将自定义 HeadingFont 属性添加到 Sample 控件。

使用“添加属性向导”添加自定义 Font 属性

加载控件的项目。
在“类视图”中展开控件的库节点。
右击控件的接口节点(库节点的第二个节点)打开快捷菜单。
在快捷菜单中单击“添加”,然后单击“添加属性”。
此操作将打开“添加属性向导”。

在“属性名”框中,键入属性名。本例中使用 HeadingFont。
对于“实现类型”,单击“Get/Set 方法”。
在“属性类型”框中,选择属性的类型 IDispatch*。
单击“完成”。
“添加属性向导”创建将 HeadingFont 自定义属性添加到 CSampleCtrl 类和 SAMPLE.IDL 文件的代码。由于 HeadingFont 是 Get/Set 属性类型,“添加属性向导”修改 CSampleCtrl 类的调度映射以包括 DISP_PROPERTY_EX 宏项:

BEGIN_DISPATCH_MAP(CSampleCtrl, COleControl)
DISP_PROPERTY_EX(CSampleCtrl, "HeadingFont ", GetHeadingFont,
SetHeadingFont, VT_DISPATCH)
END_DISPATCH_MAP()
DISP_PROPERTY_EX 宏将 HeadingFont 属性名与其相应的 CSampleCtrl 类 Get 和 Set 方法 GetHeadingFont 和 SetHeadingFont 相关联。还指定属性值的类型,此例中为 VT_FONT。

“添加属性向导”还在控件头文件 (.H) 中添加 GetHeadingFont 和 SetHeadingFont 函数的声明,并将其函数模板添加到控件的实现文件 (.CPP) 中:

LPDISPATCH CSampleCtrl::GetHeadingFont(void)


{
// TODO: Add your property handler here
return NULL;
}

void CSampleCtrl::SetHeadingFont(LPDISPATCH newValue)
{
// TODO: Add your property handler here
SetModifiedFlag();
}
最后,“添加属性向导”通过添加 HeadingFont 属性的项修改控件的 .IDL 文件:

[id(1)] IDispatch* HeadingFont;
修改控件代码
您已将 HeadingFont 属性添加到了控件,现在必须对控件头文件和实现文件进行一些修改,以完全支持新属性。

在控件头文件 (.H) 中,添加下列受保护成员变量的声明:

protected:

CFontHolder m_fontHeading;
在控件实现文件 (.CPP) 中,执行以下操作:

初始化控件构造函数中的 m_fontHeading。
CSampleCtrl::CSampleCtrl( ) : m_fontHeading( &m_xFontNotification )
{
// [...body of constructor...]
}
声明包含字体默认属性的静态 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 CSampleCtrl::DoPropExchange(CPropExchange* pPX)
{
COleControl::DoPropExchange(pPX);

// [...other PX_ function calls...]
PX_Font(pPX, _T( "HeadingFont "), m_fontHeading, &_fontdescHeading);
}
完成实现控件 GetHeadingFont 成员函数。
LPFONTDISP CSampleCtrl::GetHeadingFont( )
{
return m_fontHeading.GetFontDispatch( );
}
完成实现控件 SetHeadingFont 成员函数。
void CSampleControl::SetHeadingFont( LPFONTDISP newValue )
{
m_fontHeading.InitializeFont( &_fontdescHeading, newValue);
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 宏的计数参数增加 1。下行阐释了这一点:

BEGIN_PROPPAGEIDS(CSampleCtrl, 2)
完成这些更改后,重新生成整个项目以合并附加的功能。

[解决办法]

处理字体通知
大多数情况下,控件需要知道修改字体对象特性的时间。每个字体对象都能够通过调用 IFontNotification 接口的成员函数(由 COleControl 实现)在自身更改时提供通知。

如果控件使用常用 Font 属性,则其通知由 COleControl 的 OnFontChanged 成员函数处理。当添加自定义 Font 属性时,可以让它们使用同一实现。在上一节的示例中,这一点通过在初始化 m_fontHeading 成员变量时传递 &m_xFontNotification 来实现。

实现多个字体对象接口


上图中的实线表示两个字体对象都在使用 IFontNotification 的同一实现。如果曾想区分哪个字体已更改,以上情况可能会导致一些问题。

区分控件的字体对象通知的一个方法是,为控件中的每个字体对象各创建一个单独的 IFontNotification 接口实现。此技术使您只需更新使用最近修改的字体的一个或多个字符串,从而优化了绘制代码。以下各节说明为第二个 Font 属性实现单独的通知接口所必需的步骤。假设第二个 Font 属性是在上一节中添加的 HeadingFont 属性。

实现新的字体通知接口
若要区分两个或多个字体的通知,必须为控件中使用的每个字体各实现一个新的通知接口。以下各节介绍如何通过修改控件头文件和实现文件来实现新的字体通知接口。

向头文件中添加的内容
在控件头文件 (.H) 中,将下列代码行添加到类声明:

protected:
BEGIN_INTERFACE_PART(HeadingFontNotify, IPropertyNotifySink)
INIT_INTERFACE_PART(CSampleCtrl, HeadingFontNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(HeadingFontNotify)
这将创建名称为 HeadingFontNotify 的 IPropertyNotifySink 接口的实现。这个新接口包含名称为 OnChanged 的方法。

向实现文件中添加的内容
在初始化标头字体(在控件构造函数中)的代码中,将 &m_xFontNotification 更改为 &m_xHeadingFontNotify。然后添加下列代码:

STDMETHODIMP_(ULONG) CSampleCtrl::XHeadingFontNotify::AddRef( )
{
METHOD_MANAGE_STATE(CSampleCtrl, HeadingFontNotify)
return 1;
}
STDMETHODIMP_(ULONG) CSampleCtrl::XHeadingFontNotify::Release( )
{
METHOD_MANAGE_STATE(CSampleCtrl, HeadingFontNotify)
return 0;


}

STDMETHODIMP CSampleCtrl::XHeadingFontNotify::QueryInterface( REFIID iid, LPVOID FAR* ppvObj )
{
METHOD_MANAGE_STATE( CSampleCtrl, HeadingFontNotify )
if( IsEqualIID( iid, IID_IUnknown ) ||
IsEqualIID( iid, IID_IPropertyNotifySink))
{
*ppvObj= this;
AddRef( );
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}

STDMETHODIMP CSampleCtrl::XHeadingFontNotify::OnChanged(DISPID)
{
METHOD_MANAGE_STATE( CSampleCtrl, HeadingFontNotify )
pThis-> InvalidateControl( );
return NOERROR;
}

STDMETHODIMP CSampleCtrl::XHeadingFontNotify::OnRequestEdit(DISPID)
{
return NOERROR;
}
IPropertyNotifySink 接口中的 AddRef 和 Release 方法记录对 ActiveX 控件对象的引用数。当控件获取对接口指针的访问时,控件调用 AddRef 以增加引用数。控件完成对指针的操作后将调用 Release,其方式与调用 GlobalFree 以释放全局内存块的可能方式大致相同。当此接口的引用数为零时,可以释放此接口的实现。在此例中,QueryInterface 函数返回指向特定对象上的 IPropertyNotifySink 接口的指针。此函数允许 ActiveX 控件查询对象以确定该对象支持的接口类型。

对项目执行完这些更改后,重新生成项目,并使用测试容器测试接口。有关如何访问测试容器的信息,请参见用测试容器测试属性和事件。


[解决办法]
多查查MSDN!
[解决办法]
http://www.microsoft.com/msj/0999/Visualprog/visualprog0999.aspx
[解决办法]
取得系统字体集合后再设置嘛

读书人网 >VC/MFC

热点推荐