解析C语言中的sizeof
hebei 第 1 页 105204873.doc
解析C语言中的sizeof 5
VC编程技巧:如何处理自定义消息 ......................................................................................................... 6 VC编程技巧:在属性页中添加字体对话框 ............................................................................................. 6 VC编程技巧:实现平面工具栏的最简单方法 ....................................................................................... 11 VC编程技巧:另外一种实现平面工具栏的方法 ...................................................................................... 12 如何获取应用程序的 实例句柄? .............................................................................................................. 27 如何通过代码获得应用程序主窗口的 指针? .......................................................................................... 27 如何在程序中获得其他程序的 图标? ...................................................................................................... 27 如何编程结束应用程序?如何编程控制WINDOWS的重新引导? ....................................................... 28 怎样加栽其他的应用程序? ........................................................................................................................ 28 确定应用程序的 路径 ................................................................................................................................ 29 获得各种目录信息 ...................................................................................................................................... 29 如何自定义消息 .......................................................................................................................................... 29 如何改变窗口的图标? ................................................................................................................................ 29 如何改变窗口的缺省风格? ........................................................................................................................ 30 如何将窗口居中显示? ................................................................................................................................ 30 如何让窗口和 MDI窗口一启动就最大化和最小化? ............................................................................. 30 如何使程序保持极小状态? ........................................................................................................................ 31 如何限制窗口的 大小? .............................................................................................................................. 31 如何使窗口不可见, .................................................................................................................................. 31 如何使窗口始终在最前方? ........................................................................................................................ 31 如何创建一个字回绕的CEDITVIEW ..................................................................................................... 32 通用控件的显示窗口 .................................................................................................................................. 32 移动窗口 ...................................................................................................................................................... 32 重置窗口的大小 .......................................................................................................................................... 32 如何单击除了窗口标题栏以外的区域使窗口移动 .................................................................................. 33 如何改变视窗的背景颜色 .......................................................................................................................... 33 如何改变窗口标题 ...................................................................................................................................... 34 如何防止主框窗口在其说明中显示活动的文档名 .................................................................................. 35 如何获取有关窗口正在处理的当前消息的信息 ...................................................................................... 35 如何创建一个不规则形状的窗口 .............................................................................................................. 35 如何在代码中获取工具条和状态条的指针 .............................................................................................. 37
- 1 ---
hebei 第 2 页 105204873.doc 如何使能和禁止工具条的工具提示 .......................................................................................................... 37 如何设置工具条标题 .................................................................................................................................. 37 如何创建和使用无模式对话框 .................................................................................................................. 38 如何在对话框中显示一个位图 .................................................................................................................. 39 如何改变对话或窗体视窗的背景颜色 ...................................................................................................... 39 如何一个创建三态下压按钮 ...................................................................................................................... 39 如何动态创建控件 ...................................................................................................................................... 39 如何限制编辑框中的准许字符 .................................................................................................................. 40 如何改变控件的颜色 .................................................................................................................................. 41 当向列
框中添加多个项时如何防止闪烁 .............................................................................................. 42 如何向编辑控件中添加文本 ...................................................................................................................... 42 如何访问预定义的GDI对象 .................................................................................................................... 42 如何获取GDI对象的属性信息 ................................................................................................................ 43 如何实现一个橡皮区矩形 .......................................................................................................................... 43 如何更新翻转背景颜色的文本 .................................................................................................................. 45 如何创建一个具有特定点大小的字体 ...................................................................................................... 45 如何计算一个串的大小 .............................................................................................................................. 45 如何显示旋转文本 ...................................................................................................................................... 46 如何正确显示包含标签字符的串 .............................................................................................................. 47 串太长时如何在其末尾显示一个省略号 .................................................................................................. 47 如何快速地格式化一个CSTRING对象 .................................................................................................. 48 为什么即使调用ENABLEMENUITEM菜单项后,菜单项还处于禁止状态 ..................................... 48 如何给系统菜单添加一个菜单项 .............................................................................................................. 48 如何确定顶层菜单所占据的菜单行数 ...................................................................................................... 49 在用户环境中如何确定系统显示元素的颜色 .......................................................................................... 49 如何查询和设置系统参数 .......................................................................................................................... 50 如何使用一个预定义的WINDOWS光标 ............................................................................................... 50 如何确定当前聊环直媛? ............................................................................................................................ 50 如何检索原先的TASK MANAGER应用程序使用的任务列表 ........................................................... 51 如何确定WINDOWS和WINDOWS系统目录 ..................................................................................... 51 在哪儿创建临文件 ...................................................................................................................................... 52 如何访问桌面窗口 ...................................................................................................................................... 52
- 2 ---
hebei 第 3 页 105204873.doc 为应用程序的主窗口设置图标 .................................................................................................................. 53 如何增加一个用户自定义消息 .................................................................................................................. 53 获得当前工作目录的路径 .......................................................................................................................... 54 如何将WINEXEC 、SHELLEXECUTE或者CREATEPROCESS这三个函数载入应用程序 ..... 55 关闭窗口 ...................................................................................................................................................... 55 显示窗口图标 .............................................................................................................................................. 56 应用程序极小化 .......................................................................................................................................... 56 实例句柄 ...................................................................................................................................................... 56 如何获取应用程序的 实例句柄? .............................................................................................................. 57 如何编程结束应用程序? ............................................................................................................................ 57 怎样加载其他的应用程序? ........................................................................................................................ 57 确定应用程序的路径. ................................................................................................................................. 58 获得各种目录信息 ...................................................................................................................................... 58 如何自定义消息 .......................................................................................................................................... 58 如何改变窗口的图标? ................................................................................................................................ 59 如何改变窗口的缺省风格? ........................................................................................................................ 59 如何将窗口居中显示? ................................................................................................................................ 59 通用控件的显示窗口 .................................................................................................................................. 59 移动窗口 ...................................................................................................................................................... 60 重置窗口的大小 .......................................................................................................................................... 60 如何单击除了窗口标题栏以外的区域使窗口移动 .................................................................................. 60 如何限制窗口的大小? ................................................................................................................................ 61 如何使窗口不可见, .................................................................................................................................. 61 如何使窗口始终在最前方? ........................................................................................................................ 61 如何创建一个字回绕的CEDITVIEW ..................................................................................................... 61 如何让窗口和 MDI窗口一启动就最大化和最小化? ............................................................................. 62 如何使程序保持极小状态? ........................................................................................................................ 62 如何限制窗口的大小? ................................................................................................................................ 62 如何改变视窗的背景颜色 .......................................................................................................................... 63 如何改变窗口标题 ...................................................................................................................................... 63 如何防止主框窗口在其说明中显示活动的文档名 .................................................................................. 64 如何获取有关窗口正在处理的当前消息的信息 ...................................................................................... 64
- 3 ---
hebei 第 4 页 105204873.doc 如何创建一个不规则形状的窗口 .............................................................................................................. 64 如何设置工具条标题 .................................................................................................................................. 66 如何创建和使用无模式对话框 .................................................................................................................. 66 如何在对话框中显示一个位图 .................................................................................................................. 67 如何改变对话或窗体视窗的背景颜色 ...................................................................................................... 67 怎样让MFC的TOOLBAR上的按钮上象WORD 6.0那样出小旗子? 自己改 ................................ 68 如何使用GDI绘制的BITMAP? ............................................................................................................. 68 WINDOWS位图颠倒存储和显示是出于什么目的? .............................................................................. 69 我想在用VC++1.5编程时,NEW一个[512][512]的大数组,却总是不行( ..................................... 69 VC如何去掉MAINFRAME菜单 ........................................................................................................... 69
- 4 ---
hebei 第 5 页 105204873.doc 解析C语言中的sizeof
一、sizeof的概念
sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。
二、sizeof的使用方法
1、用于数据类型
sizeof使用形式:sizeof(type) 数据类型必须用括号括住。如sizeof(int)。
2、用于变量
sizeof使用形式:sizeof(var_name)或sizeof var_name 变量名可以不用括号括住。如sizeof (var_name),sizeof var_name等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。 注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式。
三、sizeof的结果
sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
1、若操作数具有类型char、unsigned char或signed char,其结果等于1。ANSI C正式规定字符类型为1字节。
2、int、unsigned int 、short int、unsigned short 、long int 、unsigned long 、float、double、long double类型的sizeof 在ANSI C中没有具体规定,大小依赖于实现,一般可能分别为2、2、2、2、4、4、4、8、10。
3、当操作数是指针时,sizeof依赖于编译器。例如Microsoft C/C++7.0中,near类指针字节数为2,far、huge类指针字节数为4。一般Unix的指针字节数为4。
4、当操作数具有数组类型时,其结果是数组的总字节数。
5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数,包括任何垫补在内。
让我们看如下结构:
struct {char b; double x;} a;
在某些机器上sizeof(a)=12,而一般sizeof(char)+ sizeof(double)=9。这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被4整除的地址。
6、如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。 四、sizeof与其他操作符的关系
sizeof的优先级为2级,比/、%等3级运算符优先级高。它可以与其他操作符一起组成表达式。如i*sizeof(int);其中i为int类型变量。
五、sizeof的主要用途
1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如:
void *malloc(size_t size),
size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
2、sizeof的另一个的主要用途是计算数组中元素的个数。例如:
void * memset(void * s,int c,sizeof(s))。
六、建议
由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用ziseof来代替常量计算。
- 5 ---
hebei 第 6 页 105204873.doc VC编程技巧:如何处理自定义消息
ClassWizard不允许增加用户自定义消息,所以你必须手工输入。输入后,ClassWizard就可以象处理其它消息一样处理你自定义的消息了。
下面是增加自定义消息的步骤:
第一步:定义消息。开发Windows95应用程序时,Microsoft推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
第二步:实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。
LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息
...
return 0;
}
第三步:在类头文件的AFX_MSG块中说明消息处理函数:
class CMainFrame:public CMDIFrameWnd
{
...
// 一般消息映射函数
protected:
// {{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}
第四步:在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
如果用户需要一个整个系统唯一的消息,可以调用SDK函数RegisterWindowMessage并使用ON_REGISTER_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
VC编程技巧:在属性页中添加字体对话框
在属性页中添加字体对话框,MFC提供了三种属性页类:CFontPropPage、CColorPropPage和CPicturePropPage。但是,它们只能与OLE Automation一起使用。在本文中将介绍如何在属性对话框中添加字体属性页。解决的办法是你自己建立字体属性页。为了让你能定制通用对话框的行为,SDK提供了这些对话框的对话框资源。“Choose Font”对话框是在Include目录中的FONT.DLG文件中,相应的符号在DLGS.H文件中。使用这些文件作为出发点,我们可以为字体属性页建立资源,
- 6 ---
hebei 第 7 页 105204873.doc
并且添加一个使用这些资源的CPropertyPage继承类。下面的实现可能是有限的,但也有一定的参
考价值。如果你想增强它,可以查看MFC源程序目录中的CFontPropPage 源文件。
第一步:添加对话资源
你可以在DevStudio中打开下面的rc文件DevStudio,然后把对话框资源复制到你的主资源文
件中,或者你也可以把该资源文件包含进去。为了复制资源文件,请在DevStudio中打开“fontpage.rc”
文件,然后展开资源的outline。然后打开ResourceView,以便对话框资源是可见的。最后,从
fontpage.rc中拖动IDD_FONTPAGE资源到你的应用程序ResourceView的资源中。如果你想包含
fontpage资源文件,只要把“fontpage.rc”和“fontpagerc.h”文件 (在下面列出)到项目目录中的“res”
目录中即可。然后在该目录中已有的“rc2”文件中添加下面这段。资源图像也列在下面。
#include "fontpage.rc"
Listing of FontPage.rc
/////////////////////////////////////////////////////////////////////////
// Listing of FontPage.rc
//
#include "winresrc.h"
#include "FontPageRc.h"
IDD_FONTPAGE DIALOG DISCARDABLE 13, 54, 264, 133
STYLE WS_CHILD | WS_CAPTION | WS_SYSMENU
CAPTION "Font"
FONT 8, "Helv"
BEGIN
LTEXT "&Font:",stc1,6,3,40,9
COMBOBOX IDC_FONT,6,13,131,54,CBS_SIMPLE | CBS_AUTOHSCROLL |
CBS_SORT | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
LTEXT "Font St&yle:",stc2,153,3,44,9
COMBOBOX IDC_STYLE,153,13,64,54,CBS_SIMPLE | CBS_DISABLENOSCROLL |
WS_VSCROLL | WS_TABSTOP
LTEXT "&Size:",stc3,224,3,30,9
COMBOBOX IDC_FONTSIZE,224,13,32,54,CBS_SIMPLE |
CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Effects",grp1,6,72,84,34,WS_GROUP
CONTROL "Stri&keout",IDC_STRIKEOUT,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,10,82,49,10
CONTROL "&Underline",IDC_UNDERLINE,"Button",BS_AUTOCHECKBOX,10,
94,51,10
GROUPBOX "Sample",grp2,98,72,160,49,WS_GROUP
CTEXT "AaBbYyZz",IDC_SAMPLE,104,81,149,37,SS_NOPREFIX
END
/////////////////////////////////////////////////////////////////////////
// Listing of FontPageRc.h
/////////////////////////////////////////////////////////////////////////
#define IDC_STRIKEOUT 0x0410
#define IDC_UNDERLINE 0x0411
#define grp1 0x0430
#define grp2 0x0431
#define stc1 0x0440
#define stc2 0x0441
#define stc3 0x0442
#define IDC_SAMPLE 0x0444
#define IDC_FONT 0x0470
#define IDC_STYLE 0x0471
#define IDC_FONTSIZE 0x0472
#define IDD_FONTPAGE 1543
/////////////////////////////////////////////////////////////////////////
第二步:在你的项目中包含源文件
下面给出了头文件和实现文件。你只要简单的把它们包含到你的项目中,并且使用CFontPage
- 7 ---
hebei 第 8 页 105204873.doc
类就可以了。该类的实现是比较简单的。CFontPage构造函数获取一指向LOGFONT结构的指针。它使用该结构的信息来初始化自己。如果LOGFONT结构没有提供,则使用窗口的当前字体。在OnInitDialog()函数中,我们列出了所需字体和字体组合框。但是,任何字体特性的改变,都要调用OnSelChange()函数来实现。所有的信息映射入口都指向该函数。OnSelChange()函数更新内部信息,并且显示样本文本。
FontPage.h
#if
!defined(AFX_FONTPAGE_H__DE7EDEB3_056D_11D1_82DF_E2CDC9000000__INCLUDED_)
#define AFX_FONTPAGE_H__DE7EDEB3_056D_11D1_82DF_E2CDC9000000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// FontPage.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CFontPage dialog
class CFontPage : public CPropertyPage
{
DECLARE_DYNCREATE(CFontPage)
// Construction
public:
void GetCurrentFont(LPLOGFONT lplf);
CFontPage(LOGFONT* plogfont = NULL);
~CFontPage();
// Dialog Data
//{{AFX_DATA(CFontPage)
enum { IDD = IDD_FONTPAGE };
CStatic m_staticSample;
CComboBox m_comboStyle;
CComboBox m_comboSize;
CComboBox m_comboFont;
BOOL m_bStrikeOut;
BOOL m_bUnderline;
CString m_sFont;
CString m_sSize;
CString m_sStyle;
//}}AFX_DATA
// Overrides
// ClassWizard generate virtual function overrides
//{{AFX_VIRTUAL(CFontPage)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CFontPage)
virtual BOOL OnInitDialog();
afx_msg void OnSelChange();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
CFont m_fontSample;
int m_cyPixelsPerInch;
static int CALLBACK FontEnumProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX
*lpntme, int FontType, CFontPage* pFontPage );
};
- 8 ---
hebei 第 9 页 105204873.doc
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately
// before the previous line.
#endif // !defined(AFX_FONTPAGE_H__DE7EDEB3_056D_11D1_82DF_E2CDC9000000__
NCLUDED_)
FontPage.cpp
// FontPage.cpp : implementation file
//
#include "stdafx.h"
#include "resource.h"
#include "FontPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CFontPage property page
IMPLEMENT_DYNCREATE(CFontPage, CPropertyPage)
CFontPage::CFontPage(LOGFONT* plogfont /*= NULL*/) : CPropertyPage(CFontPage::IDD)
{
//{{AFX_DATA_INIT(CFontPage)
//}}AFX_DATA_INIT
LOGFONT logfont;
CWindowDC dc(GetDesktopWindow() );
m_cyPixelsPerInch = GetDeviceCaps(dc, LOGPIXELSY);
if( plogfont == NULL )
{
CFont *pfont = dc.GetCurrentFont();
pfont->GetLogFont( &logfont );
plogfont = &logfont;
}
m_fontSample.CreateFontIndirect( plogfont );
m_bStrikeOut = plogfont->lfStrikeOut;
m_bUnderline = plogfont->lfUnderline;
m_sFont = plogfont->lfFaceName;
m_sSize.Format( "%d", MulDiv(plogfont->lfHeight, 72,
m_cyPixelsPerInch) );
m_sStyle = _T("Regular");
if( plogfont->lfWeight >= 700 && plogfont->lfItalic)
m_sStyle = _T("Bold Italic");
else if( plogfont->lfItalic )
m_sStyle = _T("Italic");
else if ( plogfont->lfWeight >= 700 )
m_sStyle = _T("Bold");
}
CFontPage::~CFontPage()
{
}
void CFontPage::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontPage)
DDX_Control(pDX, IDC_SAMPLE, m_staticSample);
- 9 ---
hebei 第 10 页 105204873.doc
DDX_Control(pDX, IDC_STYLE, m_comboStyle);
DDX_Control(pDX, IDC_FONTSIZE, m_comboSize);
DDX_Control(pDX, IDC_FONT, m_comboFont);
DDX_Check(pDX, IDC_STRIKEOUT, m_bStrikeOut);
DDX_Check(pDX, IDC_UNDERLINE, m_bUnderline);
DDX_CBString(pDX, IDC_FONT, m_sFont);
DDX_CBString(pDX, IDC_FONTSIZE, m_sSize);
DDV_MaxChars(pDX, m_sSize, LF_FACESIZE);
DDX_CBString(pDX, IDC_STYLE, m_sStyle);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontPage, CPropertyPage)
//{{AFX_MSG_MAP(CFontPage)
ON_CBN_SELCHANGE(IDC_FONT, OnSelChange)
ON_CBN_SELCHANGE(IDC_STYLE, OnSelChange)
ON_CBN_SELCHANGE(IDC_FONTSIZE, OnSelChange)
ON_BN_CLICKED(IDC_STRIKEOUT, OnSelChange)
ON_BN_CLICKED(IDC_UNDERLINE, OnSelChange)
ON_CBN_KILLFOCUS(IDC_FONT, OnSelChange)
ON_CBN_KILLFOCUS(IDC_STYLE, OnSelChange)
ON_CBN_KILLFOCUS(IDC_FONTSIZE, OnSelChange)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontPage message handlers
BOOL CFontPage::OnInitDialog()
{
CPropertyPage::OnInitDialog();
CWindowDC dc(this);
LOGFONT logfont;
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfFaceName[0] = '\0';
logfont.lfPitchAndFamily = 0;
EnumFontFamiliesEx( dc.m_hDC, &logfont, (FONTENUMPROC)FontEnumProc,
(LPARAM) this, 0 );
// Fill Size combobox with "common" sizes
TCHAR*
Defaults[]={_T("8"),_T("9"),_T("10"),_T("11"),_T("12"),_T("14"),_T("16"),_T ("18"),
_T("20"), _T("22"), _T("24"), _T("26"), _T("28"), _T("36"), _T("48") };
for (int i = 0; i < (sizeof(Defaults)/sizeof(Defaults[0])); i++)
m_comboSize.AddString(Defaults[i]);
// Fill Style combobox with "common" styles
m_comboStyle.AddString( _T("Regular") );
m_comboStyle.AddString( _T("Bold") );
m_comboStyle.AddString( _T("Italic") );
m_comboStyle.AddString( _T("Bold Italic") );
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
int CALLBACK CFontPage::FontEnumProc
(ENUMLOGFONTEX *lpelfe,NEWTEXTMETRICEX *lpntme, int FontType, CFontPage*
pFontPage )
{
if( pFontPage->m_comboFont.FindStringExact( 0,
(LPCTSTR)lpelfe->elfFullName )==CB_ERR )
{
// Add to list
- 10 ---
hebei 第 11 页 105204873.doc
pFontPage->m_comboFont.AddString( (LPCTSTR)lpelfe->elfFullName );
}
return 1;
}
void CFontPage::OnSelChange()
{
// The selection hasn't changed yet, so change it
if( IsChild( GetFocus() ) && GetFocus()->GetParent()->IsKindOf(
RUNTIME_CLASS( CComboBox ) ) )
{
CComboBox *cb = (CComboBox *)GetFocus()->GetParent();
CString sText;
if( cb->GetCurSel() != CB_ERR )
{
cb->GetLBText( cb->GetCurSel(), sText );
cb->SetWindowText( sText );
}
}
UpdateData(TRUE);
LOGFONT logfont;
m_fontSample.GetLogFont( &logfont );
logfont.lfStrikeOut = m_bStrikeOut;
logfont.lfUnderline = m_bUnderline;
memcpy( logfont.lfFaceName, m_sFont, LF_FACESIZE );
logfont.lfHeight = MulDiv(atoi(m_sSize), m_cyPixelsPerInch, 72);
logfont.lfWeight = 400; //Regular
logfont.lfItalic = FALSE;
if( m_sStyle.Find( _T("Italic") ) != -1 )
logfont.lfItalic = TRUE;
if( m_sStyle.Find( _T("Bold") ) != -1 )
logfont.lfWeight = 700;
m_fontSample.DeleteObject();
m_fontSample.CreateFontIndirect( &logfont );
m_staticSample.SetFont(&m_fontSample);
}
void CFontPage::GetCurrentFont(LPLOGFONT lplf)
{
m_fontSample.GetLogFont( lplf );
}
VC编程技巧:实现平面工具栏的最简单方法
实现平面工具栏的最简单方法
在前面两篇文章中,你已经学到了如何实现类似 Word97 的工具栏。如果你不在乎工具栏上的 gripper(参见“如何实现类似 Word97 的工具栏”),可以教你一种最简单的方法来实现。
在建立了工具栏之后,加上下面一句:
m_wndToolBar.ModifyStyle(0, TBSTYLE_FLAT); 则就可以实现不带有gripper的平面工具栏了。太简单了吧。
- 11 ---
hebei 第 12 页 105204873.doc
: VC编程技巧:如何编写类似于Word97的工具栏
如何编写类似于Word97的工具栏
本文所讨论的工具栏类是同
的 MFC CToolBar 一同工作的。注意:你必须有新的
COMCTL32.DLL (版本4.7或更高)。它是随 Internet Explorer3 一同发行,并且将做为 Windows 98
的标准组件。如果你使用的是 VC++ 5,则你已经有该动态库了。
所谓类似 Word 97 的增强工具栏具有平面外观,它的左边带有“gripper”并且各组间带有分
隔线。当鼠标移动到上面时,按钮就会突出来。MFC 使用样式位来控制其平面外观。所以你不能
在建立工具栏时来设置这种样式,你必须建立之后使用SetFlatLookStyle()函数来修改其样式。平面
外观工具栏是透明绘制的。不幸的是,MFC 没有介绍该如何编写这种透明的工?栏,所以需要你重
绘背景。这要通过变尺寸和移动信息来实现,例如当你拖动可移动的工具栏。你也可通过其按钮样
式改变时来实现。例如,当按钮从按状态变成释放状态时,背景需要重新绘制。工具栏控制本身并
不在各组按钮间绘制分隔线,只是在其间增加一个空格。该类将取 WM_PAINT 消息,并在正确的
位置添加分隔线。工具栏控制也不支持在起左边或顶部的gripper。该类将调整其用户区并绘制相应
的 gripper。使用本类,只要简单的把你的 CToolBar 变成 CFlatToolBar,并在建立工具栏后调用
SetFlatLookStyle() 函数 (既当工具栏位图装入之后 )。下载源程序(3KB)999
VC编程技巧:另外一种实现平面工具栏的方法
(不需要MSI 另外一种实现平面工具栏的方法(不需要MSIE)
在前面的文章“如何编写类似于Word97的工具栏”中,已经看到了一种实现平面工具栏的
方法。事实上,它需要你的机器上要装有 MSIE (或comctl32.dll),这似乎有些不便。所以我自己开
发出了我自己版本的平面工具栏,而不需要上面的要求。我把它称为类CToolBarEx。使用
CToolBarEx,你可以在平面和传统方式间进行切换。更新是非常快的。其中有些代码你可能觉得很
眼熟。其实分隔线和 gripper 的绘制代码或多或少是从 Roger的代码中继承来的。我为什么要做那
些重复的工作。
在平面模式下,由 CToolBarEx 来负责所有的绘制工作; 在传统的模式下,由 MFC来完成
工作。由于 VC++ 4.2 及以后的版本提供了用户自绘能力,我们可以通过一局部辅助类在?面模式
中来模仿该特性,所以我们可以在忽略当前模式(平面或传统)的情况下使用该特性。如果你想进一?
了解用户自绘制的实现,可参见ToolBarEx.cpp文件。
CToolBarEx 包含有两个文件:
ToolBarEx.h
/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1997 by Joerg Koenig
// All rights reserved
//
// Distribute freely, except: don't remove my name from the source or
// documentation (don't take credit for my work), mark your changes (don'
// get me blamed for your possible bugs), don't alter or remove this
// notice.
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc., and
// I'll try to keep a version up to date. I can be reached as follows:
// J.Koenig@adg.de (company site)
// Joerg.Koenig@rhein-neckar.de (private site)
- 12 ---
hebei 第 13 页 105204873.doc
/////////////////////////////////////////////////////////////////////////////
#if
!defined(AFX_TOOLBAREX_H__1E0F37F5_4020_11D1_9FB1_444553540000__INCLUDED_)
#define AFX_TOOLBAREX_H__1E0F37F5_4020_11D1_9FB1_444553540000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// ToolBarEx.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CToolBarEx window
class CToolBarEx : public CToolBar
{
DECLARE_DYNAMIC(CToolBarEx)
// data members
private:
BOOL m_bFlatLook;
CSize m_sizeOffset; // real starting point of the image
COLORREF m_clrBtnFace;
COLORREF m_clrBtnHilight;
COLORREF m_clrBtnShadow;
int m_nLastBtn; // index of last formed button
UINT m_uTimerEvent;
CUIntArray m_Styles;
HWND m_hwndParent; // "real" parent (even in floating mode)
BOOL m_bDeleteImgList; // remember the way we've built the
image list
CFont m_GuiFont;
// Construction
public:
CToolBarEx();
// Attributes
public:
void SetFlatLook( BOOL bFlat = TRUE ){
if( bFlat != m_bFlatLook ) {
m_bFlatLook = bFlat;
if( ::IsWindow(GetSafeHwnd()) ) {
// force a repaint of all buttons
Invalidate();
// erase/draw the gripper
OnNcPaint();
}
}
}
BOOL IsFlatLook() const {
return m_bFlatLook;
}
// This function I've missed in CToolBar for more than one time ...
void GetSizes( CSize & szBtn, CSize & szImg ) const {
szBtn = m_sizeButton;
szImg = m_sizeImage;
}
// Get the window to which the toolbar initially was docked. This
// is not necessarily the window returned by CWnd::GetParent() or
// CControlBar::GetDockingFrame(). Both these functions don't
- 13 ---
hebei 第 14 页 105204873.doc
// return the expected window, if the toolbar is floating ...
CWnd * GetParentFrame() const {
return ::IsWindow(m_hwndParent) ?
CWnd::FromHandle(m_hwndParent) : 0;
}
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CToolBarEx)
//}}AFX_VIRTUAL
protected:
virtual void OnUpdateCmdUI( CFrameWnd* pTarget, BOOL bDisableIfNoHndle );
// Implementation
public:
virtual ~CToolBarEx();
// Generated message map functions
protected:
//{{AFX_MSG(CToolBarEx)
afx_msg void OnPaint();
afx_msg void OnSysColorChange();
afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnNcPaint();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//}}AFX_MSG
afx_msg LRESULT OnSetButtonSize(WPARAM, LPARAM);
afx_msg LRESULT OnSetBitmapSize(WPARAM, LPARAM);
DECLARE_MESSAGE_MAP()
private:
// Recalculate the starting point of the button's image.
void CalculateOffset() {
if( m_pStringMap != 0 && !m_pStringMap->IsEmpty() ) {
// there are strings assigned to at least one button
// center the image horizontal
m_sizeOffset.cx = (m_sizeButton.cx-m_sizeImage.cx)/2;
// the following value calculates as follows:
// The button must be big enough to hold the image:
// + 7 pixels on x
// + 6 pixels on y
// So the y-offset is "min" (6) / 2 == 3
m_sizeOffset.cy = 3;
} else {
// no button has text assigned: center the image on the button
m_sizeOffset.cx = (m_sizeButton.cx-m_sizeImage.cx)/2;
m_sizeOffset.cy = (m_sizeButton.cy-m_sizeImage.cy)/2;
}
}
// some special drawing functions:
void DrawDisabledButton( CDC &, const CRect & ) const;
void DrawSeparator( CDC &, CRect & ) const;
void DrawGripper( CDC & ) const;
HIMAGELIST GetImageList();
- 14 ---
hebei 第 15 页 105204873.doc
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous
line.
#endif //
!defined(AFX_TOOLBAREX_H__1E0F37F5_4020_11D1_9FB1_444553540000__INCLUDED_)
ToolBarEx.cpp
/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1997 by Joerg Koenig
// All rights reserved
//
// Distribute freely, except: don't remove my name from the source or
// documentation (don't take credit for my work), mark your changes (don'
// get me blamed for your possible bugs), don't alter or remove this
// notice.
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc., and
// I'll try to keep a version up to date. I can be reached as follows:
// J.Koenig@adg.de (company site)
// Joerg.Koenig@rhein-neckar.de (private site)
////////////////////////////////////////////////////////////////////////////
// ToolBarEx.cpp : implementation file
//
// Description:
// CToolBarEx provides additional features to the standard toolbar
// "CToolBar". The main addition is the flat mode (last seen in
// Developer Studio 5.0).
// There are no special requirements for having the flat mode in your
// application (no special comctl32.dll or what ever)!
// If you need custom draw abilities, then you have to use VC++ >= 4.2
// However, the flat mode should work with older versions of VC++ too (let me know of your
experiences!)
//
// Usage:
// The only task you have to perform, is to
// #include "ToolBarEx.h"
// in either StdAfx.h or MainFrm.h and to change the type of
// CMainFrame::m_wndToolBar from CToolBar to CToolBarEx.
// Don't forget to recompile :-)
//
// Acknowledgements:
// o The main idea of how to draw a separator and the gripper is stolen
// from Roger Onslow's MSIE flat toolbar.
// Thanks for saving my time, Roger ;-)
// o The embossed drawing of a disabled image came from
// Victor M. Vogelpoel (victorv@telic.nl)
// o Some hints for buttons with text came from
// David Bates (bates@econ.ubc.ca)
// (I'm still thinking, text on toolbar-buttons is broken.
- 15 ---
hebei 第 16 页 105204873.doc
// That has to be tooltip's work. However, texts on buttons
// now work)
//
//
// (known) bugs and limitations:
// o the CDRF_NEWFONT notification is still untested ...
// o Assigning texts to buttons may cause the buttons to
// resize horizontally without notified by CToolBar. This
// leads to a wrong calculation inside CalcDynamicLayout()
// and CalcFixedLayout(). One could override both these
// functions in derived classes to avoid that problem,
// but that would be a greater pain ...
//
// if you find others (and have a solution for them ?!), please let me know:
// Joerg.Koenig@rhein-neckar.de (private site) or
// J.Koenig@adg.de (company site)
//
// Changes:
// 11/07/97
// (2 minor bugs have been occured as a result of the last update :)
// o The WRAP state of a separator will be ignored now, if
// the bar is docked vertically
// o Draw an image transparently. This is needed only if one
// uses 256 color images.
//
// 10/30/97
// o texts on buttons now work
// o gripper improved for a closer look like Office97
// o disabled images now look embossed
// o a separator is drawn only if it has no WRAP state set
#include "stdafx.h"
#include "ToolBarEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// local helper class CCustomDrawInfo
//
// The helper class CCustomDrawInfo handles the messaging to the docking
// frame of the toolbar in flat mode only. If flat-mode is disabled, then
// MFC's own messanger will be used.
//
// A few words about custom draw on toolbars:
// o custom draw is possible for MFC >= 4.2 only (older versions don't know
// anything about certain structures ...)
// o MFC does not set the "rc" member of NMCUSTOMDRAW to the rectangle of the
// button that will be drawn. However, we do, so watch out, wether the
// toolbar is flat or not (or ignore the "rc" member in both cases).
// If the current mode is not "flat", then MFC's art of message arrive ...
// o MFC does not send a message for separators, so we too don't do it.
// o It seems that MFC toolbars never send *ERASE notifications; instead they
// send TBN_QUERYDELETE for instance.
- 16 ---
hebei 第 17 页 105204873.doc
// o The CDRF_NEWFONT notification result is ignored (in flat mode. Never
// tried with original MFC, because it is broken on toolbars).
/////////////////////////////////////////////////////////////////////////////
class CCustomDrawInfo {
#if _MFC_VER >= 0x0420
NMCUSTOMDRAW m_CDRW; // custom draw information holder
LRESULT m_PrePaint; // result from prepaint otification
LRESULT m_ItemPrePaint; // dito for specific item
CToolBarEx * m_pToolBar; // the real sender of the notification
CWnd * m_pReceiver; // the receiver of the notification
LRESULT NotifyParent();
#endif // _MFC_VER
public: // construction
CCustomDrawInfo( CDC & dc, CToolBarEx * pToolBar );
public:
// NotifyItemPrePaint() returns TRUE,
// if the user wants to do the default
// (CDRF_DODEFAULT) or FALSE, if the
// user wants to skip (CDRF_SKIPDEFAULT)
// Note that CDRF_SKIPDEFAULT is not
// allowed for CDDS_PREPAINT, CDDS_POSTPAINT !
// and CDDS_ITEMPOSTPAINT
void NotifyPrePaint();
BOOL NotifyItemPrePaint(int item);
void NotifyItemPostPaint(int item);
void NotifyPostPaint();
};
#if _MFC_VER >= 0x420
LRESULT CCustomDrawInfo :: NotifyParent() {
LRESULT lRes = CDRF_DODEFAULT;
if( m_pReceiver )
lRes = m_pReceiver->SendMessage(WM_NOTIFY,
WPARAM(m_CDRW.hdr.idFrom),
LPARAM(&m_CDRW));
return lRes;
}
CCustomDrawInfo :: CCustomDrawInfo( CDC & dc, CToolBarEx * pBar )
: m_PrePaint(0)
, m_ItemPrePaint(0)
{
VERIFY((m_pToolBar = pBar) != 0);
VERIFY((m_CDRW.hdc = dc.GetSafeHdc()) != 0);
HWND hwnd = pBar->GetSafeHwnd();
VERIFY(::IsWindow(hwnd));
// initialise the NMHDR member of the customdraw structure
m_CDRW.hdr.hwndFrom = hwnd;
m_CDRW.hdr.idFrom = UINT(::GetWindowLong(hwnd, GWL_ID));
m_CDRW.hdr.code = NM_CUSTOMDRAW;
// Do not use CControlBar::GetDockingFrame() to receive
// the parent. CWnd::GetParent() is inacceptable too.
// Both these functions don't work, if the toolbar is
// floating in the air!
m_pReceiver = pBar->GetParentFrame();
- 17 ---
hebei 第 18 页 105204873.doc
if( m_pReceiver )
VERIFY(::IsWindow(m_pReceiver->GetSafeHwnd()));
}
void CCustomDrawInfo :: NotifyPrePaint() {
// fill the customdraw structure with values for CDDS_PREPAINT
m_CDRW.dwDrawStage = CDDS_PREPAINT;
// the rest of the structure stays undefined in this stage
// of drawing.
m_PrePaint = NotifyParent();
}
BOOL CCustomDrawInfo :: NotifyItemPrePaint( int nItem ) {
BOOL bRet = TRUE; // we assume to do the default
if( m_PrePaint & CDRF_NOTIFYITEMDRAW ) {
m_CDRW.dwDrawStage = CDDS_ITEMPREPAINT;
m_pToolBar->GetItemRect(nItem, &m_CDRW.rc);
m_CDRW.dwItemSpec = DWORD(m_pToolBar->GetItemID(nItem));
UINT uStyle = m_pToolBar->GetButtonStyle(nItem);
BOOL bEnable = m_pToolBar->GetToolBarCtrl()
.IsButtonEnabled(m_CDRW.dwItemSpec);
m_CDRW.uItemState = (bEnable ? 0 : CDIS_DISABLED) |
(((uStyle & TBBS_PRESSED) || (uStyle & TBBS_CHECKED)) ?
CDIS_CHECKED : 0);
m_CDRW.lItemlParam = 0;
m_ItemPrePaint = NotifyParent();
if( m_ItemPrePaint & CDRF_SKIPDEFAULT )
bRet = FALSE;
}
return bRet;
}
void CCustomDrawInfo :: NotifyItemPostPaint( int nItem ) {
if( m_ItemPrePaint & CDRF_NOTIFYPOSTPAINT ) {
m_CDRW.dwDrawStage = CDDS_ITEMPOSTPAINT;
// the rest of the data has not been changed since ITEMPREPAINT
// make sure it is so:
ASSERT(m_pToolBar->GetItemID(nItem) == m_CDRW.dwItemSpec);
NotifyParent();
}
}
void CCustomDrawInfo :: NotifyPostPaint() {
if( m_PrePaint & CDRF_NOTIFYPOSTPAINT ) {
m_CDRW.dwDrawStage = CDDS_POSTPAINT;
NotifyParent();
}
}
#else // _MFC_VER < 4.2
CCustomDrawInfo :: CCustomDrawInfo( CDC & dc, CWnd * pParent ) {
}
void CCustomDrawInfo :: NotifyPrePaint() {
}
void CCustomDrawInfo :: NotifyPostPaint() {
}
BOOL CCustomDrawInfo :: NotifyItemPrePaint( int ) {
return TRUE; // we always make the drawing by ourself
- 18 ---
hebei 第 19 页 105204873.doc
}
void CCustomDrawInfo :: NotifyItemPostPaint( int ) {
}
#endif // _MFC_VER
/////////////////////////////////////////////////////////////////////////////
// CToolBarEx
CToolBarEx::CToolBarEx()
: m_bFlatLook(TRUE)
, m_clrBtnFace(::GetSysColor(COLOR_BTNFACE))
, m_clrBtnHilight(::GetSysColor(COLOR_BTNHILIGHT))
, m_clrBtnShadow(::GetSysColor(COLOR_BTNSHADOW))
, m_nLastBtn(-1)
, m_uTimerEvent(0)
{
CalculateOffset();
// create the default font, used for buttons with text
CFont Font;
BOOL bOldSys = FALSE;
if( ! Font.CreateStockObject( DEFAULT_GUI_FONT ) ) {
// older versions of Windows* (NT 3.51 for instance)
// fail with DEFAULT_GUI_FONT
VERIFY( Font.CreateStockObject( SYSTEM_FONT ) );
bOldSys = TRUE;
}
LOGFONT logfont ;
Font.GetLogFont( &logfont ) ;
if( bOldSys ) {
logfont.lfWeight = 400;
strcpy(logfont.lfFaceName,"MS Sans Serif");
}
logfont.lfHeight = 6 ;
logfont.lfWidth = 0 ; // let windows compute this.
VERIFY( m_GuiFont.CreateFontIndirect( &logfont ) ) ;
}
CToolBarEx::~CToolBarEx()
{
}
IMPLEMENT_DYNAMIC(CToolBarEx, CToolBar)
BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
//{{AFX_MSG_MAP(CToolBarEx)
ON_WM_PAINT()
ON_WM_SYSCOLORCHANGE()
ON_WM_NCCALCSIZE()
ON_WM_MOUSEMOVE()
ON_WM_NCPAINT()
ON_WM_TIMER()
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_MESSAGE(TB_SETBUTTONSIZE, OnSetButtonSize)
ON_MESSAGE(TB_SETBITMAPSIZE, OnSetBitmapSize)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CToolBarEx message handlers
LRESULT CToolBarEx :: OnSetButtonSize(WPARAM wParam, LPARAM lParam) {
LRESULT lResult = CToolBar::OnSetButtonSize(wParam, lParam);
- 19 ---
hebei 第 20 页 105204873.doc
if( lResult )
CalculateOffset();
return lResult;
}
LRESULT CToolBarEx :: OnSetBitmapSize(WPARAM wParam, LPARAM lParam) {
LRESULT lResult = CToolBar::OnSetBitmapSize(wParam, lParam);
if( lResult )
CalculateOffset();
return lResult;
}
void CToolBarEx::OnPaint()
{
HIMAGELIST hImg = GetImageList();
#ifdef _DEBUG
if( hImg == 0 ) {
TRACE0("CToolBarEx::OnPaint(): could not get image list\n");
}
#endif
if( m_bFlatLook && hImg ) {
CRect rcUpdate;
if( ! GetUpdateRect(rcUpdate) )
return;
if( m_pStringMap && !m_pStringMap->IsEmpty() )
CalculateOffset(); // strings may have been added
// attach image-list for even more MFC feeling :)
CImageList imglist;
imglist.Attach(hImg);
POINT cursor;
::GetCursorPos(&cursor);
ScreenToClient(&cursor);
CPaintDC dc(this); // device context for painting
CFont * pOldFont = dc.SelectObject(&m_GuiFont);
// Now it's time for the first custom-draw-notification...
CCustomDrawInfo cdrw(dc, this);
cdrw.NotifyPrePaint();
register const int nBtn = GetToolBarCtrl().GetButtonCount();
for( register int i = 0; i < nBtn; ++i ) {
CRect rc;
GetItemRect(i, rc);
int nBitmap; UINT uID, uStyleState;
GetButtonInfo(i, uID, uStyleState, nBitmap);
WORD wStyle = LOWORD(uStyleState);
WORD wState = HIWORD(uStyleState);
if( wState & TBSTATE_HIDDEN )
continue;
if( wStyle == TBSTYLE_SEP ) {
if( !(wState & TBSTATE_WRAP) || ! IsFloating() )
DrawSeparator(dc, rc);
} else {
if( ! CRect().IntersectRect(rcUpdate, rc) )
continue; // this button needs no repaint
- 20 ---
hebei 第 21 页 105204873.doc
// maybe the button has text
dc.SetTextColor(RGB(0,0,0));
dc.SetBkColor(m_clrBtnFace);
// There is a bug in CToolBar: If there are texts assigned
// to buttons, then the button-widths may change transparentl
// (without notified by CToolBar), so we recalculate the
// horizontal offset here:
m_sizeOffset.cx = (rc.Width() - m_sizeImage.cx) / 2;
if( ! cdrw.NotifyItemPrePaint(i) )
continue; // parent has already drawn the button
BOOL bBtnDown = (wState & TBSTATE_CHECKED) || (wState & TBSTATE_PRESSED);
BOOL bBtnEnabled = GetToolBarCtrl().IsButtonEnabled(int(uID))
dc.FillSolidRect(rc,m_clrBtnFace);
// it seems, that CDC::Draw3dRect() changes the background color
COLORREF clrBk = dc.GetBkColor();
if( bBtnDown )
// draw a pressed button
dc.Draw3dRect(rc, m_clrBtnShadow, m_clrBtnHilight);
else if( rc.PtInRect(cursor) && ! bBtnDown && bBtnEnabled )
// draw a normal button
dc.Draw3dRect(rc, m_clrBtnHilight, m_clrBtnShadow);
else if( ! bBtnDown && bBtnEnabled )
// Draw an invisible rect around the button.
// This prevents us from erasing the background
// if the button was formed before
// (that would cause the button to flicker ...)
dc.Draw3dRect(rc, m_clrBtnFace, m_clrBtnFace);
dc.SetBkColor(clrBk);
// the point where to start with the image
CPoint pt(rc.left + m_sizeOffset.cx + bBtnDown,
rc.top + m_sizeOffset.cy + bBtnDown);
imglist.Draw(&dc, nBitmap, pt, ILD_TRANSPARENT);
CString strText = GetButtonText(i);
if( strText.GetLength() ) {
CRect rectText(
rc.left+3+bBtnDown,
rc.top+m_sizeOffset.cy+m_sizeImage.cy+1+bBtnDown,
rc.right-3+bBtnDown,
rc.bottom-3+bBtnDown
);
dc.DrawText(strText, rectText,
DT_CENTER|DT_VCENTER|DT_NOCLIP);
}
if( ! bBtnEnabled )
// gray out that button
DrawDisabledButton(dc, rc);
cdrw.NotifyItemPostPaint(i);
}
}
dc.SelectObject(pOldFont);
if( ! m_bDeleteImgList )
imglist.Detach();
// last but not least: inform the parent for end of painting
cdrw.NotifyPostPaint();
- 21 ---
hebei 第 22 页 105204873.doc
} else
// classic mode (or couldn't receive imagelist)
CToolBar::OnPaint();
}
void CToolBarEx :: DrawDisabledButton( CDC & dc, const CRect & rc ) const {
// create a monochrome memory DC
CDC ddc;
ddc.CreateCompatibleDC(0);
CBitmap bmp;
bmp.CreateCompatibleBitmap(&ddc, rc.Width(), rc.Height());
CBitmap * pOldBmp = ddc.SelectObject(&bmp);
// build a mask
ddc.PatBlt(0, 0, rc.Width(), rc.Height(), WHITENESS);
dc.SetBkColor(m_clrBtnFace);
ddc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, rc.left, rc.top, SRCCOPY);
dc.SetBkColor(m_clrBtnHilight);
ddc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, rc.left, rc.top, RCPAINT);
// Copy the image from the toolbar into the memory DC
// and draw it (grayed) back into the toolbar.
dc.FillSolidRect(rc.left, rc.top, rc.Width(), rc.Height(), m_clrBtnFace);
dc.SetBkColor(RGB(0, 0, 0));
dc.SetTextColor(RGB(255, 255, 255));
CBrush brShadow, brHilight;
brHilight.CreateSolidBrush(m_clrBtnHilight);
brShadow.CreateSolidBrush(m_clrBtnShadow);
CBrush * pOldBrush = dc.SelectObject(&brHilight);
dc.BitBlt(rc.left+1, rc.top+1, rc.Width(), rc.Height(), &ddc, 0, 0, 0x00E20746L);
dc.SelectObject(&brShadow);
dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &ddc, 0, 0, 0x00E20746L);
// reset DCs
dc.SelectObject(pOldBrush);
ddc.SelectObject(pOldBmp);
ddc.DeleteDC();
bmp.DeleteObject();
}
void CToolBarEx :: DrawSeparator( CDC & dc, CRect & rc ) const {
BOOL bHorz = ((m_dwStyle & CBRS_ORIENT_HORZ) != 0) ? TRUE : FALSE;
// make sure, this separator is not a placeholder for
// another control.
if( rc.Width() <= 8 ) {
if( bHorz ) {
// draw the separator bar in the middle
int x = (rc.left + rc.right) / 2;
rc.left = x-1; rc.right = x+1;
dc.Draw3dRect(rc, m_clrBtnShadow, m_clrBtnHilight);
}
else {
// draw the separator bar in the middle
rc.left = rc.left - m_sizeButton.cx;
rc.right = rc.left + m_sizeButton.cx;
rc.top = rc.bottom+1;
rc.bottom = rc.top+3;
int y = (rc.top+rc.bottom)/2;
- 22 ---
hebei 第 23 页 105204873.doc
rc.top = y-1; rc.bottom = y+1;
dc.Draw3dRect( rc, m_clrBtnShadow, m_clrBtnHilight);
}
}
}
void CToolBarEx :: DrawGripper( CDC & dc ) const {
if( m_dwStyle & CBRS_FLOATING )
return; // no gripper if floating
CRect gripper;
GetWindowRect(gripper);
ScreenToClient(gripper);
gripper.OffsetRect(-gripper.left, -gripper.top);
if( m_dwStyle & CBRS_ORIENT_HORZ ) {
// gripper at left
gripper.DeflateRect(4, 4);
gripper.right = gripper.left+3;
dc.Draw3dRect(
gripper,
m_clrBtnHilight,
m_clrBtnShadow
);
gripper.OffsetRect(3, 0);
dc.Draw3dRect(
gripper,
m_clrBtnHilight,
m_clrBtnShadow
);
} else {
// gripper at top
gripper.DeflateRect(4, 4);
gripper.bottom = gripper.top+3;
dc.Draw3dRect(
gripper,
m_clrBtnHilight,
m_clrBtnShadow
);
gripper.OffsetRect(0, 3);
dc.Draw3dRect(
gripper,
m_clrBtnHilight,
m_clrBtnShadow
);
}
}
void CToolBarEx :: OnUpdateCmdUI( CFrameWnd* pTarget, BOOL bDisableIfNoHndler ) {
if( m_bFlatLook ) {
// save current styles
register const int nBtn = GetToolBarCtrl().GetButtonCount();
register int nIdx;
for( nIdx = 0; nIdx < nBtn; ++nIdx )
m_Styles.SetAtGrow(nIdx, GetButtonStyle(nIdx));
// do base class processing
CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
- 23 ---
hebei 第 24 页 105204873.doc
//check wether styles have been changed
for( nIdx = 0; nIdx < nBtn; ++nIdx ) {
if( m_Styles[nIdx] != GetButtonStyle(nIdx) ) {
// invalidate that button
CRect rc;
GetItemRect(nIdx, rc);
InvalidateRect(rc);
}
}
} else
// simply delegate
CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
}
void CToolBarEx::OnSysColorChange()
{
CToolBar::OnSysColorChange();
m_clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
m_clrBtnHilight = ::GetSysColor(COLOR_BTNHILIGHT);
m_clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
}
void CToolBarEx::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR lpncsp)
{
CToolBar::OnNcCalcSize(bCalcValidRects, lpncsp);
// adjust non-client area for gripper at left or top
if( m_dwStyle & CBRS_ORIENT_HORZ ) {
lpncsp->rgrc[0].left += 4;
lpncsp->rgrc[0].right += 4;
} else {
lpncsp->rgrc[0].top += 6;
lpncsp->rgrc[0].bottom += 6;
}
}
void CToolBarEx::OnMouseMove(UINT nFlags, CPoint point)
{
if( m_bFlatLook ) {
register const int nBtn = GetToolBarCtrl().GetButtonCount();
const int nLastBtn = m_nLastBtn;
m_nLastBtn = -1;
for( register int i = 0 ; i < nBtn ; ++i ) {
CRect rc;
GetItemRect(i, rc);
const BOOL bBtnEnabled = GetToolBarCtrl().IsButtonEnabled(int(GetItemID(i)));
const BOOL bSep = GetButtonStyle(i) & TBBS_SEPARATOR;
if( bSep || ! bBtnEnabled )
continue;
const BOOL bHasCursor = rc.PtInRect(point);
if( bHasCursor && bBtnEnabled ) {
if( nLastBtn != i ) {
// force a repaint of the button with the cursor on it
InvalidateRect(rc, FALSE);
}
m_nLastBtn = i;
} else if( !bHasCursor && i == nLastBtn ) {
// force a repaint of the last formed button
- 24 ---
hebei 第 25 页 105204873.doc
InvalidateRect(rc, FALSE);
}
}
// One problem occures with WM_MOUSEMOVE: we cannot detect
// that the mouse leaves the window. If the mouse moves quick
// enough, then the last formed button stays visible. To
// resolve this problem, we set a timer and check, wether
// the mouse is outside the window ...
KillTimer(m_uTimerEvent);
m_uTimerEvent = SetTimer(1, 250, 0);
}
CToolBar::OnMouseMove(nFlags, point);
}
void CToolBarEx::OnNcPaint()
{
if( m_bFlatLook ) {
CToolBar::EraseNonClient();
CWindowDC dc(this);
DrawGripper(dc);
} else
CToolBar::OnNcPaint();
}
void CToolBarEx::OnTimer(UINT nIDEvent)
{
if( nIDEvent == m_uTimerEvent && m_nLastBtn >= 0 ) {
POINT pt;
::GetCursorPos(&pt);
CRect rc;
GetWindowRect(rc);
if( ! rc.PtInRect(pt) ) {
GetItemRect(m_nLastBtn, rc);
InvalidateRect(rc, FALSE);
m_nLastBtn = -1;
KillTimer(nIDEvent);
}
} else
CToolBar::OnTimer(nIDEvent);
}
int CToolBarEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CToolBar::OnCreate(lpCreateStruct) == -1)
return -1;
// Save the parent at creation time. It may change, if
// the toolbar is floating; but we want to know of the
// "real" parent (for notification messages)!
m_hwndParent = lpCreateStruct->hwndParent;
return 0;
}
#define PADWIDTH(x) (((x)*8+31)&~31)/8
HIMAGELIST CToolBarEx :: GetImageList() {
m_bDeleteImgList = FALSE;
HIMAGELIST hImg = HIMAGELIST(SendMessage(TB_GETIMAGELIST));
#ifdef _DEBUG
- 25 ---
hebei 第 26 页 105204873.doc
if( hImg == 0 ) {
TRACE0("CToolBarEx::OnPaint(): could not get image list\n");
}
#endif
if( ! hImg ) {
// comctl32.dll version prior to 4.70 doesn't know
// anything of the TB_GETIMAGELIST message
if( m_hbmImageWell != 0 ) {
// Yup - we have a valid image.
// But beware: Do not use this bitmap directly.
// We make the copy by ourself. CopyImage() (for
// instace) produces inacceptable copies under
// some circumstances ...
CImageList imglist;
CBitmap bmp;
// retrieve the size of the bitmap
BITMAP bmHdr;
::GetObject(m_hbmImageWell, sizeof(BITMAP), &bmHdr);
DWORD dwWidth, dwHeight = bmHdr.bmHeight;
if (bmHdr.bmBitsPixel > 8)
dwWidth = PADWIDTH(bmHdr.bmWidth * 3);
else
dwWidth = PADWIDTH(bmHdr.bmWidth);
// copy the bitmap
CClientDC cdc(this);
CDC dc1, dc2;
dc1.CreateCompatibleDC(&cdc);
dc2.CreateCompatibleDC(&cdc);
bmp.CreateCompatibleBitmap(&cdc, dwWidth, dwHeight);
CBitmap * pOBmp = dc1.SelectObject(&bmp);
HGDIOBJ hOObj = ::SelectObject(dc2.GetSafeHdc(), m_hbmImageWell)
dc1.BitBlt(0,0,dwWidth,dwHeight,&dc2,0,0,SRCCOPY);
::SelectObject(dc2.GetSafeHdc(), hOObj);
dc1.SelectObject(pOBmp);
dc1.DeleteDC();
dc2.DeleteDC();
imglist.Create(m_sizeImage.cx, m_sizeImage.cy,TRUE,dwWidth/m_sizeImage.cx,1);
imglist.SetBkColor(m_clrBtnFace);
imglist.Add(&bmp,m_clrBtnFace);
hImg = imglist.Detach();
bmp.DeleteObject();
m_bDeleteImgList = TRUE;
}
}
return hImg;
}
在MFC应用程序中使用 CToolBarEx,你必须完成下面的步骤(假定你使用的是
AppWizard/ClassWizard):
1. 在 StdAfx.h 或 MainFrm.h 中包含 #include "ToolBarEx.h"
2. 把 CMainFrame::m_wndToolBar 的类型 从 CToolBar 变成 CToolBarEx类
CToolBarEx 提供了下面的共用方法 ( 另外还有它的 ancestor 类 ):
// Set the mode of the toolbar. The mode changes immediately
// on the screen.
void SetFlatLook( BOOL bFlat = TRUE );
// determine wether the current mode is "flat"
BOOL IsFlatLook() const;
- 26 ---
hebei 第 27 页 105204873.doc
// This function I've personally missed in CToolBar
// for more than one time ...
void GetSizes( CSize & sizeButton, CSize & sizeImage ) const;
// Get the window to which the toolbar initially was docked. This
// is not necessarily the window returned by CWnd::GetParent() or
// CControlBar::GetDockingFrame(). Both these functions don't
// return the expected window, if the toolbar is floating ...
CWnd * GetParentFrame() const;
该代码更新和增强了:文本按钮可以工作了。gripper改进后更象Office97的了。被禁止的图
像更具有浮雕的效果。分隔线只有在没有设置WRAP时才绘制。
如何获取应用程序的 实例句柄?
应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用
AfxGetInstancdHandle获得句柄.
Example: HANDLE hInstance=AfxGetInstanceHandle();
如何通过代码获得应用程序主窗口的 指针?
主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化.
如何在程序中获得其他程序的 图标?
两种方法:
(1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,
(2) SDK函数 SHGetFileInfo获得有关文件的 很多信息,如大小图标,属性, 类型等.
Example(1): 在程序窗口左上角显示 NotePad图标.
void CSampleView: OnDraw(CDC * pDC)
{
if( :: SHGetFileInfo(_T("c:\\pwin95\\notepad.exe"),0,
&stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
{
pDC ->DrawIcon(10,10,stFileInfo.hIcon);
}
}
Example(2):同样功能,Use ExtractIcon Function
void CSampleView:: OnDraw(CDC *pDC)
- 27 ---
hebei 第 28 页 105204873.doc
{
HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T
("NotePad.exe"),0);
if (hIcon &&hIcon!=(HICON)-1)
pDC->DrawIcon(10,10,hIcon);
}
说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory 函数得到, 如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程序,考虑应该全面点.
如何编程结束应用程序?如何编程控制windows的重新引导?
这是个很简单又是编程中经常要遇到的问题.
第一问,向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据.
Example: AfxGetMainWindow()->SendMessage(WM_CLOSE);
还可以创建一个自定义的函数 Terminate Window
void Terminate Window(LPCSTR pCaption)
{
CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption);
if (pWnd)
pWnd ->SendMessage(WM_CLOSE);
}
说明: FindWindow函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时 FindWindow就无能为力了,可以通过枚举 windows任务列表的办法来实现。 在机械出版社"Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。
第二问,Use ExitWindowsEx Function函数控制系统是重新引导,还是重启 windows. 前面已经有人讲过乐,就不再提了。
怎样加栽其他的应用程序?
我记得这好象是出场频度很高的问题。三个SDK函数 winexec, shellexecute,createprocess可以使用。 WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数值得说一下,比如泥用 SW_SHOWMAXMIZED方式去加栽一个无最大化按钮的程序,呵呵 就是Neterm,calc等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。ShellExecute较 WinExex灵活一点,可以指定工作目录,下面的 Example就是直接打开 c:\temp\1.txt,而不用加栽与 txt文件关联的应用程序,很多安装程序完成后都会打开一个窗口,来显示Readme or Faq,偶猜就是这么作的啦.
ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED);
CreateProcess最复杂,一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等.来看个很简单的 Example:
STARTUPINFO stinfo; //启动窗口的信息
- 28 ---
hebei 第 29 页 105204873.doc
PROCESSINFO procinfo; //进程的信息
CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_
CLASS,NULL,NULL, &stinfo,&procinfo);
确定应用程序的 路径
前些天好象有人问过这个问题. Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。
Example:
TCHAR exeFullPath[MAX_PATH]; // MAX_PATH在API中定义了吧,好象是128
GetModuleFileName(NULL,exeFullPath,MAX_PATH)
获得各种目录信息
Windows目录: Use "GetWindowsDirectory“
Windows下的system目录: Use "GetSystemDirectory"
temp目录: Use "GetTempPath "
当前目录: Use "GetCurrentDirectory"
请注意前两个函数的第一个参数为 目录变量名,后一个为缓冲区; 后两个相反.
如何自定义消息
也有人问过的,其实不难。
(1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100),
MS 推荐的至少是 WM_USER+100;
(2)写消息处理函数,用 WPARAM,LPARAM返回LRESULT.
LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
//加入你的处理函数
}
(3) 在类的 AFX_MSG处进行声明,也就是常说的"宏映射"
如何改变窗口的图标?
- 29 ---
hebei 第 30 页 105204873.doc
向窗口发送 WM_SECTION消息。
Example:
HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON);
ASSERT(hIcon);
AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon);
如何改变窗口的缺省风格?
重栽 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他创建信
息.
Example: Delete "Max" Button and Set Original Window's Position and Size
BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs)
{
cs.style &=~WS_MAXINIZEMOX;
cs.x=cs.y=0;
cs.cx=GetSystemMetrics(SM_CXSCREEN/2);
cs.cy=GetSystemMetrics(SM_CYSCREEN/2);
return CMDIFramewnd ::PreCreateWindow(cs);
}
如何将窗口居中显示?
Easy, Call Function CWnd:: Center Windows
Example(1): Center Window( ); //Relative to it's parent
// Relative to Screen
Example(2): Center Window(CWnd:: GetDesktopWindow( ));
//Relative to Application's MainWindow
AfxGetMainWnd( ) -> Center Window( );
如何让窗口和 MDI窗口一启动就最大化和最
小化?
先说窗口。
在 InitStance 函数中设定 m_nCmdShow的 取值.
m_nCmdShow=SW_SHOWMAXMIZED ; //最大化
- 30 ---
hebei 第 31 页 105204873.doc
m_nCmdShow=SW_SHOWMINMIZED ; //最小化
m_nCmdShow=SW_SHOWNORMAL ; //正常方式
MDI窗口:
如果是创建新的应用程序,可以用 MFC AppWizard 的Advanced 按钮并在MDI子窗口风格组中检测最大化或最小化; 还可以重载 MDI Window 的PreCreateWindow函数,设置WS_MAXMIZE or WS_MINMIZE;如果从 CMDIChildWnd 派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MDI Child Window的风格。
如何使程序保持极小状态?
很有意思的问题
这么办: 在恢复程序窗体大小时, Windows会发送WM_QUERY-OPEN消息,用 ClassWizard设置成员函数 OnQueryOpen() ,add following code:
Bool CMainFrame:: OnQueryOpen( )
{
Return false;
}
如何限制窗口的 大小?
也就是 FixedDialog形式。 Windows 发送 WM_GETMAXMININFO消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码.
如何使窗口不可见,
很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow 控制.
如何使窗口始终在最前方?
两种途径.
BringWindowToTop(Handle); SetWindowPos函数,指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的风格.
Example:
void ToggleTopMost( CWnd *pWnd)
{
ASSERT_VALID(pWnd);
pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?
&wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE);
- 31 ---
hebei 第 32 页 105204873.doc
}
如何创建一个字回绕的CEditView
重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象的ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示设置cs. style,调用基类函数后要修改cs . style。
BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs)
{
//First call basse class function .
BOOL bResutl =CEditView : : PreCreateWindow (cs) ;
// Now specify the new window style .
cs.style &= ~ (ES_AUTOHSCROLL ,WS_HSCROLL);
return bResult ;
}
通用控件的显示窗口
MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表控件,CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。
移动窗口
调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关(顶层窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口的大小。
//Move window to positoin 100 , 100 of its parent window .
SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE ,SWP_NOAORDER);
重置窗口的大小
调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。
- 32 ---
hebei 第 33 页 105204873.doc
// Get the size of the window .
Crect reWindow ;
GetWindowRect (reWindow );
//Make the window twice as wide and twice as tall .
SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,
reWindow . Height () * 2,
SWP_NOMOVE ,SWP_NOZORDER
如何单击除了窗口标题栏以外的区域使窗口移
动
当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息,可以处理该信息使
Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用ClassWizard处理
该信息并调用基类函数, 如果函数返回HTCLIENT 则表明鼠标在客房区域,返回HTCAPTION表
明鼠标在Windows的标题栏中。
UINT CSampleDialog : : OnNcHitTest (Cpoint point ) {
UINT nHitTest =Cdialog: : OnNcHitTest (point );
return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest ; }
上述技术有两点不利之处, 其一是在窗口的客户区域双击时, 窗口将极大;其二, 它不适
合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键使主框窗口认为鼠标在其窗口标
题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个
WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。
void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point ) {
CView : : OnLButtonDow (nFlags , pont );
//Fool frame window into thinking somene clicked on
its caption bar .
GetParentFrame ( ) —> PostMessage (
WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) );
}
该技术也适用于对话框和基于对的应用程序,只是不必调用CWnd : : GetParentFrame 。
void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point ) {
Cdialog : : OnLButtonDow (nFlags, goint );
//Fool dialog into thinking simeone clicked on its caption bar .
PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) )
}
如何改变视窗的背景颜色
Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。//Paint
- 33 ---
hebei 第 34 页 105204873.doc
area that needs to be erased.
BOOL CSampleView : : OnEraseBkgnd (CDC* pDC) {
// Create a pruple brush.
CBrush Brush (RGB (128 , 0 , 128) );
// Select the brush into the device context . CBrush* pOldBrush = pDC—>SelcetObject (&brush);
// Get the area that needs to be erased . CRect reClip ;
pDC—>GetCilpBox (&rcClip);
//Paint the area.
pDC—> PatBlt (rcClip.left , rcClip.top ,
rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY ); //Unselect brush out of device context . pDC—>SelectObject (pOldBrush );
// Return nonzero to half fruther processing . return TRUE;
}
如何改变窗口标题
调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。
//Set title for application's main frame window . AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") ); //Set title for View's MDI child frame window . GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") );
//Set title for dialog's push button control. GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") );
如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数
AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在联机帮助中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。
AfxSetWindowText的实现如下:
voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )
{
itn nNewLen= Istrlen (Ipaznew);
TCHAR szOld [256];
//fast check to see if text really changes (reduces flash in the controls )
if (nNewLen >_contof (szOld) ,,
: : GetWindowText (hWndCrtl , szOld , _countof (szOld) !=nNewLen ,,
Istrcmp (szOld , IpszNew )! = 0 {
//change it
: : SetWindowText (hWndCtrl , IpszNew );
}
}
- 34 ---
hebei 第 35 页 105204873.doc
如何防止主框窗口在其说明中显示活动的文档名
创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位, 如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。
BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs)
{
//Turn off FWS_ADDTOTITLE in main frame .
cs.styel & = ~FWS_ADDTOTITLE ;
return CMDIFrameWnd : : PreCreateWindow (cs ); }
关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。
如何获取有关窗口正在处理的当前消息的信息
调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用 ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。 viod CMainFrame : : OnCommmonMenuHandler ( ) {
//Display selected menu item in debug window .
TRACE ("Menu item %u was selected . \n" , GetCruuentMessage ( ) —> wParam ); }
如何创建一个不规则形状的窗口
可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域,实际上使窗口成为指定的不规则形状。使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。 给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。
Class CRoundDlg : public CDialog
{
…
private :
Crgn m_rgn : // window region
…
} ;
修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口: BOOL CRoundDlg : : OnInitDialog ( )
- 35 ---
hebei 第 36 页 105204873.doc
{
CDialog : : OnInitDialog ( ) ;
//Get size of dialog .
CRect rcDialog ;
GetClientRect (rcDialog );
// Create region and assign to window .
m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width ( ) , rcDialog .Height (
) );
SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn , TRUE );
return TRUE ;
}
通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例
子程序是修改OnPaint函数使窗口形状看起来象一个球形体。
voik CRoundDlg : : OnPaint ( )
{
CPaintDC de (this) ; // device context for painting .
//draw ellipse with out any border
dc. SelecStockObject (NULL_PEN);
//get the RGB colour components of the sphere color
COLORREF color= RGB( 0 , 0 , 255);
BYTE byRed =GetRValue (color);
BYTE byGreen = GetGValue (color);
BYTE byBlue = GetBValue (color);
// get the size of the view window
Crect rect ;
GetClientRect (rect);
// get minimun number of units
int nUnits =min (rect.right , rect.bottom );
//calculate he horiaontal and vertical step size
float fltStepHorz = (float) rect.right /nUnits ;
float fltStepVert = (float) rect.bottom /nUnits ;
int nEllipse = nUnits/3; // calculate how many to draw
int nIndex ; // current ellipse that is being draw
CBrush brush ; // bursh used for ellipse fill color
CBrush *pBrushOld; // previous brush that was selected into dc
//draw ellipse , gradually moving towards upper-right corner
for (nIndex = 0 ; nIndes < + nEllipse ; nIndes ++) {
//creat solid brush
brush . CreatSolidBrush (RGB ( ( (nIndex *byRed ) /nEllipse ).
( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllips ) ) );
//select brush into dc
pBrushOld= dc .SelectObject (&brhsh);
//draw ellipse
dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,
rect. right -( (int) fltStepHorz * nIndex )+ 1,
rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) ;
//delete the brush
brush.DelecteObject ( );
}
}
最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。
UINT CRoundDlg : : OnNchitTest (Cpoint point )
{
//Let user move window by clickign anywhere on the window .
- 36 ---
hebei 第 37 页 105204873.doc
UINT nHitTest = CDialog : : OnNcHitTest (point) ;
rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ;
}
如何在代码中获取工具条和状态条的指针
缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个
AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何
通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针:
//Get pointer to status bar .
CStatusBar * pStatusBar =
(CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow
(AFX_IDW_STUTUS_BAR);
//Get pointer to toolbar .
CToolBar * pToolBar =
(CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow (AFX_IDW_TOOLBAR);
如何使能和禁止工具条的工具提示
如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,需
要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数:
void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) {
ASSERT_VALID (m_wndToolBar);
DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) ;
if (bDisplayTips)
dwStyle ,=CBRS_TOOLTIPS ;
else
dwStyle & = ~ CBRS_TOOLTIPS ;
m_wndToolBar.SetBarStyle (dwStyle );
}
如何设置工具条标题
工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下:
int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct ) {
…
// Set the caption of the toolbar .
m_wndToolBar.SetWindowText (_T "Standdard");
- 37 ---
hebei 第 38 页 105204873.doc
如何创建和使用无模式对话框
MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几个额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的:模式对话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。
void CSampleDialog : : OnOK ( )
{
// Retrieve and validate dialog data .
if (! UpdateData (TRUE) )
{
// the UpdateData rountine will set focus to correct item
TRACEO (" UpdateData failed during dialog termination .\n") ;
return ;
}
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( ) ;
}
void CSampleDialog : : OnCancel ( ) {
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( ) ;
}
其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回,因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重置该函数并执行清除操作,诸如删除this指针。
void CSampleDialog : : PostNcDestroy ( )
{
// Declete the C++ object that represents this dialog .
delete this ;
}
}
最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放,要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序是如何创建无模式对话的: void CMainFrame : : OnSampleDialog ( ) {
//Allocate a modeless dialog object .
CSampleDilog * pDialog =new CSampleDialog ;
ASSERT_VALID (pDialog) ;
//Create the modeless dialog .
BOOL bResult = pDialog —> Creste (IDD_IDALOG) ;
ASSERT (bResult ) ;
}
- 38 ---
hebei 第 39 页 105204873.doc
如何在对话框中显示一个位图
这要归功于Win 32先进的静态控件和Microsoft的资源编辑器, 在对话框中显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。
如何改变对话或窗体视窗的背景颜色
调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。BOOL CSampleApp : : InitInstance ( )
{
//use blue dialog with yellow text . }
如何一个创建三态下压按钮
可以使用新的BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性Push—like即可。不用任何附加程序就可以成为三态下压按钮。
如何动态创建控件
分配一个控件对象的实例并调用其Create成员函数。开发者最容易忽略两件事:忘记指定WS_VISBLE标签和在栈中分配控件对象。下例动态地创建一个下压按钮控件: //In class declaration (.H file ). private :
CButton* m _pButton ;
//In class implementation (.cpp file ) . m_pButton =new CButton ;
ASSERT_VALID (m_pButton);
m_pButton —>Create (_T ("Button Title ") , WS_CHILD ,WS_VISIBLE ,
BS_PUSHBUTTON.
Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )
- 39 ---
hebei 第 40 页 105204873.doc
如何限制编辑框中的准许字符
如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志
ES_NUMBERS,它是Windows 95新增加的标志,该标志限制 编辑控件只按收数字字符。如果用户
需要复杂的编辑控件,可以使用Microsoft 的屏蔽编辑控件,它是一个很有用的OLE定制控件。 如果希望不使用OLE 定制控件自己处理字符,可以派生一个CEdit 类并处理WM_CHAR消息,然
后从编辑控件中过滤出特定的字符。首先,使用ClassWizard 建立一个 CEdit的派生类,其次,在
对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem . //In your dialog class declaration (.H file ) private :
CMyEdit m_wndEdit ; // Instance of your new edit control . //In you dialog class implementation (.CPP file ) BOOL CSampleDialog : : OnInitDialog ( )
{
…
//Subclass the edit lontrod .
m_wndEdit .SubclassDlgItem (IDC_EDIT,this );
…
}
使用ClassWizard处理WM_CHAR消息,计算nChar参量并决定所执行的操作,用户可以确定
是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母字符,则调用CWnd ; OnChar,否则不调用OnChar.
//Only display alphabetic dharacters .
void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags )
{
//Determine if nChar is an alphabetic character .
if (: : IsCharAlpha ( ( TCHAR) nChar ) )
CEdit : : OnChar (nChar, nRepCnt , nFlags ); }
如果要修改字符,则不能仅仅简单地用修改过的nChar调用CEdit : : OnChar,然后CEdit: : OnChar调用CWnd: : Default获取原来的wParam 和lParam 的值 ,这样是不行的。要修改一个字
符,需要首先修改nChar,然后用修改过的nChar调用
CWnd: : DefWindowProc。下例说明了如何将字符转变为大写:
//Make all characters uppercase
void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags )
{
//Make sure character is uppercase .
if (: : IsCharAlpha ( .( TCHAR) nChar)
nChar=: : CharUpper (nChar ) ;
//Bypass default OnChar processing and directly call
//default window proc.
DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ;
}
- 40 ---
hebei 第 41 页 105204873.doc
如何改变控件的颜色
有两种方法。其一,可以在父类中指定控件的颜色,或者利用MFC4.0新的消息反射在控件类中指定颜色。当控件需要重新着色时,工作框调用父窗口(通常是对话框)的CWnd: : OnCrtlColor,可以在父窗口类中重置该函数并指定控件的新的绘画属性。例如,下述代码将对话中的所有编辑控件文本颜色改为红色:
HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor)
{
HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor );
//Draw red text for all edit controls .
if (nCtlColor= = CTLCOLOR_EDIT )
pDC —> SetTextColor (RGB (255 , 0 , 0 , ) ) ;
return hbr ;
}
然而,由于每个父窗口必须处理通知消息并指定每个控件的绘画属性,所以,这种方法不
是完全的面向对象的方法。控件处理该消息并指定绘画属性更合情合理。消息反射允许用户这
样做。通知消息首先发送给父窗口,如果父窗口没有处理则发送给控件。创建一个定制彩色列
表框控件必须遵循下述步骤。
首先,使用ClassWizard 创建一个CListBox 的派生类并为该类添加下述数据成员。 class CMyListBox ; publilc CListBox
{
„
private;
COLORREF m_clrFor ; // foreground color
COLORREF m_clrBack ; //background color
Cbrush m_brush ; //background brush
„
} ;
其次,在类的构造函数中,初始化数据中。
CMyListBox : : CMyListBox ()
{
//Initialize data members .
m_clrFore =RGB (255 , 255 , 0) ; // yellow text
m_clrBack=RGB (0 , 0 , 255) ; // blue background
m_brush . CreateSolidBrush (m _clrBack ); }
最后,使用ClassWizard处理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新的绘画属性。
HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor )
{
pDC—>SetTextColor (m_clrFore);
pDC—>SetBkColor (m_clrBack);
return (HBRUSH) m_brush.GetSafeHandle () }
现在,控件可以自己决定如何绘画,与父窗口无关。
- 41 ---
hebei 第 42 页 105204873.doc 当向列表框中添加多个项时如何防止闪烁
调用CWnd::SetRedraw 清除重画标志可以禁止CListBox(或者窗口)重画。当向列表框添加几个项时,用户可以清除重画标志,然后添加项,最后恢复重画标志。为确保重画列表框的新项,调用SetRedraw (TRUE) 之后调用CWnd::Invalidate。
//Disable redrawing.
pListBox->SetRedraw (FALSE);
//Fill in the list box gere
//Enable drwing and make sure list box is redrawn.
pListBox->SetRedraw (TRUE);
pListBox->Invalidate ();
如何向编辑控件中添加文本
由于没有CEdit:: AppendText函数,用户只好自己做此项工作。调用CEdit:: SetSel移动到编辑控件末尾,然后调用CEdit:: ReplaceSel添加文本。下例是AppendText 的一种实现方法: void CMyEdit:: AppendText (LPCSTR pText) {
int nLen=GetWindowTextLength ();
SetFocus ();
SetSel (nLen, nLen);
ReplaceSel (pText);
}
如何访问预定义的GDI对象
可以通过调用CDC:: SlectStockObject使用Windows的几个预定义的对象,诸如刷子、笔以及字体。下例使用了Windows预定义的笔和刷子GDI对象在视窗中画一个椭圆。 //Draw ellipse using stock black pen and gray brush.
void CSampleView:: OnDraw (CDC* pDC) {
//Determine size of view.
CRect rcView;
GetClientRect (rcView);
//Use stock black pen and stock gray brush to draw ellipse.
pDC->SelectStockObject (BLACK_PEN);
pDC->SelectStockObject (GRAY_BRUSH)
//Draw the ellipse.
pDC->Ellipse (reView);
}
也可以调用新的SDK函数GetSysColorBrush获取一个系统颜色刷子,下例用背景色在视窗中画一个椭圆:
void CsampleView:: OnDraw (CDC* pDC)
- 42 ---
hebei 第 43 页 105204873.doc
{
//Determine size of view.
CRect rcView;
GetClientRect (rcView);
//Use background color for tooltips brush.
CBrush * pOrgBrush=pDC->SelectObject (
CBrush::FromHandle (::GetSysColorBrush (COLOR_INFOBK)));
//Draw the ellipse.
pDC->Ellipse (rcView);
//Restore original brush.
pDC->SelectObject (pOrgBrush);
}
如何获取GDI对象的属性信息
可以调用GDIObject:: GetObject。这个函数将指定图表设备的消息写入到缓冲区。下例创建了几个有用的辅助函数。
//Determine if font is bold.
BOOL IsFontBold (const CFont&trusfont) {
LOGFONT stFont;
font.GetObject (sizeof (LOGFONT), &stFont);
return (stFont.lfBold)? TRUE: FALSE; }
//Return the size of a bitmap.
CSize GetBitmapSize (const CBitmap&tsfobitmap) {
BITMAP stBitmap;
bitmap.GetObject (sizeof (BITMAP), &stBitmap);
return CSize (stBitmap.bmWidth, stBitmap. bmHeight);
}
//Create a pen with the same color as a brush. BOOL CreatePenFromBrush (Cpen&romBpen, cost Cbrush&mBpebrush)
{
LOGBRUSH stBrush;
brush.Getobject (sizeof (LOGBRUSH), &stBrush);
return pen. Createpen (PS_SOLID, 0, stBrush.ibColor);
}
如何实现一个橡皮区矩形
CRectTracker是一个很有用的类,可以通过调用CRectTracker:: TrackRubberBand 响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。
首先,在文件档中声明一个CRectTracker数据成员:
class CSampleView : Public CView
- 43 ---
hebei 第 44 页 105204873.doc
{
…
public :
CrectTracker m_tracker;
…
};
其次,在文档类的构造函数中初始化CRectTracker 对象:
CSampleDoc:: CSampleDOC ()
{
//Initialize tracker position, size and style.
m_tracker.m_rect.SetRect (0, 0, 10, 10);
m_tracker.m_nStyle=CRectTracker:: resizeInside |
CRectTracker:: dottedLine;
}
然后,在OnDraw函数中画椭圆和踪迹矩形:
void CSampleView:: OnDraw (CDC* pDC)
{
CSampleDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//Select blue brush into device context.
CBrush brush (RGB (0, 0, 255));
CBrush* pOldBrush=pDC->SelectObject (&brush);
//draw ellipse in tracking rectangle.
Crect rcEllipse;
pDoc->m_tracker.GetTrueRect (rcEllipse);
pDC->Ellipse (rcEllipse);
//Draw tracking rectangle.
pDoc->m_tracker.Draw (pDC);
//Select blue brush out of device context.
pDC->Selectobject (pOldBrush);
}
最后,使用ClassWizard处理WM_LBUTTONDOWN消息,并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。
void CSampleView::OnLButtonDown (UINT nFlags, CPoint point)
{
//Get pointer to document.
CSampleDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//If clicked on ellipse, drag or resize it. Otherwise create a
//rubber-band rectangle nd create a new ellipse.
BOOL bResult=pDoc->m_tracker.HitTest (point)!= CRectTracker::hitNothing;
//Tracker rectangle changed so update views.
if (bResult)
{
pDoc->m_tracker.Track (this,point,TRue);
pDoc->SetModifiedFlag ();
pDoc->UpdateAllViews (NULL);
}
else
pDoc->m-tracker.TrackRubberBand (this,point,TRUE);
CView:: onLButtonDown (nFlags,point); }
- 44 ---
hebei 第 45 页 105204873.doc
如何更新翻转背景颜色的文本
调用CDC:: SetBkmode并传送OPAQUE用当前的背景颜色填充背景,或者调用CDC::SetBkMode并传送TRANSPAARENT使背景保持不变,这两种方法都可以设置背景模式。下例设置背景模式为TRANSPARENT,可以两次更新串,用花色带黑阴影更新文本。黑色串在红色串之后,但由于设置了背景模式仍然可见。
void CSampleView:: OnDraw (CDC* pDC)
{
//Determint size of view.
CRect rcView;
GetClientRect (rcVieew);
//Create sample string to display.
CString str (_T ("Awesome Shadow Text((("));
//Set the background mode to transparent.
pDC->SetBKMode (TRANSPARENT);
//Draw black shadow text.
rcView.OffsetRect (1, 1);
pDc->SetTextColor (RGB (0, 0, 0));
pDC->DrawText (str, str.GetLength (), rcView,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//Draw red text.
rcView.OffsetRect (-1,-1);
pDc->SetTextColor (RGB (255, 0, 0));
pDC->DrawText (str, str.GetLength (), rcView,
DT_SINGLELINE | DT_CENTER | DT_VCENTER); }
如何创建一个具有特定点大小的字体
可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一些。可以如下将字体的点转换为字体的高度:
int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72);下例创建了一个8点的Apial字体:
„
CClientDC dc (AqfxGetMainWnd ());
m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY),
72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
OUT_STROKE_PRECIS,CLIP_STROKE_PRECIS,DRAFT_QUALITY,
VARIABLE_PITCH | FF-SWISS,_T ("Arial"));
……
如何计算一个串的大小
- 45 ---
hebei 第 46 页 105204873.doc
函数CDC:: Det text Extent 根据当前选择的字体计算一个串的高度和宽度。如果使用的不是系统字体而是其他字体,则在调用GetTextExtent之前将字体选进设备上下文中是很重要的,否则计算高度和宽度时将依据系统字体,由此得出的结果当然是不正确的。下述样板程序当改变下压按钮的标题时动态调整按钮的大小,按钮的大小由按钮的字体和标题的大小而定。响应消息WM_SETTEXT时调用OnSetText,该消息使用ON_MESSAE宏指令定义的用户自定义消息。
LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam)
{
//Pass message to window procedure.
LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr (),
m_hWnd, GetCurrentMessage () ->message,wParam,lParam);
//Get title of push button.
CString strTitle;
GetWindowText (strTitle);
//Select current font into device context.
CDC* pDC=GetDc ();
CFont*pFont=GetFont ();
CFont*pOldFont=pDC->SelectObject (pFont);
//Calculate size of title.
CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength ());
//Adjust the button's size based on its title.
//Add a 5-pixel border around the button.
SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
//Clean up.
pDC->SelectFont (pOldFont);
ReleaseDC (pDC);
return bResult;
}
如何显示旋转文本
只要用户使用TrueType或者GDI笔或字体就可以显示旋转文本(有些硬件设备也支持旋转光栅字体)。LOGFONT结构中的ifEscapement成员指定了文本行和x轴的角度,角度的单位是十分之一度而不是度,例如,ifEscapement为450表示字体旋转45度。为确保所有的字体沿坐标系统的同一方向旋转,一定要设置ifEscapement成员的CLIP_LH_ANGLES位,否则,有些字体可能反向旋转。下例使用了14点Arial字体每间隔15度画一个串。
void CSampleView:: OnDraw (CDC* pDC)
{
//Determine the size of the window.
CRect rcClient;
GetClientRect (rcClient);
//Create sample string.
CString str (_T ("Wheeee(((I am rotating!"));
//Draw transparent, red text.
pDC->SetBkMode (TRANSPARENT);
pDC->SetTextColor (RGB (255,0,0));
CFont font; //font object
LOGFONT stFont; //font definition
//Set font attributes that will not change.
memset (&stFont, 0, sizeof (LOGFONT));
stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps (LOGPIXELSY), 72);
- 46 ---
hebei 第 47 页 105204873.doc
stFont.ifWeight=FW_NORMAL;
stFont.ifClipPrecision=LCIP_LH_ANGLES;
strcpy (stFont.lfFaceName, "Arial");
//Draw text at 15degree intervals.
for (int nAngle=0; nAngle<3600; nAngle+=150) {
//Specify new angle.
stFont.lfEscapement=nAngle;
//Create and select font into dc.
font.CreateFontIndirect (&stfont);
CFont* pOldFont=pDC->SelectObject (&font);
//Draw the text.
pDC->SelectObject (pOldFont);
font.DelectObjext ();
}
}
如何正确显示包含标签字符的串
调用GDI文本绘画函数时需要展开标签字符,这可以通过调用CDC:: TabbedTextOut或者CDC:: DrawText并指定DT_EXPANDTABS标志来完成。TabbedTextOut函数允许指定标签位的数组,下例指定每20设备单位展开一个标签:
void CSampleView:: OnDraw (CDC* pDC)
{
CTestDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoC);
CString str;
str.Format (_T ("Cathy\tNorman\tOliver"));
int nTabStop=20; //tabs are every 20 pixels
pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10); }
串太长时如何在其末尾显示一个省略号
调用CDC:: DrawText并指定DT_END_ELLIPSIS标志,这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。
void CSampleView:: OnDraw (CDC* pDC)
{
CTestDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//Add ellpsis to end of string if it does not fit
pDC->Drawtext (CString ("This is a long string"),
CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS);
//Add ellpsis to middle of string if it does not fit
pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath,
CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS);
- 47 ---
hebei 第 48 页 105204873.doc
}
如何快速地格式化一个CString对象
调用CString:: Format,该函数和printf函数具有相同的参数,下例说明了如何使用Format函数: //Get size of window.
CRect rcWindow;
GetWindowRect (rcWindow);
//Format message string.
CString strMessage;
strMessage.Format (_T ("Window Size (%d, %d)"), rcWindow.Width (), rcWindow.Height ());
//Display the message.
MessageBox (strmessage);
为什么即使调用EnableMenuItem菜单项后,菜
单项还处于禁止状态
需要将CFrameWnd:: m_bAutomenuEnable设置为FALSE,如果该数据成员为TRUE(缺省值),
工作框将自动地禁止没有ON_UPDATE_COMMAND_UI或者ON_COMMAND的菜单项。
//Disable MFC from automatically disabling menu items. m_bAuoMenuEnable=FALSE;
//Now enable the menu item.
CMenu* pMenu=GetMenu ();
ASSERT_VALID (pMenu);
pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED);
如何给系统菜单添加一个菜单项
给系统菜单添加一个菜单项需要进行下述三个步骤:首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols(((可以显示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000; 其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单项添加
到菜单中。下例给系统菜单添加两个新的菜单项:
int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct) {
…
//Make sure system menu item is in the right range.
ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM);
- 48 ---
hebei 第 49 页 105204873.doc
ASSERT (IDM-MYSYSITEM<0xF000);
//Get pointer to system menu.
CMenu* pSysmenu=GetSystemmenu (FALSE);
ASSERT_VALID (pSysMenu);
//Add a separator and our menu item to system menu.
CString StrMenuItem (_T ("New menu item"));
pSysMenu->Appendmenu (MF_SEPARATOR);
pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem);
…
}
现在,选择系统菜单项时用户应进行检测。使用ClassWizard处理WM_SYSCOMMAND消息并检测用户菜单的nID参数:
void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam) {
//Determine if our system menu item was selected.
if ( (nID & 0xFFF0)==IDM_MYSYSITEM)
{
//TODO-process system menu item
}
else
CMDIFrameWnd:: OnSysCommand (nID, lParam); }
最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。
如何确定顶层菜单所占据的菜单行数
这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。
int CMainFrame:: GetMenuRows ()
{
CRect rcFrame,rcClient;
GetWindowRect (rcFrame);
GetClientRect (rcClient);
return (rcFrame.Height () -rcClient.Height ()-
:: GetSystemMetrics (SM_CYCAPTION) -
(:: getSystemMetrics (SM_CYFRAME) *2)) /
:: GetSystemMetrics (SM_CYMENU); }
在用户环境中如何确定系统显示元素的颜色
调用SDK函数GetSysColor可以获取一个特定显示元素的颜色。下例说明了如何在MFC函数CMainFrameWnd:: OnNcPaint中调用该函数设置窗口标题颜色。
void CMiniFrameWnd:: OnNcPaint ()
{
…
- 49 ---
hebei 第 50 页 105204873.doc
dc.SetTextColor (:: GetSysColor (m_bActive ?
COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
…
}
如何查询和设置系统参数
在Windows 3.1 SDK中介绍过SDK函数SystemParametersInfo,调用该函数可以查询和设
置系统参数,诸如按键的重复速率设置、鼠标双击延迟时间、图标字体以及桌面覆盖位图等等。
//Create a font that is used for icon titles. LOGFONT stFont;
:: SystemParametersInfo (SPIF_GETICONTITLELOGFONT,
sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE); m_font.CreateFontIndirect (&stFont);
//Change the wallpaper to leaves.bmp.
:: SystemParametersInfo (SPI_SETDESKWALLPAPER, 0, _T (" forest.bmp"), SPIF_UPDATEINIFILE);
如何使用一个预定义的Windows光标
调用CWinApp:: LoadStandardCursor并传送光标标识符。
BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message)
{
//Display wait cursor if busy.
if (m_bBusy)
{
SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT));
return TRUE;
}
return CDialog:: OnSetCursor (pWnd. nHitTest,message); }
如何确定当前聊环直媛?
调用SDK函数GetSystemMetrics,该函数可以检索有关windows显示信息,诸如标题大小、边
界大小以及滚动条大小等等。
//Initialize CSize object with screen size.
CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN));
- 50 ---
hebei 第 51 页 105204873.doc
如何检索原先的Task Manager应用程序使用的任务列表
原先的Task Manager应用程序显示顶层窗口的列表。为了显示该列表,窗口必须可见、包含一个标题以及不能被其他窗口拥有。调用CWnd:: GetWindow可以检索顶层窗口的列表,调用IsWindowVisible、GetWindowTextLength以及GetOwner可以确定窗口是否应该在列表中。下例将把TaskManager窗口的标题填充到列表中。
void GetTadkList (CListBox&engtlist)
{
CString strCaption; //Caption of window.
list.ResetContent (); //Clear list box.
//Get first Window in window list.
ASSERT_VALID (AfxGetMainWnd ());
CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST);
//Walk window list.
while (pWnd)
{
// I window visible, has a caption, and does not have an owner?
if (pWnd ->IsWindowVisible () &&
pWnd ->GetWindowTextLength () &&! pWnd ->GetOwner ())
{
//Add caption o window to list box.
pWnd ->GetWindowText (strCaption);
list.AddString (strCaption);
}
//Get next window in window list.
pWnd=pWnd->GetWindow (GW_HWNDNEXT);
}
}
如何确定Windows和Windows系统目录
有两个SDK函数可以完成该功能。GetWindowsDirectory和GetSystemDirectory,下例说明了如何使用这两个函数:
TCHAR szDir [MAX_PATH];
//Get the full path of the windows directory. :: GetWindowsDirectory (szDir, MAX_PATH); TRACE ("Windows directory %s\n", szDir); //Get the full path of the windows system directory. :: GetSystemDirectory (szDir, MAX_PATH); TRACE ("Windows system directory %s\n", szDir);
- 51 ---
hebei 第 52 页 105204873.doc
在哪儿创建临文件
调用SDK函数GetTemPath可以确定临时文件的目录,该函数首先为临时路径检测TMP环境变量:如果没有指定TMP,检测TMP环境变量,然后返回到当前目录。下例说明了如何创建一个临时文件。
„
//get unique temporary file.
CString strFile;
GetUniqueTempName (strFile);
TRY
{
//Create file and write data.Note that file is closed
//in the destructor of the CFile object.
CFile file (strFile,CFile:: modeCreate | CFile:: modeWrite);
//write data
}
CATCH (CFileException, e)
{
//error opening file
}
END_CATCH
„
Void GetuniqueTempName (CString&Name strTempName) {
//Get the temporary files directory.
TCHAR szTempPath [MAX_PATH];
DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath);
ASSERT (dwResult);
//Create a unique temporary file.
TCHAR szTempFile [MAX_PATH];
UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile);
ASSERT (nResult);
strTempName=szTempFile;
}
如何访问桌面窗口
静态函数CWnd:: GetDesktopWindow 返回桌面窗口的指针。下例说明了MFC函数CFrameWnd::BeginModalStae是如何使用该函数进入内部窗口列表的。
void CFrameWnd::BeginModalState ()
{
…
//first count all windows that need to be disabled
UINT nCount=0;
HWND hWnd=:: GetWindow (:: GetDesktopWindow (), GW_CHILD);
while (hWnd!=NULL)
{
- 52 ---
hebei 第 53 页 105204873.doc
if (:: IsWindowEnabled (hwnd) &&
CWnd::FromHandlePermanent (hWnd)!=NULL &&
AfxIsDescendant (pParent->m_hWnd, hWnd) &&
:: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0)
{
++nCount;
}
hWnd=:: GetWindow (hWnd, GW_HWNDNEXT);
}
… }
为应用程序的主窗口设置图标
向窗口发送WM_SETICON消息,可改变窗口的图标,下面的例子为应用程序的主窗口设置图标。
//Load icon resource.
HICON hIcon = AfxGetApp ( )—>LoadIcon (IDI_ICON);
ASSERT (hIcon);
//Specify new iconfor window .
AfxGetMainWnd ( ) —> SendMessage (WM_SETICON, TRUE , (LPARAM) hIcon);
如何增加一个用户自定义消息
由于Windows是事件驱动的环境,用户常常需要增加一些自定义消息。Class Winzard不允许增加用户自定义消息,所以必须手工输入。但是输入以后可以使用Class Wizard象游览任何其他消息一样游览用户自定义的信息。下面的步骤说明 了如何增加一个用户自定义消息:
自选,定义消息。当开发Windows 95应用程序进,Microsoft推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
#define WM_MY _MESSAGE (WM_USER+100)
第二, 实现消息处理函数。 该函数使用WPARAM 和LPARAM参数并返回LRESULT 。 LRESULT CMainFrame : : OnMyMessage (WPARAM wParam , LPARAM Iparam )
{
/TODO: handle user defined message
return 0;
}
第三,在类头文件的AFX_MSG块中说明 消息处理函数:
class CMainFrame: public DMDIFrameWnd {
…
//Generated message map functions
protected :
// { { AFX_MSG (CMainFrame)
afx_msg int OnCreate (LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer (UINT nIDEvent );
afx_msg LRESULT OnMyMessage (WPARAM wParam , LPARAM Iparam);
/// } } AFX_MSG
- 53 ---
hebei 第 54 页 105204873.doc
DECLARE_MESSAGE_MAP ( )
}
最后, 在用户类的消息映射块中,使用ON_MESSAGE 指令将消息映射到消息处理函数中。BEGIN_MESSAGE_MAP (CMainFrame, CMDIFrameWnd)
// { { AFX_MSG_MAP (CMainFrame )
ON_WM_CREATE ( )
ON_WM_TIMER ( )
ON_MESSAGE (WM_MY_MESSAGE , OnMyMessage)
// } }AFX_MSG_MAP
END_MESSAGE_MAP ( )
如果用户需要一个整个系统唯一的消息,可以调整用SDK函数
RegisterWindowMessage并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE 宏指令,其余步骤同上。
获得当前工作目录的路径
调用SDK函数GetCurrentDirectory可以获得当前工作目录的路径。下面的例子在 CString对象中创建一个返回当前工作目录的函数:
CSrting GetCurrentWorkingDir ()
{ CString strDir ;
: : GetCurrentDirectory (MAX_PATH, strDir . GetBuffer (MAX_PATH ));
strDir. ReleaseBuffer ( )
return strDir ;
}
调用SDK函数GetModuleFileName可以获取应用程序的路径,然后除去可以执行文件名部分。下面的例子是一个函数,可以调用以确定所载入的应用程序目录。在初始化过程中工作框调用GetModuleFileName并在CWinApp: : m _pszhelpFilePath中主帮助文件路径。如果没有指定新的帮助文件目录,可以使用m_pszHelpFilePath而不必调用GetModuleFileName。
void GetLaunchedDir (Cstring &—> strLaunched)
{
TCHAR szFullPath [MAX_PATH];
TCHAR szDir [_MAX_DIR];
TCHAR szDrive [_MAX_DRIVE];
//Get application's full path.
: : GetModuleFileName (NULL, szFullPath , MAX_PATH); //Break full path into separate components . _splitpath (szFullPath, szDrive , szDir , NULL , NULL );
//Store application's drive and path . strLaunched . Format (_T ("%s%s"), szDrive , szDir ); }
该函数返回一个长路径名,工作框中的一些函数如AfxOleRegisterControlClass和CDocManager : : RegisterShellFileTypes使用AfxGetModuleShortFileName半文档化的函数来代替GetModuleFileName, 该函数返回一个模块的短路径名,该函数在AFXPRIV.H中说明,在FILECORE.CPP中实现。 下面就是该函数的实现:
void AFXAPI AfxGetModuleShortFileName (HINSTANGCE hInst , Cstring &strShortName )
{
TCHAR szLongPathName [_MAX_PATH ];
: :GetmoduleFileName (hInst, szLongPathName , _MAX _PATH);
: :GetShortPathName (szLongPathName,
strShortName. GetBuffer (_MAX_PATH), _MAX_PATH);
strShortName. ReleasBuffer ();
- 54 ---
hebei 第 55 页 105204873.doc
}
如何将WinExec 、ShellExecute或者CreateProcess这三个函数载入应用程序
调用SDK函数WinExec 、ShellExecute或者CreateProcess。WinExec函数使用起来最简单,它有两个参数:程序命令行和显示状态。Shell Execute函数比较灵活允许用户打开指定工作目录的文件。CreateProcess最复杂,使用它用户可以指定进程以及安全属性、继承信息、类的优先级信息。下面的例子说明了如何将这三个函数载入应用程序:
// Launch the calculator application . : : WinExec_ (_T ("calc . exe") , SW_SHOW); //Open file . txt with its associated application . launch the application
// minimized and set the working directory to c: \data . : : ShellExecute (NULL, NULL , _T("file . txt"),
NULL, _T("c: \\data") , SW_SHOWMINIMIZED) ; //Launch Media Player using CreateProcess. //Allocate and initialize startup and process structures .
STARTUPINFO infoStart ;
PROCESS_INFORMATION infoProcess ;
memset (&infoStart , 0, sizeof (infoStart)); infoStart. cb =sizeof(STARTUPINFO);
关闭窗口
最清楚的方法是向主窗口发送一个WM_CLOSE消息,这样将调用CWnd :: OnClose成员函数, 该函数允许提示用户保存修改过的数据。此外, 向窗口发送一个WM_DESTROY消息也可以关闭窗口。下面例示了如何中止应用程序并说明了一个类属的Terminate Window函数:
//Terminate our application
AfxGetMainWnd () —>PostMessage (WM_CLOSE);
//Generic function to terminate other window . void Terminate Window (LPCTSTR pCaption ) ,
//Find window with matching caption .
CWnd *pWnd =Cwnd ::FindWindow (NULL, pCaption ):
//If found window , ask it to close .
if (pWnd)
pWnd —>postMessage (WM_CLOSE);
,
- 55 ---
hebei 第 56 页 105204873.doc 显示窗口图标
图标是DLL或者应用程序的执行文件的,应用程序可以调用新的SDK函数SHGetFileInfo或者原先的ExtractIcon函数来获取图标资源的句柄,也可以使用SHGetFileInfo函数获取文件的其他信息,如大小图标,文件属性以及文件类型。下面的例子使用了这两函数在一个显示窗口的左上角显示笔记本的图标:
//Example using new SHGetFileInfo function . void CSampleView : OnDraw (CDC * pDC ) ,
//Retrieve handle to icon .
if ( :: SHGetFileInfo (_T ("c: \\windows \\notepad . exe"),
0 , &stFileInfo , sizeof (stFileInfo), SHGFI _ICON))
,
// Draw icon ;
pDC—> DrawIcon(10,10, stFileInfo . hIcon) ;
,
,
//Example using old ExtractIcon function . void CSampleView : OnDraw (CDC* pDC) ,
//Retrieve handle to icon .
HICON hIcon = :: ExtractIcon (
AfxGetInstanceHandle( ), _T ("notepad . exe"), 0);
//Draw icon .
if (hIcon && hIcon ! = (HICON) —1)
pDc —> DrawIcon (10,10, hIcon); ,
应用程序极小化
主框窗口的指针保存在CWinThread::m_pMainWnd中, 可以调用 AfxGetMainWnd来获取,下面的例子使应用程序极小化:
//Minimize application
AfxGetMainWnd () —> Show Window (SW_ SHOWMINIMIZED):
实例句柄
应用的程序的实例句柄保存在CWinApp::m_hInstance 中, 用户可以调用
AfxGetInstanceHandle获取句柄。
//Get apllication's instance handle. HANDLE hInstance = AfGetInstanceHandle ( ):
- 56 ---
hebei 第 57 页 105204873.doc
如何获取应用程序的 实例句柄?
应用程序的实例句柄保存在CWinApp m_hInstance 中,可以这么调用AfxGetInstancdHandle获得句柄. Example: HANDLE hInstance=AfxGetInstanceHandle() 如何通过代码获得应用程序主窗口的指针? 主窗口的指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED) //使程序最大化.
如何编程结束应用程序?
这是个很简单又是编程中经常要遇到的问题.向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据.
Example: AfxGetMainWindow()->SendMessage(WM_CLOSE) 还可以创建一个自定义的函数 Terminate Window
void Terminate Window(LPCSTR pCaption)
{
CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption) if (pWnd)
pWnd ->SendMessage(WM_CLOSE)
}
说明: FindWindow函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时FindWindow就无能为力了?可以通过枚举 windows任务列表的办法来实现。在机械出版社"Windows 95API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。
怎样加载其他的应用程序?
三个SDK函数 winexec, shellexecute,createprocess可以使用。
WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数值得一说,比如泥用 SW_SHOWMAXMIZED方式去加载一个无最大化按钮的程序,就是Neterm,calc等等,就不会出现正常的窗体,但是已经被加到任务列表里了。
ShellExecute较 WinExex灵活一点,可以指定工作目录,下面的Example就是直接打开c:\temp\1.txt,而不用加载与 txt文件关联的应用程序,很多安装程序完成后都会打开一个窗口,来显示Readme or Faq,我猜就是这么作的啦.
ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED) CreateProcess
最复杂,一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等.来看个很简单的Example:
- 57 ---
hebei 第 58 页 105204873.doc
STARTUPINFO stinfo
//启动窗口的信息
PROCESSINFO procinfo //进程的信息
CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_
CLASS,NULL,NULL, &stinfo,&procinfo)
确定应用程序的路径.
Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。
Example:
TCHAR
exeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧,好象是128
GetModuleFileName(NULL,exeFullPath,MAX_PATH)
获得各种目录信息
Windows目录: Use "GetWindowsDirectory" Windows下的system目录: Use "GetSystemDirectory" temp目录: Use "GetTempPath"
当前目录: Use "GetCurrentDirectory" 请注意前两个函数的第一个参数为目录变量名,后一个为缓冲区后两个相反.
如何自定义消息
(1) 手工定义消息,可以这么写
#define WM_MY_MESSAGE(WM_USER+100), MS 推荐的至少是 WM_USER+100
(2)写消息处理函数,用
WPARAM,LPARAM返回LRESULT.
LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
temp目录: Use "GetTempPath"
//加入你的处理函数 irectory"
}
- 58 ---
hebei 第 59 页 105204873.doc 如何改变窗口的图标?
向窗口发送 WM_SECTION消息。
Example:
HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON)
ASSERT(hIcon)
AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon)
如何改变窗口的缺省风格?
重载 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他创建信息.
Example: Delete "Max" Button and Set Original Window's Position and Size
BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs)
{
cs.style &=~WS_MAXINIZEMOX
cs.x=cs.y=0
cs.cx=GetSystemMetrics(SM_CXSCREEN/2)
cs.cy=GetSystemMetrics(SM_CYSCREEN/2)
return CMDIFramewnd ::PreCreateWindow(cs)
}
如何将窗口居中显示?
Call Function CWnd::
Center Windows
Example(1):
Center Window( ) //Relative to it's parent
// Relative to Screen
Example(2):
Center Window(CWnd:: GetDesktopWindow( ))
//Relative to Application's MainWindow
AfxGetMainWnd( ) -> Center Window( )
通用控件的显示窗口
MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表控件,CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。
- 59 ---
hebei 第 60 页 105204873.doc
移动窗口
调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关(顶层窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口的大小。
//Move window to positoin 100 , 100 of its parent window . SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE ,SWP_NOAORDER)
重置窗口的大小
调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。
// Get the size of the window .
Crect reWindow
GetWindowRect (reWindow )
//Make the window twice as wide and twice as tall . SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2, reWindow . Height () * 2,
SWP_NOMOVE ,SWP_NOZORDER )
如何单击除了窗口标题栏以外的区域使窗口移
动
当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息,可以处理该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用ClassWizard处理该信息并调用基类函数, 如果函数返回HTCLIENT则表明鼠标在客房区域,返回HTCAPTION表明鼠标在Windows的标题栏中。
UINT CSampleDialog : : OnNcHitTest (Cpoint point ) {
UINT nHitTest =Cdialog: : OnNcHitTest (point )
return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest }
上述技术有两点不利之处,其一是在窗口的客户区域双击时,窗口将极大;其二, 它不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键使主框窗口认为鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个
WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。
void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point )
{
CView : : OnLButtonDow (nFlags , pont )
//Fool frame window into thinking somene clicked on its caption bar .
- 60 ---
hebei 第 61 页 105204873.doc
GetParentFrame ( ) —> PostMessage (
WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) ) }
该技术也适用于对话框和基于对的应用程序,只是不必调用 CWnd: :GetParentFrame 。
void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point ) {
Cdialog : : OnLButtonDow (nFlags, goint )
//Fool dialog into thinking simeone clicked on its caption bar .
PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) )
}
如何限制窗口的大小?
也就是 FixedDialog形式。 Windows发送 WM_GETMAXMININFO消息来跟踪, 响应它,在
OnGetMAXMININFO 中写代码:
如何使窗口不可见,
很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow控制.
如何使窗口始终在最前方?
BringWindowToTop(Handle) SetWindowPos函数,指定窗口的最顶风格,用WS_EX_TOPMOST扩展
窗口的风格
Example:
void ToggleTopMost( CWnd *pWnd)
{
ASSERT_VALID(pWnd)
pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)? &wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE)
}
如何创建一个字回绕的CEditView
重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象的
ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示设置cs.
style,调用基类函数后要修改cs . style。
- 61 ---
hebei 第 62 页 105204873.doc BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs)
{
//First call basse class function .
BOOL bResutl =CEditView : : PreCreateWindow (cs)
// Now specify the new window style .
cs.style &= ~ (ES_AUTOHSCROLL ,WS_HSCROLL)
return bResult
}
如何让窗口和 MDI窗口一启动就最大化和最小化?
先说窗口。
在 InitStance 函数中设定 m_nCmdShow的取值.
m_nCmdShow=SW_SHOWMAXMIZED //最大化
m_nCmdShow=SW_SHOWMINMIZED //最小化
m_nCmdShow=SW_SHOWNORMAL //正常方式
MDI窗口:
如果是创建新的应用程序,可以用MFC AppWizard 的Advanced 按钮并在MDI子窗口风格组中检测最大化或最小化还可以重载 MDI Window 的PreCreateWindow函数,设置WS_MAXMIZE or WS_MINMIZE如果从 CMDIChildWnd派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MDI Child Window的风格。
如何使程序保持极小状态?
WS_MINMIZE如果从 CMDIChildWnd派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MD Child Window的风格。
这么办: 在恢复程序窗体大小时,Windows会发送WM_QUERY-OPEN消息,用 ClassWizard设成员函数
OnQueryOpen() ,add following code: Bool CMainFrame:: OnQueryOpen( )
{
Return false
}
如何限制窗口的大小?
- 62 ---
hebei 第 63 页 105204873.doc
也就是 FixedDialog形式。 Windows发送 WM_GETMAXMININFO消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码:
如何改变视窗的背景颜色
Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。 //Paint area that needs to be erased.
BOOL CSampleView : : OnEraseBkgnd (CDC* pDC) {
// Create a pruple brush.
CBrush Brush (RGB (128 , 0 , 128) )
// Select the brush into the device context . CBrush* pOldBrush = pDC—>SelcetObject (&brush)
// Get the area that needs to be erased . CRect reClip
pDC—>GetCilpBox (&rcClip)
//Paint the area.
pDC—> PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height( ) , PATCOPY )
//Unselect brush out of device context . pDC—>SelectObject (pOldBrush )
// Return nonzero to half fruther processing . return TRUE
}
如何改变窗口标题
调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。
//Set title for application's main frame window . AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") ) //Set title for View's MDI child frame window . GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") )
//Set title for dialog's push button control. GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") ) 如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数 AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在联机帮助中找到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。
AfxSetWindowText的实现如下:
voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )
{
itn nNewLen= Istrlen (Ipaznew)
TCHAR szOld [256]
//fast check to see if text really changes (reduces flash in the controls )
if (nNewLen >_contof (szOld)
,, : : GetWindowText (hWndCrtl, szOld , _countof (szOld) !=nNewLen
- 63 ---
hebei 第 64 页 105204873.doc ,, Istrcmp (szOld , IpszNew)! = 0
{
//change it
: : SetWindowText(hWndCtrl , IpszNew )
}
}
如何防止主框窗口在其说明中显示活动的文档名
创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。
BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs)
{
//Turn off FWS_ADDTOTITLE in main frame .
cs.styel & = ~FWS_ADDTOTITLE
return CMDIFrameWnd : : PreCreateWindow (cs ) }
关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。
如何获取有关窗口正在处理的当前消息的信息
调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。 viod CMainFrame : : OnCommmonMenuHandler ( ) {
//Display selected menu item in debug window .
TRACE ("Menu item %u was selected . \n" ,GetCruuentMessage ( ) —> wParam ) }
如何创建一个不规则形状的窗口
可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域,实际上使窗口成为指定的不规则形状。 使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。
Class CRoundDlg : public CDialog
- 64 ---
hebei 第 65 页 105204873.doc
{
…
private :
Crgn m_rgn : // window region
…
}
修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口:
BOOL CRoundDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( )
//Get size of dialog .
CRect rcDialog
GetClientRect (rcDialog )
// Create region and assign to window .
m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width( ) , rcDialog.Height ( ) )
SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn ,TRUE )
return TRUE
}
通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例子程序是改OnPaint函数使窗口形状看起来象一个球形体。
voik CRoundDlg : : OnPaint ( )
{
CPaintDC de (this) // device context for painting
//draw ellipse with out any border
dc. SelecStockObject (NULL_PEN)
//get the RGB colour components of the sphere color
COLORREF color= RGB( 0 , 0 , 255)
BYTE byRed =GetRValue (color)
BYTE byGreen = GetGValue (color)
BYTE byBlue = GetBValue (color)
// get the size of the view window
Crect rect
GetClientRect (rect)
// get minimun number of units
int nUnits =min (rect.right , rect.bottom )
//calculate he horiaontal and vertical step size
float fltStepHorz = (float) rect.right /nUnits
float fltStepVert = (float) rect.bottom /nUnits
int nEllipse = nUnits/3 // calculate how many to draw
int nIndex
// current ellipse that is being draw
CBrush brush
// bursh used for ellipse fill color
CBrush *pBrushOld // previous brush that was selected into dc
//draw ellipse , gradually moving towards upper-right corner
for (nIndex = 0 nIndes < + nEllipse nIndes++) {
//creat solid brush
brush . CreatSolidBrush (RGB ( ( (nIndex*byRed ) /nEllipse ).
( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) )
//select brush into dc
pBrushOld= dc .SelectObject (&brhsh)
- 65 ---
hebei 第 66 页 105204873.doc
//draw ellipse
dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,
rect. right -( (int) fltStepHorz * nIndex )+ 1,
rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1)
//delete the brush
brush.DelecteObject ( )
}
}
最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。
UINT CRoundDlg : : OnNchitTest (Cpoint point ) {
//Let user move window by clickign anywhere on thewindow .
UINT nHitTest = CDialog : : OnNcHitTest (point)
rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest }
如何设置工具条标题
工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下:
int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct )
{
…
// Set the caption of the toolbar .
m_wndToolBar.SetWindowText (_T "Standdard")
如何创建和使用无模式对话框
MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几个额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的:模式对话通过调用CDialog : : EndDialog来中止,无模式对话则是调用CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。
void CSampleDialog : : OnOK ( )
{
// Retrieve and validate dialog data .
if (! UpdateData (TRUE) )
{
// the UpdateData rountine
will set focus to correct item TRACEO (" UpdateData failed during dialog termination .\n")
return
- 66 ---
hebei 第 67 页 105204873.doc
}
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( )
}
void CSampleDialog : : OnCancel ( ) {
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( )
}
其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回,因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重置该函数并执行清除操作,诸如删除this指针。
void CSampleDialog : : PostNcDestroy ( )
{
// Declete the C++ object that represents this dialog.
delete this
最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放,要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序是如何创建无模式话的: 象;无模式对话不是同步的,创建函数调用后立即返回,
void CMainFrame : : OnSampleDialog ( ) {
//Allocate a modeless dialog object .
CSampleDilog * pDialog =new CSampleDialog
ASSERT_VALID (pDialog) Destroy ( )
//Create the modeless dialog . represents this dialog.
BOOL bResult = pDialog —> Creste (IDD_IDALOG)
ASSERT (bResult )
}
如何在对话框中显示一个位图
这要归功于Win 32先进的静态控件和Microsoft的资源编辑器,在对话框中显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。
如何改变对话或窗体视窗的背景颜色
调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。 BOOL CSampleApp : : InitInstance ( ) {
…
//use blue dialog with yellow text .
SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 ,255 , 0 ) )
…
- 67 ---
hebei 第 68 页 105204873.doc
}
需要重画对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR,通常用户可让Windows选择绘画背景的刷子,也可重置该消息指定刷子。下例说明了创建一个红色背景对话的步骤。
首先,给对话基类增加一人成员变量
CBursh :class CMyFormView : public CFormView {
…
private :
CBrush m_ brush // background brush }
其次, 在类的构造函数中将刷子初始化为所需要的背景颜色。
CMyFormView : : CMyFormView ( )
{
// Initialize background brush .
m_brush .CreateSolidBrush (RGB ( 0, 0, 255) ) }
最后,使用ClassWizard处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的刷子句柄。由于当重画对话控件时也要调用该函数,所以要检测nCtlColor参量。
HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor)
{
// Determine if drawing a dialog box . If we are, return +handle to
//our own background brush . Otherwise let windows handle it .
if (nCtlColor = = CTLCOLOR _ DLG )
return (HBRUSH) m_brush.GetSafeHandle ( )
return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor
)
}
怎样让MFC的TOOLBAR上的按钮上象WORD 6.0那样出小旗子? 自己改
在 CMyWinApp::OnIdle() 中 判断鼠标位置, 在ToolBar上时显示一个 Popup 窗口就行了。不一定要直接修改MFC的源码。我自己就实现过,不麻烦。VC++ 2.0 以后的类库已经实现,但VC++2.0 只能用于 32Bit 程序开发。我不知道有没有更新的16Bit 的MFC类库。如谁知道,告诉我一声。
如何使用GDI绘制的Bitmap?
用GDI函数绘制了一幅大图画,使用CScrolView显示,想加快速度避免重绘,使用CBitmap指针存储,总是出错,请赐教。
用兼容设备上下文试一试.
1) 创建一个与CScrolView设备上下文兼容的设备上下文
2) 创建一个ScrolSize大小的兼容位图
- 68 ---
hebei 第 69 页 105204873.doc
3) 将兼容位图选入兼容设备上下文
4) 用GDI函数在兼容设备上下文绘制
5) 需重绘时用BITBLT函数将兼容设备上下文的位图映射到CScrolView所在的 设备上下文上.
WINDOWS位图颠倒存储和显示是出于什么目的?
怎么样才能由上至下地显示一幅图象?能不能不颠倒?用SETDIBTODEVICE行吗?
是出于用户坐标系的原因.
用SETDIBTODEVICE可以,但仍需要注意位图的坐标系与DEVICE坐标系的区别.
我想在用VC++1.5编程时,new一个[512][512]的大数组,却总是不行(
这样的做法并不十分好,要分配如此大的内存最好用全局的内存分配函数.直接用指针操作,效率也会提高.
VC如何去掉mainframe菜单
跳过MFC的一套东西,在InitInstance()成员函数里直接调用CMydialog dlg; dlg.DoModal ; CMydialog
dlg; dlg.DoModal ; 以此对话框作为主界面.
在VC2中可以在APPWIZARD里选“DIALOG BASED APPLICATION”。
- 69 ---
hebei 第 1 页 105204873.doc
- 1 -
hebei 第 1 页 105204873.doc 说明:
这些文章只是从88上的精华区选取整理,没有记载原来作者,鉴于本文属个人自己整理,希望你补充之后将最新版本送给88上的hebei。
个别的目录有遗失的现象。
- 1 -
hebei 第 2 页 105204873.doc
- 2 -