字體的使用是ActiveX控件制作過程中不可缺少的部分。本文將深入淺出地介紹在ActiveX控件中制作過程中如何使用字體。本文所提及的ActiveX控件制作是指利用VC++6.0的MFC ActiveX ControlWizard 工具,用其它方法制作 ActiveX 控件本文不作討論。
本文專門設置了一些例程,以便您能夠更好地掌握這些內容。這些例程都是完整的ActiveX控件制作源代碼。為了突出重點,本文僅對字體使用相關部分的源代碼作較詳細的介紹,其余部分的代碼本文不作過多討論。字體作為一種屬性在ActiveX控件中使用,與其它屬性沒有區別,同樣分為庫存屬性和自定義屬性,本文將分四個部分進行介紹。
第一部分 在控件中使用庫存字體(Stock Font)屬性
使用ClassWizard 添加 Font庫存屬性的步驟:
ClassWizard將在控件類的執行文件的dispatch映射表中加入下列行:
DISP_STOCKPROP_FONT()
另外, ClassWizard 在.ODL 文件中加入下列行:
[id(DISPID_FONT), bindable] IFontDisp* Font;
例程1:Label.ocx
下面,我們舉一個具體的實例詳細演示如何在控件中添加Font庫存屬性。您可以下載該例程進行編譯生成 .ocx 控件,並測試該控件。
我們將要制作的控件取名Label.ocx,模仿VB工具箱中的Label控件。該控件增強了VC++工具箱中的Static Text控件的有限的功能,您可以方便地在您的工程中使用。例程的工程名也取名為Label。
創建Label工程
打開Visual C++ 6.0,單擊File菜單的New,彈出New對話框。在對話框中選擇MFC ActiveX ControlWizard,並輸入工程名Label,單擊OK按鈕,關閉該對話框並彈出MFC ActiveX ControlWizard-Step 1 of 2對話框。如圖1-1。
圖1-1
接受MFC ActiveX ControlWizard-Step 1 of 2對話框所有默認設置,單擊Next按鈕,關閉該窗口同時彈出MFC ActiveX ControlWizard-Step 2 of 2對話框。繼續接受MFC ActiveX ControlWizard-Step 2 of 2對話框所有默認設置,單擊Finish按鈕。
繼續單擊OK 按鈕,Label工程創建完成,我們將繼續對該工程進行修改。使用ClassWizard 給控件增加庫存屬性Caption,BackColor,ForeColor,Font。
我們已經給控件增加了庫存屬性Caption,該屬性用以設置Label控件的文本內容。按上述同樣操作,依次添加庫存屬性BackColor,ForeColor,Font。這3個屬性分別用以設置Label控件的背景色,前景色以及字體的屬性。如圖1-2。
圖1-2
添加顏色屬性頁和字體屬性頁
打開工程的LabelCtl.cpp文件,將其中的如下代碼進行修改:
BEGIN_PROPPAGEIDS(CLabelCtrl, 1)
PROPPAGEID(CLabelPropPage::guid)
END_PROPPAGEIDS(CLabelCtrl)
修改後的代碼:
BEGIN_PROPPAGEIDS(CLabelCtrl, 3) // 具體個數由實際情況而定
PROPPAGEID(CLabelPropPage::guid)//系統自帶的屬性頁
PROPPAGEID(CLSID_CColorPropPage) //加入Color屬性頁
PROPPAGEID(CLSID_CFontPropPage) //加入Font屬性頁
END_PROPPAGEIDS(CLabelCtrl)
修改系統自帶的屬性頁
打開系統自帶的屬性頁資源IDD_PROPPAGE_LABEL,將靜態文本框IDC_STATIC的內容改為"Caption:",添加一個編輯框(Edit Box)控件,控件ID為IDC_CAPTION。如圖1-3
圖1-3
按下"Ctrl+W"組合鍵打開ClassWizard,選中Member Variables標簽,Class name:下拉列表框選擇CLabelPropPage,Control IDs:選中IDC_CAPTION,單擊Add Variable…按鈕,彈出Add Member Variable對話框。
在Add Member Variable對話框中,Member variable name:框輸入m_caption,Category選擇Value,Variable type:框選擇CString,Optional property name:框選擇Caption,單擊OK按鈕。如圖1-4。
圖1-4
再次單擊OK按鈕關閉ClassWizard。上述操作,編輯框IDC_CAPTION與Caption屬性之間建立了聯系。您可以通過修改編輯框的內容來改變控件Caption的屬性值。
修改OnDraw函數
修改後的OnDraw函數如下:
void CLabelCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid )
{
// TODO: Replace the following code with your own drawing code.
COLORREF colorBack=TranslateColor(GetBackColor());
COLORREF colorFore=TranslateColor(GetForeColor());
// GetBackColor(),GetForeColor()分別得到背景色和前景色
// GetBackColor(),GetForeColor()返回類型為OLE_COLOR
// TranslateColor函數將OLE_COLOR類型轉換為COLORREF類型
CBrush brush(colorBack);
pdc->FillRect(rcBounds, &brush);
//背景色填充整個控件
pdc->SetBkMode(TRANSPARENT);
//設置透明背景色
pdc->SetTextColor(colorFore);
//前景色設置為字體顏色
const CString& strCaption = InternalGetText();
//獲得庫存屬性Caption的值
CFont* pOldFont;
pOldFont = SelectStockFont(pdc);
//設備上下文中選擇字體對象
RECT rect;
::CopyRect(&rect,rcBounds);
pdc->DrawText(strCaption,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
//單行,水平居中,垂直居中顯示
pdc->SelectObject(pOldFont);
}
Label控件的制作已經完成了,您可以方便地改變字體的大小、類型、顏色以及控件的背景色。當然,您還可以進一步完善該控件,更加方便您的使用。
第二部分 在控件中使用自定義的字體(Custom Font)屬性
除了庫存字體屬性Font外, ActiveX控件還允許使用自定義的字體屬性。添加一個自定義字體屬性,要完成一個自定義字體屬性,你應該首先使用 ClassWizard 添加自定義字體屬性,然後對代碼作一些修改。下面將描述怎樣給一個控件添加自定義屬性(假設控件的名字為Sample):
使用 ClassWizard 添加自定義字體屬性
ClassWizard 將產生相應的代碼把自定義屬性HeadingFont添加到CSampleCtrl類中和 SAMPLE.ODL文件中。既然 HeadingFont是一個 Get/Set 屬性類型,ClassWizard 修改CSampleCtrl 類的dispatch 映射表來包括一個DISP_PROPERTY_EX 宏入口:
BEGIN_DISPATCH_MAP(CSampleCtrl, COleControl)
DISP_PROPERTY_EX 宏把HeadingFont屬性名和它的相應的CSampleCtrl類的Get / Set 方法(GetHeadingFont and SetHeadingFont)聯系起來。 ClassWizard 也在控件的頭文件(.H)為GetHeadingFont 和 SetHeadingFont函數添加聲明 ,並在控件的執行文件(.CPP)添加模板函數:
//{{AFX_DISPATCH_MAP(CSampleCtrl)
DISP_PROPERTY_EX(CSampleCtrl, "HeadingFont", GetHeadingFont,
SetHeadingFont, VT_DISPATCH)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP() LPFONTDISP CSampleCtrl::GetHeadingFont()
{
// TODO: Add your property handler here
return NULL;
}
void CSampleCtrl::SetHeadingFont(LPFONTDISP newValue)
{
// TODO: Add your property handler here
SetModifiedFlag();
}
最後, ClassWizard修改控件的 .ODL 文件,為HeadingFont 屬性添加一個入口:[id(1)] IFontDisp* HeadingFont;
修改控件代碼
現在你已經為控件添加了HeadingFont屬性,你必須對控件的頭文件和執行文件進行修改以完全支持新的屬性。在控件的頭文件(.H),添加一個protected成員變量的聲明:
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函數的調用,提供自定義字體屬性的初始化和持久化。
void CSampleCtrl::DoPropExchange(CPropExchange* pPX)
完成控件的GetHeadingFont成員函數。
{
COleControl::DoPropExchange(pPX);
// [...other PX_ function calls...]
PX_Font(pPX, _T("HeadingFont"), m_fontHeading, &_fontdescHeading);
} LPFONTDISP CSampleCtrl::GetHeadingFont( )
完成控件的SetHeadingFont成員函數
{
return m_fontHeading.GetFontDispatch( );
} 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);
添加標准字體屬性頁自定義字體屬性設置完成後,應添加標准字體屬性頁,允許控件使用者更改控件當前的字體。為標准字體屬性頁增加屬性頁的ID號, 在BEGIN_PROPPAGEIDS宏後添加如下行:
PROPPAGEID(CLSID_CFontPropPage)
完成這些工作後,重新編譯工程。
例程2:Label1.ocx
例程2的Label1控件與例程1的Label控件在功能實現上沒有任何區別,只是在改變字體特性時,不再使用庫存字體屬性Font,而是使用自定義字體屬性CaptionFont。下面我們將結合Label1控件介紹如何在控件中使用自定義屬性。
打開Visual C++ 6.0,按照例程1的操作步驟新建Label1工程,象例程1那樣接受所有默認設置, 完成Label1工程創建。如圖2-1。
圖2-1
使用ClassWizard 給控件增加庫存屬性BackColor,ForeColor,Caption
按上述同樣操作,添加庫存屬性ForeColor,Caption。BackColor,ForeColor,Caption這三個屬性分別用來設置Label1控件的背景色,前景色和字符串內容。如圖2-2。
圖2-2
使用ClassWizard 給控件增加自定義屬性CaptionFont
如圖2-3
圖2-3
修改控件代碼
在控件的頭文件(Label1Ctl.h),添加一個protected成員變量的聲明:
protected:
CFontHolder m_fontCaption;
如圖2-4。
圖2-4
在控件的執行文件(.CPP)中,如下操作:
在控件的構造函數中初始化m_fontCaption。
CLabel1Ctrl::CLabel1Ctrl(): m_fontCaption(&m_xFontNotification)
{
InitializeIIDs(&IID_DLabel1, &IID_DLabel1Events);
// TODO: Initialize your control''s instance data here.
}
聲明一個靜態FONTDESC結構,該結構包含缺省的字體屬性。
static const FONTDESC _fontdescCaption =
{ sizeof(FONTDESC), OLESTR("MS Sans Serif"), FONTSIZE( 12 ), FW_BOLD,
ANSI_CHARSET, FALSE, FALSE, FALSE };
在控件的DoPropExchange 成員函數,添加一個PX_Font函數的調用,提供自定義字體屬性的初始化和持久化。
void CLabel1Ctrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
PX_Font(pPX, _T("CaptionFont"), m_fontCaption, &_fontdescCaption);
}
完成控件的GetCaptionFont成員函數。
LPFONTDISP CLabel1Ctrl::GetCaptionFont()
{
// TODO: Add your property handler here
return m_fontCaption.GetFontDispatch();
}
完成控件的SetHeadingFont成員函數
void CLabel1Ctrl::SetCaptionFont(LPFONTDISP newValue)
{
// TODO: Add your property handler here
m_fontCaption.InitializeFont(&_fontdescCaption,newValue);
OnFontChanged();
SetModifiedFlag();
}
修改控件的OnDraw成員函數,
void CLabel1Ctrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
// TODO: Replace the following code with your own drawing code.
COLORREF colorBack=TranslateColor(GetBackColor());
COLORREF colorFore=TranslateColor(GetForeColor());
CBrush brush(colorBack);
pdc->FillRect(rcBounds, &brush);
//背景色填充整個控件
pdc->SetBkMode(TRANSPARENT);
//設置透明背景色
pdc->SetTextColor(colorFore);
//前景色設置為字體顏色
const CString& strCaption = InternalGetText();
//獲得庫存屬性Caption的值
CFont* pOldFont;
pOldFont = SelectFontObject(pdc,m_fontCaption);
//設備上下文中選擇字體對象
RECT rect;
::CopyRect(&rect,rcBounds);
pdc->DrawText(strCaption,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
//單行,水平居中,垂直居中顯示
pdc->SelectObject(pOldFont);
}
添加顏色屬性頁和字體屬性頁打開工程的Label1Ctl.cpp文件,將其中的如下代碼進行修改:
BEGIN_PROPPAGEIDS(CLabel1Ctrl, 1)
修改後的代碼:
PROPPAGEID(CLabelPropPage::guid)
END_PROPPAGEIDS(CLabel1Ctrl)BEGIN_PROPPAGEIDS(CLabel1Ctrl, 3) // 具體個數由實際情況而定
修改系統自帶的屬性頁
PROPPAGEID(CLabel1PropPage::guid)//系統自帶的屬性頁
PROPPAGEID(CLSID_CColorPropPage) //加入Color屬性頁
PROPPAGEID(CLSID_CFontPropPage) //加入Font屬性頁
END_PROPPAGEIDS(CLabel1Ctrl)
打開系統自帶的屬性頁資源IDD_PROPPAGE_LABEL1,將靜態文本框IDC_STATIC的內容改為"Caption:",添加一個編輯框(Edit Box)控件,控件ID為IDC_CAPTION。如圖2-5。
圖2-5
按下"Ctrl+W"組合鍵打開ClassWizard,選中Member Variables標簽,Class name:下拉列表框選擇CLabel1PropPage,Control IDs:選中IDC_CAPTION,單擊Add Variable…按鈕,彈出Add Member Variable對話框。
在Add Member Variable對話框中,Member variable name:框輸入m_caption,Category選擇Value,Variable type:框選擇CString,Optional property name:框選擇Caption,單擊OK按鈕。
再次單擊OK按鈕關閉ClassWizard。
上述操作,編輯框IDC_CAPTION與Caption屬性之間建立了聯系。您可以通過修改編輯框的內容來改變控件Caption的屬性值。
編譯並構建Label1.ocx控件。
第三部分 使用多種字體
前面分別詳細說明了如何在控件中使用庫存屬性和自定義屬性。但有時我們需要在一個控件中使用多種字體,下面我們將說明如何在一個控件中實現多種字體屬性。
大多數情況下,每個字體對象都能夠通過調用IFontNotification接口的成員函數(由COleControl實現)在自身更改時提供通知。如果控件使用庫存Font屬性,則其通知由COleControl的OnFontChanged成員函數處理。當添加自定義Font屬性時,可以讓它們使用同一實現。在第二部分的例程中,這一點通過在初始化m_fontCaption成員變量時傳遞&m_xFontNotification來實現。
例程3將演示多個字體對象使用IFontNotification的同一實現,實現在一個控件中使用多種字體。
例程3:LabelEx0.ocx
例程1的Label控件確實增強了VC++工具箱中的Static Text控件的功能。但對於形如"m3/h","h2o"的文本內容,使用一個Label控件就有點無能為力了,下面我們將制作一個LabelEx0控件來再次擴展Label控件的功能,同時演示如何在控件中添加多種字體屬性。
LabelEx0控件內部由上、中、下三個部分組成,三個部分的字體內容和字體屬性可以分別設置,以方便地顯示上下標部分。
打開Visual C++ 6.0,新建LabelEx0工程,接受所有默認設置,完成LabelEx0工程創建。使用ClassWizard 給控件增加庫存屬性BackColor,ForeColor:
我們已經給控件增加了庫存屬性BackColor,該屬性用以設置LabelEx0控件的背景色。按上述同樣操作,添加庫存屬性ForeColor。
使用ClassWizard 給控件增加自定義屬性CaptionUp,CaptionMiddle,CaptionDown:
按上述同樣操作,添加自定義屬性CaptionMiddle,CaptionDown。CaptionUp,CaptionMiddle和CaptionDown分別用以設置LabelEx0控件上、中、下三個部分的文本內容。
使用ClassWizard 給控件增加自定義屬性XUp,YUp,XMiddle, YMiddle, XDown, YDown
按上述同樣操作,添加自定義屬性YUp,XMiddle, YMiddle, XDown和YDown。其中XUp 和Yup屬性用來決定上標文本的位置;XMiddle和YMiddle用以設置中間文本的位置;XDown和YDown 用以設置LabelEx0控件下標文本的位置。
使用ClassWizard 給控件增加自定義屬性FontUp,FontMiddle,FontDown
按上述同樣操作,添加自定義屬性FontMiddle,FontDown。FontUp,FontMiddle和FontDown分別用以設置LabelEx0控件上、中、下三個部分的字體屬性。
添加顏色屬性頁和字體屬性頁
打開工程的LabelEx0Ctl.cpp文件,將其中的如下代碼進行修改:
BEGIN_PROPPAGEIDS(CLabelEx0Ctrl, 1)
PROPPAGEID(CLabelEx0PropPage::guid)
END_PROPPAGEIDS(CLabelEx0Ctrl)
修改後的代碼: BEGIN_PROPPAGEIDS(CLabelEx0Ctrl, 3) // 具體個數由實際情況而定
PROPPAGEID(CLabelEx0PropPage::guid)//系統自帶的屬性頁
PROPPAGEID(CLSID_CColorPropPage) //加入Color屬性頁
PROPPAGEID(CLSID_CFontPropPage) //加入Font屬性頁
END_PROPPAGEIDS(CLabelEx0Ctrl)
修改系統自帶的屬性頁
打開系統自帶的屬性頁資源IDD_PROPPAGE_LABELEx0,把屬性頁的尺寸由250×62調整為250×110。刪除原有的靜態文本框,重新添加9個靜態文本框,靜態文本框的內容依次為"CaptionUp:", "CaptionMiddle:","CaptionDown:","XUp:","Yup:","XMiddle:","YMiddle:","XDown:","YDown:"。添加9個對應的編輯框(Edit Box)控件,控件ID依次為IDC_CAPTIONUP,IDC_CAPTIONMIDDLE,IDC_CAPTIONDOWN,IDC_XUP,IDC_YUP,IDC_XMIDDLE,IDC_YMIDDLE,IDC_XDOWN,IDC_YDOWN。其中,IDC_CAPTIONUP,IDC_CAPTIONMIDDLE,IDC_CAPTIONDOWN分別用於輸入上標,中間,下標的文本內容;IDC_XUP,IDC_YUP,IDC_XMIDDLE,IDC_YMIDDLE,IDC_XDOWN,IDC_YDOWN分別用於輸入上標,中間,下標的文本的坐標位置。如圖3-1。
圖3-1
按下"Ctrl+W"組合鍵打開ClassWizard,選中Member Variables標簽,Class name:下拉列表框選擇CLabelEx0PropPage,Control IDs:選中IDC_CAPTIONUP,單擊Add Variable…按鈕,彈出Add Member Variable對話框。
在Add Member Variable對話框中,Member variable name:框輸入m_captionUp,Category選擇Value,Variable type:框選擇CString,Optional property name:框選擇CaptionUp,單擊OK按鈕。重復上述操作,為其余8個編輯控件建立添加相應的成員變量。對應關系如下表:
控件ID
Member variable name
Category
Variable type
Optional property name
IDC_CAPTIONUP
m_captionUp
Value
CString
CaptionUp
IDC_CAPTIONMIDDLE
m_captionMiddle
Value
CString
CaptionMiddle
IDC_CAPTIONDOWN
m_captionDown
Value
CString
CaptionDown
IDC_XUP
m_xUp
Value
long
XUp
IDC_YUP
m_yUp
Value
long
YUp
IDC_XMIDDLE
m_xMiddle
Value
long
XMiddle
IDC_YMIDDLE
m_yMiddle
Value
long
YMiddle
IDC_XDOWN
m_xDown
Value
long
XDown
IDC_YDOWN
m_yDown
Value
long
YDown
再次單擊OK按鈕關閉ClassWizard。修改控件代碼在控件的頭文件(LabelEx0Ctl.h),添加三個protected成員變量的聲明:
protected:
CFontHolder m_fontUp;
CFontHolder m_fontMiddle;
CFontHolder m_fontDown;
在控件的執行文件(LabelEx0Ctl.CPP)中,如下操作:在控件的構造函數中初始化
m_fontUp, m_fontMiddle, m_fontDown。 CLabelEx0Ctrl::CLabelEx0Ctrl():m_fontUp(&m_xFontNotification),
m_fontMiddle(&m_xFontNotification),m_fontDown(&m_xFontNotification)
{
InitializeIIDs(&IID_DLabelEx0, &IID_DLabelEx0Events);
// TODO: Initialize your control''s instance data here.
}
聲明一個靜態FONTDESC結構,該結構包含缺省的字體屬性。
static const FONTDESC _fontdescCaption =
{ sizeof(FONTDESC), OLESTR("MS Sans Serif"), FONTSIZE( 12 ), FW_BOLD,
ANSI_CHARSET, FALSE, FALSE, FALSE };
在控件的DoPropExchange 成員函數,添加PX_函數的調用。
void CLabelEx0Ctrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
// TODO: Call PX_ functions for each persistent custom property.
PX_Font(pPX, _T("FontUp"), m_fontUp, &_fontdescCaption);
PX_Font(pPX, _T("FontMiddle"), m_fontMiddle, &_fontdescCaption);
PX_Font(pPX, _T("FontDown"), m_fontDown, &_fontdescCaption);
PX_Long(pPX,_T("XUp"),m_xUp,0);
PX_Long(pPX,_T("YUp"),m_yUp,0);
PX_Long(pPX,_T("XMiddle"),m_xMiddle,0);
PX_Long(pPX,_T("YMiddle"),m_yMiddle,20);
PX_Long(pPX,_T("XDown"),m_xDown,0);
PX_Long(pPX,_T("YDown"),m_yDown,30);
PX_String(pPX, _T("CaptionUp"), m_captionUp, _T("上標"));
PX_String(pPX, _T("CaptionMiddle"), m_captionMiddle, _T("中間"));
PX_String(pPX, _T("CaptionDown"), m_captionDown, _T("下標"));
}
完成控件的成員函數
void CLabelEx0Ctrl::OnCaptionUpChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnCaptionMiddleChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnCaptionDownChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnXUpChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnYUpChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnXMiddleChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnYMiddleChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnXDownChanged()
{
InvalidateControl();
SetModifiedFlag();
}
void CLabelEx0Ctrl::OnYDownChanged()
{
InvalidateControl();
SetModifiedFlag();
}
LPFONTDISP CLabelEx0Ctrl::GetFontUp()
{
return m_fontUp.GetFontDispatch();
}
void CLabelEx0Ctrl::SetFontUp(LPFONTDISP newValue)
{
m_fontUp.InitializeFont(&_fontdescCaption,newValue);
OnFontChanged();
SetModifiedFlag();
}
LPFONTDISP CLabelEx0Ctrl::GetFontMiddle()
{
return m_fontMiddle.GetFontDispatch();
}
void CLabelEx0Ctrl::SetFontMiddle(LPFONTDISP newValue)
{
m_fontMiddle.InitializeFont(&_fontdescCaption,newValue);
OnFontChanged();
SetModifiedFlag();
}
LPFONTDISP CLabelEx0Ctrl::GetFontDown()
{
return m_fontDown.GetFontDispatch();
}
void CLabelEx0Ctrl::SetFontDown(LPFONTDISP newValue)
{
m_fontDown.InitializeFont(&_fontdescCaption,newValue);
OnFontChanged();
SetModifiedFlag();
}
修改OnDraw函數,修改後的OnDraw函數如下:
void CLabelExCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
// TODO: Replace the following code with your own drawing code.
COLORREF colorBack=TranslateColor(GetBackColor());
COLORREF colorFore=TranslateColor(GetForeColor());
CBrush brush(colorBack);
pdc->FillRect(rcBounds, &brush);
pdc->SetBkMode(TRANSPARENT);
pdc->SetTextColor(colorFore);
CFont* pOldFont;
RECT rect;
::CopyRect(&rect,rcBounds);
pOldFont = SelectFontObject(pdc, m_fontUp);
pdc->TextOut(m_xUp,m_yUp,m_captionUp);
SelectFontObject(pdc, m_fontMiddle);
pdc->TextOut(m_xMiddle,m_yMiddle,m_captionMiddle);
SelectFontObject(pdc, m_fontDown);
pdc->TextOut(m_xDown,m_yDown,m_captionDown);
pdc->SelectObject(pOldFont);
}
LabelEx0控件的制作已經完成了。您可以對它進行測試,並使用它制作形如"m3/h"樣式的標簽。
第四部分 優化代碼,合理地使用多種字體
上例中三個字體對象使用同一IFontNotification實現,不能具體區分控件字體對象的通知。如果想區分哪個字體已更改,可以使用以下方法:
為控件的每個字體對象各創建一個單獨的IFontNotification接口實現。此技術使您只需更新使用最近修改的字體的一個或多個字符串,從而優化了繪制代碼。以下將以修改例程3 LabelEx0的字體屬性FontUp為例來說明如何為第二個字體屬性實現單獨的通知接口所必需的步驟。
實現新的字體通知接口
若要區分兩個或多個字體的通知,必須為控件中使用的每個字體各實現一個新的通知接口。以下各節介紹如何通過修改控件頭文件和實現文件來實現新的字體通知接口。
向頭文件中添加的內容
在控件頭文件(CLabelEx0Ctrl.H)中,添加下列代碼:
DECLARE_INTERFACE_MAP() //聲明接口映射
BEGIN_INTERFACE_PART(FontUpNotify,IPropertyNotifySink)//聲明實現接口IPropertyNotifySink的嵌套類
INIT_INTERFACE_PART(CLabelEx0Ctrl,FontUpNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(FontUpNotify)
這樣,CLabelEx0Ctrl中多了一個嵌套類XFontUpNotify,以及它的一個變量m_xFontUpNotify。在CLabelEx0Ctrl的實現文件中加入該嵌套類的實現:
//映射接口IPropertyNotifySink到相應的嵌套類
BEGIN_INTERFACE_MAP(CLabelEx0Ctrl,COleControl)
INTERFACE_PART(CLabelEx0Ctrl,IID_IPropertyNotifySink,FontUpNotify)
END_INTERFACE_MAP()
STDMETHODIMP_(ULONG) CLabelEx0Ctrl::XFontUpNotify::AddRef()
{
METHOD_PROLOGUE_EX(CLabelEx0Ctrl,FontUpNotify)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CLabelEx0Ctrl::XFontUpNotify::Release()
{
METHOD_PROLOGUE_EX(CLabelEx0Ctrl,FontUpNotify)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CLabelEx0Ctrl::XFontUpNotify::QueryInterface(REFIID iid,LPVOID FAR* ppvObj)
{
METHOD_PROLOGUE_EX(CLabelEx0Ctrl,FontUpNotify)
return (HRESULT)pThis->ExternalQueryInterface(&iid,ppvObj);
}
STDMETHODIMP CLabelEx0Ctrl::XFontUpNotify::OnChanged(DISPID)
{
METHOD_PROLOGUE_EX(CLabelEx0Ctrl,FontUpNotify)
pThis->InvalidateControl();
return NOERROR;
}
STDMETHODIMP CLabelEx0Ctrl::XFontUpNotify::OnRequestEdit(DISPID)
{
return NOERROR;
}
在CLabelEx0Ctrl類的構造函數代碼中,將m_fontUp(&m_xFontNotification)更改為m_fontUp(&m_xFontUpNotify)。對項目執行完這些更改後,重新生成項目,並使用測試容器測試接口。
例程4:LabelEx.ocx
例程4的控件名稱為LabelEx.ocx,它是例程3代碼的優化,實現與例程3完全相同的功能。打開Visual C++ 6.0,新建LabelEx工程,接受所有默認設置,完成LabelEx工程創建。完成所有與例程3完全相同的操作,完成後再作如下改動和補充:
向控件頭文件(CLabelExCtrl.H)中添加下列代碼
DECLARE_INTERFACE_MAP() //聲明接口映射
CLabelExCtrl類的構造函數的代碼作如下改動
BEGIN_INTERFACE_PART(FontUpNotify,IPropertyNotifySink)
INIT_INTERFACE_PART(CLabelExCtrl,FontUpNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(FontUpNotify)
BEGIN_INTERFACE_PART(FontMiddleNotify,IPropertyNotifySink)
INIT_INTERFACE_PART(CLabelExCtrl,FontMiddleNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(FontMiddleNotify)
BEGIN_INTERFACE_PART(FontDownNotify,IPropertyNotifySink)
INIT_INTERFACE_PART(CLabelExCtrl,FontDownNotify)
STDMETHOD(OnRequestEdit)(DISPID);
STDMETHOD(OnChanged)(DISPID);
END_INTERFACE_PART(FontDownNotify)
在CLabelExCtrl的實現文件中加入該嵌套類的實現
BEGIN_INTERFACE_MAP(CLabelExCtrl,COleControl)
INTERFACE_PART(CLabelExCtrl,IID_IPropertyNotifySink,FontUpNotify)
INTERFACE_PART(CLabelExCtrl,IID_IPropertyNotifySink,FontMiddleNotify)
INTERFACE_PART(CLabelExCtrl,IID_IPropertyNotifySink,FontDownNotify)
END_INTERFACE_MAP()
STDMETHODIMP_(ULONG) CLabelExCtrl::XFontUpNotify::AddRef()
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontUpNotify)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CLabelExCtrl::XFontUpNotify::Release()
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontUpNotify)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CLabelExCtrl::XFontUpNotify::QueryInterface(REFIID iid,LPVOID FAR* ppvObj)
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontUpNotify)
return (HRESULT)pThis->ExternalQueryInterface(&iid,ppvObj);
}
STDMETHODIMP CLabelExCtrl::XFontUpNotify::OnChanged(DISPID)
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontUpNotify)
pThis->InvalidateControl();
return NOERROR;
}
STDMETHODIMP CLabelExCtrl::XFontUpNotify::OnRequestEdit(DISPID)
{
return NOERROR;
}
STDMETHODIMP_(ULONG) CLabelExCtrl::XFontMiddleNotify::AddRef()
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontMiddleNotify)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CLabelExCtrl::XFontMiddleNotify::Release()
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontMiddleNotify)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CLabelExCtrl::XFontMiddleNotify::QueryInterface(REFIID iid,LPVOID FAR* ppvObj)
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontMiddleNotify)
return (HRESULT)pThis->ExternalQueryInterface(&iid,ppvObj);
}
STDMETHODIMP CLabelExCtrl::XFontMiddleNotify::OnChanged(DISPID)
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontMiddleNotify)
pThis->InvalidateControl();
return NOERROR;
}
STDMETHODIMP CLabelExCtrl::XFontMiddleNotify::OnRequestEdit(DISPID)
{
return NOERROR;
}
STDMETHODIMP_(ULONG) CLabelExCtrl::XFontDownNotify::AddRef()
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontDownNotify)
return (ULONG)pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CLabelExCtrl::XFontDownNotify::Release()
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontDownNotify)
return (ULONG)pThis->ExternalRelease();
}
STDMETHODIMP CLabelExCtrl::XFontDownNotify::QueryInterface(REFIID iid,LPVOID FAR* ppvObj)
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontDownNotify)
return (HRESULT)pThis->ExternalQueryInterface(&iid,ppvObj);
}
STDMETHODIMP CLabelExCtrl::XFontDownNotify::OnChanged(DISPID)
{
METHOD_PROLOGUE_EX(CLabelExCtrl,FontDownNotify)
pThis->InvalidateControl();
return NOERROR;
}
STDMETHODIMP CLabelExCtrl::XFontDownNotify::OnRequestEdit(DISPID)
{
return NOERROR;
}CLabelExCtrl::CLabelExCtrl():m_fontUp(&m_xFontUpNotify),
m_fontMiddle(&m_xFontMiddleNotify),m_fontDown(&m_xFontDownNotify)
{
InitializeIIDs(&IID_DLabelEx, &IID_DLabelExEvents);
// TODO: Initialize your control''s instance data here.
}
對項目執行完這些更改後,重新生成項目,並使用測試容器測試接口。本人初學VC++,所學粗淺,發表此文,以求共勉,還望方家指教。
e-mail:[email protected] 或 [email protected]。