上一篇文章介绍了如何创建基于对话框的模态对话框和非模态对话框。这篇文章为大家介绍一下字体对话框和颜色对话框的创建与实现。
话不多说,我们先来看一下效果图。
此实例要实现的功能:
MFC使用CFontDialog类封装了字体对话框的所有操作。字体对话框也是一种模态对话框。
CFontDialog类的构造函数:
CFontDialog(
LPLOGFONT lplfInitial = NULL,
DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
CDC* pdcPrinter = NULL,
CWnd* pParentWnd = NULL
);
参数说明:
参数 | 作用 |
---|---|
lplfInitial | 指向 LOGFONT 结构体数据的指针,可以通过它设置字体的一些特征 |
dwFlags | 指定选择字体的一个或多个属性 |
pdcPrinter | 指向一个打印设备上下文的指针 |
pParentWnd | 指向字体对话框父窗口的指针 |
LOGFONT 指针 | LOGFONT 结构体中包含了字体的大部分特征,包括字体高度、宽度、方向、名称等等 |
typedef struct tagLOGFONT {
LONG lfHeight;//指定高度(逻辑单位)
LONG lfWidth;//指定字符的平均宽度(逻辑单位)。如果为0,则比例自适应
LONG lfEscapement;//字符串的书写角度,单位0.1度,默认为0
LONG lfOrientation;//每个字符的书写角度,单位0.1度,默认为0
LONG lfWeight;//字符的笔画粗细,范围0~1000,0表示默认粗细,使用数字或下表中定义的宏均可。(见表一)
BYTE lfItalic;//指定字体是否是斜体
BYTE lfUnderline;//指定字体是否有下划线
BYTE lfStrikeOut;//指定字体是否有删除线
BYTE lfCharSet;//指定字符集
BYTE lfOutPrecision;//指定文字的输出精度(见表二)
BYTE lfClipPrecision;//指定文字的剪辑精度(见表三)
BYTE lfQuality;//指定文字的输出质量(见表四)
BYTE lfPitchAndFamily;//指定以常规方式描述字体的字体系列(见表五)
TCHAR lfFaceName[LF_FACESIZE];//字体名称,名称不得超过 31 个字符。如果是空字符串,系统将使用第一个满足其它属性的字体。
} LOGFONT;
表一:
宏 | 粗细值 |
---|---|
FW_DONTCARE | 0 |
FW_THIN | 100 |
FW_EXTRALIGHT | 200 |
FW_ULTRALIGHT | 200 |
FW_LIGHT | 300 |
FW_NORMAL | 400 |
FW_REGULAR | 400 |
FW_MEDIUM | 500 |
FW_SEMIBOLD | 600 |
FW_DEMIBOLD | 600 |
FW_BOLD | 700 |
FW_EXTRABOLD | 800 |
FW_ULTRABOLD | 800 |
FW_HEAVY | 900 |
FW_BLACK | 900 |
表二:
lfOutPrecision 指定文字的输出精度。输出精度定义输出与所请求的字体高度、宽度、字符方向、行距、间距和字体类型相匹配必须达到的匹配程度。可以是以下值:
值 | 含义 |
---|---|
OUT_DEFAULT_PRECIS | 指定默认的映射行为 |
OUT_DEVICE_PRECIS | 当系统包含多个名称相同的字体时,指定设备字体 |
OUT_OUTLINE_PRECIS | 指定字体映射选择 TrueType 和其它的 outline-based 字体 |
OUT_RASTER_PRECIS | 当系统包含多个名称相同的字体时,指定光栅字体(即点阵字体) |
OUT_STRING_PRECIS | 这个值并不能用于指定字体映射,只是指定点阵字体枚举数据 |
OUT_STROKE_PRECIS | 这个值并不能用于指定字体映射,只是指定 TrueType 和其他的 outline-based 字体,以及矢量字体的枚举数据 |
OUT_TT_ONLY_PRECIS | 指定字体映射只选择 TrueType 字体。如果系统中没有安装 TrueType 字体,将选择默认操作 |
OUT_TT_PRECIS | 当系统包含多个名称相同的字体时,指定 TrueType 字体 |
表三:
lfClipPrecision指定文字的剪辑精度。剪辑精度定义如何剪辑字符的一部分位于剪辑区域之外的字符。可以是以下值:
值 | 含义 |
---|---|
CLIP_DEFAULT_PRECIS | 指定默认的剪辑行为 |
CLIP_STROKE_PRECIS | 这个值并不能用于指定字体映射,只是指定光栅(即点阵)、矢量或 TrueType 字体的枚举数据 |
CLIP_EMBEDDED | 当使用内嵌的只读字体时,必须指定这个标志 |
CLIP_LH_ANGLES | 如果指定了该值,所有字体的旋转都依赖于坐标系统的方向是逆时针或顺时针。如果没有指定该值,设备字体始终逆时针旋转,但是其它字体的旋转依赖于坐标系统的方向。该设置影响 lfOrientation 参数的效果。 |
表四:
lfQuality 指定文字的输出质量。输出质量定义图形设备界面 (GDI) 必须尝试将逻辑字体属性与实际物理字体的字体属性进行匹配的仔细程度。可以是以下值:
值 | 含义 |
---|---|
ANTIALIASED_QUALITY | 指定输出质量是抗锯齿的(如果字体支持)。 |
DEFAULT_QUALITY | 指定输出质量不重要。 |
DRAFT_QUALITY | 草稿质量。字体的显示质量是不重要的。对于光栅字体(即点阵字体),缩放是有效的,这就意味着可以使用更多的尺寸,但是显示质量并不高。如果需要,粗体、斜体、下划线和删除线字体会被合成。 |
NONANTIALIASED_QUALITY | 指定输出质量不是抗锯齿的。 |
PROOF_QUALITY | 正稿质量。指定字体质量比匹配字体属性更重要。对于光栅字体(即点阵字体),缩放是无效的,会选用其最接近的字体大小。虽然选中 PROOF_QUALITY 时字体大小不能精确地映射,但是输出质量很高,并且不会有畸变现象。如果需要,粗体、斜体、下划线和删除线字体会被合成。 |
表五:
lfPitchAndFamily 指定以常规方式描述字体的字体系列。字体系列描述大致的字体外观。字体系列用于在所需精确字体不可用时指定字体。
1~2 位指定字体间距,可以是以下值:
值 | 含义 |
---|---|
DEFAULT_PITCH | 指定默认间距 |
FIXED_PITCH | 指定固定间距 |
VARIABLE_PITCH | 指定可变间距 |
4~7 位指定字体系列,可以是以下值:
值 | 含义 |
---|---|
FF_DECORATIVE | 指定特殊字体。例如 Old English |
FF_DONTCARE | 指定字体系列不重要 |
FF_MODERN | 指定具有或不具有衬线的等宽字体。例如,Pica、Elite 和 Courier New 都是等宽字体 |
FF_ROMAN | 指定具有衬线的等比字体。例如 MS Serif |
FF_SCRIPT | 指定设计为类似手写体的字体。例如 Script 和 Cursive |
FF_SWISS | 指定不具有衬线的等比字体。例如 MS Sans Serif |
我们在字体对话框中选择了字体后,如何获取选定的字体呢?我们可以通过 CFontDialog 类的成员变量m_cf间接获得选定字体的CFont对象。m_cf是
CHOOSEFONT 类型的变量,CHOOSEFONT结构体定义如下:
typedef struct {
DWORD lStructSize;
HWND hwndOwner;
HDC hDC;
LPLOGFONT lpLogFont;
INT iPointSize;
DWORD Flags;
COLORREF rgbColors;
LPARAM lCustData;
LPCFHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
HINSTANCE hInstance;
LPTSTR lpszStyle;
WORD nFontType;
INT nSizeMin;
INT nSizeMax;
} CHOOSEFONT, *LPCHOOSEFONT;
CHOOSEFON结构体中有个成员 lpLogFont,它是指向LOGFONT结构体变量的指针,就像上面所说,LOGFONT 中包含了字体特征,例如,我们可以通过LOGFONT的lfFaceName得知字体名。
我们最终要获得的是所选择字体的CFont对象,有了字体的LOGFONT怎样获得对应的CFont对象呢?使用CFont类的成员函数CreateFontIndirect可以达到此目的。函数原型如下:
BOOL CreateFontIndirect(const LOGFONT* lpLogFont );
参数是LOGFONT指针类型,我们可以传入CFontDialog类成员变量m_cf的 lpLogFont成员,就可以得到所选字体的CFont对象了。
IDC_FONT_BUTTON
;,Caption 修改为“ 字体选择” ;再添加一个编辑框,ID设为IDC_FONT_EDIT
;再添加一个静态文本框,ID默认IDC_STATIC
,Caption 修改为“ 奥利给!!” 。CFont m_font
;用来保存编辑框中选择的字体。void CFontDlg::OnBnClickedFontButton()
{
// TODO: 在此添加控件通知处理程序代码
CString strFontName; // 字体名称
LOGFONT lf; // LOGFONT 变量
// 将 lf 所有字节清零
memset(&lf, 0, sizeof(LOGFONT));
// 将 lf 中的元素字体名设为“ 宋体”
_tcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("宋体"));
// 构造字体对话框,初始选择字体名为“ 宋体”
CFontDialog fontDlg(&lf);
if (IDOK == fontDlg.DoModal()) // 显示字体对话框
{
// 如果 m_font 已经关联了一个字体资源对象,则释放它
if (m_font.m_hObject)
{
m_font.DeleteObject();
}
// 使用选定字体的 LOGFONT 创建新的字体
m_font.CreateFontIndirect(fontDlg.m_cf.lpLogFont);
// 获取编辑框 IDC_FONT_EDIT 的 CWnd 指针,并设置其字体
GetDlgItem(IDC_FONT_EDIT)->SetFont(&m_font);// 如果用户选择了字体对话框的 OK 按钮,则获取被选择字体的名称并显示到编辑框里
strFontName = fontDlg.m_cf.lpLogFont->lfFaceName;
SetDlgItemText(IDC_FONT_EDIT, strFontName);
//字体属性赋值到静态文本
GetDlgItem(IDC_STATIC)->SetFont(&m_font);
}
}
MFC中提供了CColorDialog 类封装了颜色对
话框的所有操作,我们可以通过它显示颜色对话框,并获取颜色对话框中选择的
颜色。颜色对话框跟字体对话框一样,也是一种模态对话框。
CColorDialog 类的构造函数:
CColorDialog(
COLORREF clrInit = 0,
DWORD dwFlags = 0,
CWnd* pParentWnd = NULL
);
参数 | 功能 |
---|---|
clrInit | 默认选择颜色的颜色值,类型为 COLORREF,实际上就是unsigned long 类型。如果没有设置它的值,则默认为 RGB(0,0,0),即黑色 |
dwFlags | 自定义颜色对话框功能和外观的属性值 |
pParentWnd | 颜色对话框的父窗口的指针 |
我们使用颜色对话框的最终目的还是要获得在颜色对话框中选择的颜色值。为此CColorDialog类的成员函数GetColor()能够很好的实现我们的要求。
GetColor()
函数的原型为:
COLORREF GetColor( ) const;
它返回所选颜色的COLORREF值。
如果我们想获得R、G、B 各分量的值可以根据GetColor得到的COLORREF颜色值,通过使用GetRValue、GetGValue和GetBValue三个宏获得。
GetRValue
的语法形式为:
BYTE GetRValue(DWORD rgb);
参数rgb就是COLORREF颜色值,返回值即是R分量值。其他两个宏的形式与之类似。例如,GetColor()函数返回的COLORREF为10000,则R分量值就是 GetRValue(10000)。
接上面的字体文本框继续创建:
IDC_COLOR_BUTTON
,Caption设为“ 颜色选择” ;再添加四个静态文本框,ID分别为IDC_COLOR_STATIC
、IDC_R_STATIC
、IDC_G_STATIC
、IDC_B_STATIC
, Caption分别设为“颜色值:” 、“R:” 、“G:”、“B:” ,然后每个静态文本框后添加一个编辑框,四个编辑框的ID分别为IDC_COLOR_EDIT
、IDC_R_EDIT
、IDC_G_EDIT
、IDC_B_EDIT
。IDC_COLOR_BUTTON
添加点击消息的消息处理函数。
COLORREF color = RGB(0, 0, 0); // 颜色对话框的初始颜色为黑色
CColorDialog colorDlg(color); // 构造颜色对话框,传入初始颜色值
void CFontDlg::OnBnClickedColorButton()
{
// TODO: 在此添加控件通知处理程序代码
if(IDOK == colorDlg.DoModal()) // 显示颜色对话框,并判断是否点击了“ 确定”
{
color = colorDlg.GetColor(); // 获取颜色对话框中选择的颜色值
SetDlgItemInt(IDC_COLOR_EDIT, color); // 在 Color 编辑框中显示所选颜色值
SetDlgItemInt(IDC_R_EDIT, GetRValue(color)); // 在 R 编辑框中显示所选颜色的 R 分量值
SetDlgItemInt(IDC_G_EDIT, GetGValue(color)); // 在 G 编辑框中显示所选颜色的 G 分量值
SetDlgItemInt(IDC_B_EDIT, GetBValue(color)); // 在 B 编辑框中显示所选颜色的 B 分量值
}
Invalidate(TRUE);//最重要的一句代码,重绘窗口
}
HBRUSH CFontDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: 在此更改 DC 的任何特性
if (pWnd->GetDlgCtrlID() == IDC_STATIC)// IDC_STATIC1为所选文本框ID
{
pDC->SetTextColor(color);//设置字体颜色
}
// TODO: 如果默认的不是所需画笔,则返回另一个画笔
return hbr;
}
注:以下两行代码必须放在void CFontDlg::OnBnClickedColorButton()
函数外面。 这是因为OnCtlColor消息函数需要调用color的值给静态文本框显示的字符。
COLORREF color = RGB(0, 0, 0); // 颜色对话框的初始颜色为黑色
CColorDialog colorDlg(color); // 构造颜色对话框,传入初始颜色值