// CClientDC类在构造时调用GetDC,然后在释放时又调用ReleaseDC所以不用手动释放
//利用MFC的CWindowDC绘图
/好处是可以访问整个窗口区域,包括框架窗口客户区和非客户区,桌面等, // // // // // // // // // // // // // // // // // // // // // }
CWindowDC dc(this); CWindowDC dc(GetParent()); dc.MoveTo(m_ptnOrigin); dc.LineTo(point);
CWindowDC dc(GetDesktopWindow());//这个可以画到桌面上其它地方 dc.MoveTo(m_ptnOrigin); dc.LineTo(point);
//以上所画的线条颜色都是黑色的,因为在设备描述表中使用默认的画笔(黑色), //要改变线条颜色则需要自己生成一个新的画笔对象, //将它选到设备描述表中,再画就使用新画笔来绘图 CPen m_pen(PS_DASH, 2, RGB(255, 0, 0));//生成新的画笔 CClientDC dc(this);
CPen *pOldPen = dc.SelectObject(&m_pen);//选择进设备描述表中 dc.MoveTo(m_ptnOrigin); dc.LineTo(point);
dc.SelectObject(pOldPen);//在使用完新的画笔后,要将原来的画笔重新选择时设备描述表 //使用画刷来填充矩形
CBrush m_brush(RGB(120, 0, 23)); CClientDC dc(this);
dc.FillRect(CRect(m_ptnOrigin, point), &m_brush); //使用位图画刷来填充矩形 //创建一个位图对象 CBitmap m_bitmap;
m_bitmap.LoadBitmap(IDB_MyBitmap); CBrush m_Brush(&m_bitmap); CClientDC dc(this);
dc.FillRect(CRect(m_ptnOrigin, point), &m_Brush); //透明画刷
//首先使用Win32的API函数GetStockObject来获取一个NULL_BRUSH画刷 CClientDC dc(this);
CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); CBrush *pOldBrush = dc.SelectObject(pBrush); dc.Rectangle(CRect(m_ptnOrigin, point)); dc.SelectObject(pOldBrush); bIsMouseDown = FALSE;
CView::OnLButtonUp(nFlags, point);
//是静态成员函数,从句柄获取对象的指针
类的静态成员函数可以由类名直接调用,也可以由对象调用。可以认为静态成员函数并不属于某个对象,它属于类本身。程序运行伊始,即使没有实例化类的对象,静态
成员函数和静态成员变量已然有其内存空间。静态成员函数不能访问非静态成员变量!静态成员变量必须在类的外部初始化。当然如果并不打算用到静态成员变量,此时你可以不初始它。 4. 理解代码区,数据区,堆,栈!(http://www.downcode.com/server/j_server/J_1010.Html)
对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。
Lesson5: 文本编程
1,创建插入符:
void CreateSolidCaret( int nWidth, int nHeight );//创建插入符 void CreateCaret( CBitmap* pBitmap );//创建位图插入符 void ShowCaret( );//显示插入符 void HideCaret( );//隐藏插入符
static void PASCAL SetCaretPos( POINT point );//移动插入符号 说明: 1)创建插入符要在窗口创建完成之后,CreateSolidCaret函数创建的插入符被初始化为隐藏,所以需要调用ShowCaret()将其显示。
2)使用CreateCaret函数创建位图插入符的时候,不能使用局部的位图对象关联位图资源。(与资源相关联的C++对象,当它析构的时候会同时把与它相关联的资源销毁。) 2,获取当前字体信息的度量:CDC::GetTextMetrics
BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const; 说明:
typedef struct tagTEXTMETRIC { /* tm */
int tmHeight;//字体高度。Specifies the height (ascent + descent) of characters. int tmAscent;//基线以上的字体高度 int tmDescent;//基线以下的字体高度 int tmInternalLeading; int tmExternalLeading;
int tmAveCharWidth;//字符平均宽度 int tmMaxCharWidth; int tmWeight; BYTE tmItalic;
BYTE tmUnderlined; BYTE tmStruckOut; BYTE tmFirstChar; BYTE tmLastChar; BYTE tmDefaultChar;
BYTE tmBreakChar;
BYTE tmPitchAndFamily; BYTE tmCharSet; int tmOverhang;
int tmDigitizedAspectX; int tmDigitizedAspectY; } TEXTMETRIC; //创建设备描述表 CClientDC dc(this); //定义文本信息结构体变量 TEXTMETRIC tm; //获得设备描述表中的文本信息 dc.GetTextMetrics(&tm); //根据字体大小,创建合适的插入符 CreateSolidCaret(tm.tmAveCharWidth / 8, tm.tmHeight); ShowCaret(); 3,OnDraw函数:
virtual void OnDraw( CDC* pDC ) 当窗口(从无到有或尺寸大小改变等)要求重绘的时候,会发送WM_PAIN消息,调用OnDraw函数进行重绘。在客户区的绘图如果想保持不变也可以在这个函数中进行编写,每次重给的时候会再次执行代码,生成绘图.
4,获取某字符串的高度和宽度(区别字符串的长度,长度表示字符个数): CDC::GetTextExtent
CSize GetTextExtent( LPCTSTR lpszString, int nCount ) const; CSize GetTextExtent( const CString& str ) const; 说明:
//The CSize class is similar to the Windows SIZE structure。 typedef struct tagSIZE { int cx;//the x-extent int cy;//the y-extent } SIZE;
5,路径层:
BOOL BeginPath( );//CDC中函数 //在这作图定义路径层剪切区域 BOOL EndPath( );
BOOL SelectClipPath( int nMode );//调用这个函数来使当前路径层剪切区域与新剪切区域进行互操作。
//在这覆盖作图(包含前定义的路径层区域)定义新的剪切区域 说明:
1)SelectClipPath Selects the current path as a clipping region for the device context, combining the new region with any existing clipping region by using the specified mode. The device context identified must contain a closed path.
2)应用:当作图的时候,如果想要在整幅图形其中的某个部分和其它部分有所区别,我们
可以把这部分图形放到路径层当中,然后指定调用指定互操作模式调用SelectClipPath( int nMode )函数来使路径层和覆盖在其上新绘图剪切区域进行互操作,达到特殊效果。 6,关于文本字符串一些函数:
COLORREF GetBkColor( ) const;//得到背景颜色
virtual COLORREF SetBkColor( COLORREF crColor );//设置背景颜色 BOOL SetTextBkColor( COLORREF cr );//设置文本背景颜色
virtual COLORREF SetTextColor( COLORREF crColor );//设置文本颜色
virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount );//输出文本 BOOL TextOut( int x, int y, const CString& str );//在x,y所指定坐标处输出str CString Left( int nCount ) const;//得到字符串左边nCount个字符 int GetLength( ) const;//得到字符串长度strlen() 7,字体CFont::CFont CFont( );//构造函数
//Constructs a CFont object. The resulting object must be initialized with CreateFont, CreateFontIndirect, CreatePointFont, or CreatePointFontIndirect before it can be used. 选用字体事例代码组: CClientDC dc(this);
CFont font;//构造字体对象
font.CreatePointFont(300,\华文行楷\初始化字体对象,与字体资源相关联 CFont *pOldFont=dc.SelectObject(&font);//将新字体选入DC ...
dc.SelectObject(pOldFont);//恢复原字体 说明:
1)构造字体对象时候,必须初始化。(初始化是将字体对象与字体资源相关联)。 2)初始化对象时候,选用的字体也可以是系统字体,但不一定都有效,据测试选用。 8,在MFC中CEditView 和 cRichEditView类已经完成了初步的文字处理。可以让应用程序的View类以CEditView 和 cRichEditView类为基类。在创建工程中的第六步可以选择. 9,平滑变色
CDC::TextOut()是一个字母一个字母的输出,达不到平滑效果。
CDC::DrawText():将文字的输出局限于一个矩形区域,超出矩形区域的文字都被截断。利
用这一特点,可每隔些时间增加矩形大小,从而可实现人眼中的平滑效果。 CWnd::SetTimer():设置定时器。按设定的时间定时发送WM_TIMER消息。 说明:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );
//nIDEvent定时器标示,nElapse消息发送间隔时间,void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)设置回调函数,如果设置则由设置的回调函数处理WM_TIMER消息,如果没有设置回调函数设为NULL,这发送的WM_TIMER消息压入消息队列,交由相关联的窗口处理(添加WM_TIMER消息处理函数OnTimer())。
afx_msg void OnTimer( UINT nIDEvent );
//响应WM_TIMER消息,nIDEvent为消息对应定时器标示(可以设置不同的定时器发送
WM_TIMER消息)
问题:
1,在CCareView类中添加WM_CREATE消息响应函数OnCreate(),WM_CREATE消息是在什么时候被检查到而被响应的呢?
(猜测:添加WM_CREATE消息后,消息被压入消息队列,然后经过消息循环进行分发到具体窗口,从而进行响应)
2,现有一文本文件内容已经读入串STR中,要求在视图客户区按原先文本文件中的格式输出。
问题是,利用CDC的TextOut()来在CView类派生类窗口中输出串时,忽略了串中的TAB、回车换行等格式,无论串有多长均在一行上输出。 这其中是CDC类成员函数TextOut()忽略串中格式的,还是CView类派生类窗口设置从中做怪呢?怎么解决
Lesson6: 菜单编程
1. MFC中的顶层菜单默认为弹出菜单(Pop-up),它是不能用来作命令响应的,当取消
Pop-up选项后可接受命令响应。
2. 消息的分类:标准消息,命令消息,通告消息。
[标准消息]:除WM_COMMAND之外,所有以WM_开头的消息。从CWnd类派生的类都可以接收到这一消息
[命令消息]:来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget(CWnd的父类)派生的类都可以接收到这一类消息
[通告消息]:由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。从CCmdTarget(CWnd的父类)派生的类都可以接收到这一类消息 总结:凡是从CWnd派生的类,既可以接收标准消息,也要以接收命令消息和通告消息。而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。
3. MFC中菜单项消息如果利用ClassWizard来对菜单项消息分别在上述四个类中进行响
应,则菜单消息传递顺序:View类--Doc类--CMainFrame类--App类。菜单消息一旦在其中一个类中响应则不再在其它类中查找响应函数。
菜单消息与前面介绍的标准消息的实现机制是相类似的,都是在消息响应函数原型(头文件),消息映射宏(源文件)和消息函数实现(源文件)中添加代码。注意:文档类与应用程序类都是由CCmndTarget类派生,所以可以接收菜单命令消息,但不能接收标准消息(只能由CWnd类派生才可以)。 具体消息路由过程:
当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终交给App类进行处理。