在用C++ Builder进行程序设计时,很多时候需要在运行状态下更改控件的字体名称或大小,虽然VCL类库中提供了TFontDialog对话框组件,但有时候并不是很方便。而C++ Builder本身又没有提供类似Word工具栏中的字体名称及大小的选择下拉列表,为方便使用,作者特编写两个字体组件 TFontNameComboBox和TFontSizeComboBox,下简单介绍一下实现的方法及原理。
要想取得系统所支持的字体及字体的大小,需要用到Windows SDK中的EnumFontFamiliesEx或EnumFontFamilies函数。这两个函数的函数原型如下:
int EnumFontFamiliesEx(
HDC hdc, // handle to device context
LPLOGFONT lpLogfont,// pointer to logical font information
FONTENUMPROC lpEnumFontFamExProc, // pointer to callback function
LPARAM lParam, // application-supplied data
DWORD dwFlags // reserved; must be zero
);
int EnumFontFamilies(
HDC hdc, // handle to device control
LPCTSTR lpszFamily, // pointer to family-name string
FONTENUMPROC lpEnumFontFamProc,// pointer to callback function
LPARAM lParam// address of application-supplied data
);
这两个函数的功能基本相同,但相对而言EnumFontFamiliesEx函数提供了更多的字体信息。在这两个函数中,都用到一个类型为FONTENUMPROC的回调函数,该函数的原型如下:
int CALLBACK EnumFontFamProc(
ENUMLOGFONT FAR *lpelf, // pointer to logical-font data
NEWTEXTMETRIC FAR *lpntm, // pointer to physical-font data
int FontType, // type of font
LPARAM lParam // address of application-defined data
);
这两个函数更详细的说明请参考MSDN。
下面是组件的简单实现代码:
/*===========================================================================
TFontNameComboBox及TFontNameSizeComboBox组件头文件
文件名称:FontComboBox.H
程序设计:梁生红
创建日期:2003-03-20
===========================================================================*/
#ifndef FontComboBoxH
#define FontComboBoxH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#include <StdCtrls.hpp>
#include <printers.hpp>
#include <Math.h>
//---------------------------------------------------------------------------
int static PixelsPerInch;
//下列两个回调函数一定不能为类成员函数
bool __stdcall EnumFontNameProc(ENUMLOGFONT FAR *lpelf,NEWTEXTMETRICEX FAR *lpntme,
int FontType, LPARAM lParam);
bool __stdcall EnumFontSizeProc(ENUMLOGFONT FAR *lpelf,NEWTEXTMETRIC FAR *lpntm,
int FontType, LPARAM lParam);
//---------------------------------------------------------------------------
/* TODO : TFontNameComboBox的声明 */
class PACKAGE TFontNameComboBox : public TCustomComboBox
{
private:
protected:
void __fastcall Build();
public:
__fastcall TFontNameComboBox(TComponent* Owner);
__published:
__property Style;
__property Anchors;
__property BiDiMode;
__property Color;
__property Constraints;
__property Ctl3D;
__property DragCursor;
__property DragKind;
__property DragMode;
__property DropDownCount;
__property Enabled;
__property Font;
__property ItemHeight;
__property MaxLength;
__property ParentBiDiMode;
__property ParentColor;
__property ParentCtl3D;
__property ParentFont;
__property ParentShowHint;
__property PopupMenu;
__property ShowHint;
__property TabOrder;
__property TabStop;
__property Visible;
__property OnChange;
__property OnClick;
__property OnContextPopup;
__property OnDblClick;
__property OnDragDrop;
__property OnDragOver;
__property OnDrawItem;
__property OnDropDown;
__property OnEndDock;
__property OnEndDrag;
__property OnEnter;
__property OnExit;
__property OnKeyDown;
__property OnKeyPress;
__property OnKeyUp;
__property OnMeasureItem;
__property OnStartDock;
__property OnStartDrag;
};
//---------------------------------------------------------------------------
/* TODO : TFontSizeComboBox的声明 */
class PACKAGE TFontSizeComboBox : public TCustomComboBox
{
private:
AnsiString FFontName;
void __fastcall SetFontName(AnsiString AFontName);
protected:
void __fastcall Build();
public:
__fastcall TFontSizeComboBox(TComponent* Owner);
__published:
__published:
__property AnsiString FontName = {read = FFontName, write = SetFontName};
__property Style;
__property Anchors;
__property BiDiMode;
__property Color;
__property Constraints;
__property Ctl3D;
__property DragCursor;
__property DragKind;
__property DragMode;
__property DropDownCount;
__property Enabled;
__property Font;
__property ItemHeight;
__property MaxLength;
__property ParentBiDiMode;
__property ParentColor;
__property ParentCtl3D;
__property ParentFont;
__property ParentShowHint;
__property PopupMenu;
__property ShowHint;
__property TabOrder;
__property TabStop;
__property Visible;
__property OnChange;
__property OnClick;
__property OnContextPopup;
__property OnDblClick;
__property OnDragDrop;
__property OnDragOver;
__property OnDrawItem;
__property OnDropDown;
__property OnEndDock;
__property OnEndDrag;
__property OnEnter;
__property OnExit;
__property OnKeyDown;
__property OnKeyPress;
__property OnKeyUp;
__property OnMeasureItem;
__property OnStartDock;
__property OnStartDrag;
};
//---------------------------------------------------------------------------
#endif
实现文件
/*===========================================================================
TFontNameComboBox及TFontNameSizeComboBox组件实现文件
文件名称:FontComboBox.CPP
程序设计:梁生红
创建日期:2003-03-20
===========================================================================*/
#include <vcl.h>
#pragma hdrstop
#include "FontComboBox.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TFontNameComboBox *)
{
new TFontNameComboBox(NULL);
}
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TFontSizeComboBox *)
{
new TFontSizeComboBox(NULL);
}
//---------------------------------------------------------------------------
/* TODO : 回调函数实现代码 */
bool __stdcall EnumFontNameProc(ENUMLOGFONT FAR *lpelf,NEWTEXTMETRICEX FAR *lpntme,
int FontType, LPARAM lParam)
{
char FontFullName[64];
strcpy(FontFullName,lpelf->elfFullName);
if(((TStrings*)(lParam))->IndexOf(FontFullName)==-1)
((TStrings*)(lParam))->Add(FontFullName);
return true;
}
//----------------------------------------------------------------------------
bool __stdcall EnumFontSizeProc(ENUMLOGFONT FAR *lpelf,NEWTEXTMETRIC FAR *lpntm,
int FontType, LPARAM lParam)
{
if(FontType&TRUETYPE_FONTTYPE)
{
((TStrings*)(lParam))->Add("8");
((TStrings*)(lParam))->Add("9");
((TStrings*)(lParam))->Add("10");
((TStrings*)(lParam))->Add("11");
((TStrings*)(lParam))->Add("12");
((TStrings*)(lParam))->Add("14");
((TStrings*)(lParam))->Add("16");
((TStrings*)(lParam))->Add("18");
((TStrings*)(lParam))->Add("20");
((TStrings*)(lParam))->Add("22");
((TStrings*)(lParam))->Add("24");
((TStrings*)(lParam))->Add("26");
((TStrings*)(lParam))->Add("28");
((TStrings*)(lParam))->Add("36");
((TStrings*)(lParam))->Add("48");
((TStrings*)(lParam))->Add("72");
return false;
}
else
{
AnsiString s;
int i,v,v2;
v = floor((lpelf->elfLogFont.lfHeight-lpntm->tmInternalLeading)*72/PixelsPerInch);
s = IntToStr(v);
for(i = 0;i<((TStrings*)(lParam))->Count-1;i++)
{
v2 = StrToInt(((TStrings*)(lParam))->Strings[i]);
if(v2==v)
return true;
if(v2>v)
{
((TStrings*)(lParam))->Insert(i,s);
return true;
}
}
((TStrings*)(lParam))->Add(s);
return true;
}
}
//---------------------------------------------------------------------------
/* TODO : TFontNameComboBox实现部分 */
__fastcall TFontNameComboBox::TFontNameComboBox(TComponent* Owner)
: TCustomComboBox(Owner)
{
Sorted = true;
if(!ComponentState.Contains(csDesigning))
Build();
}
//---------------------------------------------------------------------------
void __fastcall TFontNameComboBox::Build()
{
HDC DC = NULL;
LOGFONT LogFont;
TNotifyEvent OnChangeEvent;
OnChangeEvent = OnChange;
OnChange = NULL;
Items->Clear();
LogFont.lfCharSet = DEFAULT_CHARSET;
strcpy(LogFont.lfFaceName,"");
LogFont.lfPitchAndFamily = 0;
DC = GetDC(GetDesktopWindow());
try
{
EnumFontFamiliesEx(DC,&LogFont,(FONTENUMPROC)(EnumFontNameProc),LPARAM(Items),0);
}
__finally
{
ReleaseDC(GetDesktopWindow(),DC);
}
OnChange = OnChangeEvent;
if(Items->Count)
ItemIndex = 0;
}
//---------------------------------------------------------------------------
/* TODO : TFontSizeComboBox实现部分 */
__fastcall TFontSizeComboBox::TFontSizeComboBox(TComponent* Owner)
: TCustomComboBox(Owner)
{
Sorted = false;
}
//---------------------------------------------------------------------------
void __fastcall TFontSizeComboBox::SetFontName(AnsiString AFontName)
{
FFontName = AFontName;
if(!ComponentState.Contains(csDesigning))
{
Items->Clear();
Build();
}
}
//---------------------------------------------------------------------------
void __fastcall TFontSizeComboBox::Build()
{
TNotifyEvent OnChangeEvent = OnChange;
OnChange = NULL;
HDC DC = GetDC(GetDesktopWindow());
PixelsPerInch = GetDeviceCaps(DC, LOGPIXELSY);
try
{
EnumFontFamilies(DC, FFontName.c_str(), (FONTENUMPROC)(EnumFontSizeProc),LPARAM(Items));
}
__finally
{
ReleaseDC(GetDesktopWindow(),DC);
}
OnChange = OnChangeEvent;
if(Items->Count)
ItemIndex = 0;
}
//---------------------------------------------------------------------------
namespace Fontcombobox
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[2] = {__classid(TFontNameComboBox),
__classid(TFontSizeComboBox)};
RegisterComponents("Samples", classes, 1);
}
}
//---------------------------------------------------------------------------