孙鑫VC++学习笔记(转载至程序员之家--虎非龙)[1--5]

第一课

 

1.MFC生成的C++源文件中都有StdAfx.h,此文件包含了常用的AFX函数的声明,其中有afxwin.h,此文件包含了CRECT,CPoint,CWnd等许多类及其方法的声明。
2.Project->Setting->Debug可以加入命令行参数。
3.在SDK中要加入"windows.h"和stdio.h。因为LoadCursor,MessageBox等函数的声明在这个文件中。
4.创建一个完整的窗口的四个步骤SDK,1设计窗口类,2注册窗口类,3创建窗口,4显示窗口
5.函数名可以代表函数代码的首地址,即可作为函数指针。
6.要查看VC数据类型,可以在MSDN中输入“BOOL”然后选择“DATA TYPE”。
7.atof将字符串转化为float,atoi将字符串转化为int型。
8.所有从CWnd类派生的类都有m_hWnd句柄。
9.变量的生命周期:可以认为出了包含它的大括号,这个变量的生命周期结束。所以全局变量的声明位于所有大括号之外。但是用new声明的变量和用static声明的变量除外。
10.SDK示范程序,见下面。
11.sprintf格式化字符,其头文件为stdio.h,在MFC中格式化字符用CString.Format
12.GetDC()与ReleaseDC()要成对使用,否则会内存泄漏。同样,BeginPaint()与EndPaint()。
13.GetStockObject()得到画笔、画刷、字体、调色板的句柄,使用时必须用类型转换。
14.什么时候用NULL,什么时候用0.答,对指针赋值时用NULL,对变量赋值时用0.
15.什么是野指针?答:将指针指向的变量的内存释放后,此指针即变成野指针!如何避免野指针?答:将此指针指向NULL即可。p=NULL;
16.SDK代码流程:
#include "windows.h"//包含头文件LoadCursor,TextOut等函数
#include "stdio.h"//包含sprintf,printf等函数
LRESULT CALLBACK MyProc(...);//声明回调函数
int WINAPI WinMain()
{
WNDCLASS wndcls;//设计窗口类
wndcls.hcursor=LoadCursor();//初始化
....
RegisterClass(&wndcls);//注册窗口类
hwnd=CreateWindow(...);//创建窗口
ShowWindow(..);//显示窗口
UpdateWindow(..);
MSG msg;//定义消息结构体
while(GetMessage(...))//消息循环
{
...
}
return 0;
}

 

LRESULT CALLBACK MyProc(...)//实现回调函数
{
switch(uMsg)
{
case WM_CHAR:
break;
...
}
}

 

 

 

 

第2课
1.定义结构体和类时别忘记在最后加入";"号!例如Class Point{int x;int y;};
2.#include <xxx.h>与#include "xxx.h"的区别:<>不查找运行时目录,""查找运行时目录!
3.类的定义中,如果未指明成员类型,则缺省为private.而结构体中则缺省为public.
4.引用:引用经常用在函数的传参上。另外数值交换函数也经常用引用。例
change(int &x,int &y){int temp;temp=x;x=y;y=x}调用时即可以用 int a=3;int b=4;change(a,b);一般不用指针来作为参数进行数值交换。因为会引起歧义。
5.通常将类的定义放.h文件,而将其实现放在cpp文件中,别忘记了在cpp文件中#include "xxx.h"
6.如何防止类的重复定义?
用#inndef Point_H_H
#define Point_H_H
class Point{};
#endif来防止
7.源文件cpp文件单独编译成obj文件。最后由链接器将与将要使用到的C++标准库类链接成exe文件,头文件不参加编译。所以在cpp文件中别忘记了加入#include "xxx.h"
8.函数的覆盖,在子类中重写父类的函数,此时采用早期绑定的方法。如果加入了virtual,则将采用迟绑定的技术,在运行时根据对象的类型确定调用哪一个函数。此迟绑定技术是MFC的类的继承的精髓。
9.强制类型转换。如果CFish从CAnimal派生而来。则可以将鱼的对象转换为CAnimal的对象,而反之则不行。从现实中理解也是正常的,鱼可以是动物,而动物却不是鱼。再如int可以强制转换成char型。而反之则出错。

 

 

 

 

第3课
1.在main或WinMain之前,全局变量已经被分配内存并初始化了。
2.在MFC中在WinMain之前有个theApp全局变量先被构造并被初始化,而由于子类构造函数执行前,其父类的构造函数先被执行,所以CTestApp的父类CWinAPP的构造函数先执行。产生了theApp对象后,在WinMain()中的指针*pThread和*pApp就有了内容。
3.MFC大致流程:
CTestApp theApp;//构造全局对象
WinMain()
{
AfxWinMain();//调用下面的函数
}
AfxWinMain()
{
pThread->Initinstance();//初始化工作和注册窗口类,窗口显示和更新
pThread->Run();//消息循环
}
而在BOOL CTestApp::InitInstance()中的代码
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
  IDR_MAINFRAME,
  RUNTIME_CLASS(CTestDoc),
  RUNTIME_CLASS(CMainFrame),       // main SDI frame window
  RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate);
完成了将这三个类关联起来的工作。
4.如何在单文档文件中显示一个CButton的对象?
在CMainFrame::OnCreate()中定义一个CButton的对象btn;然后调用btn.Create("维新",WS_DISABLED   |WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,
  CRect(0,0,300,100),/*GetParent(),*/this,123);
注意点:
     (1).此处btn不能是局部变量,否则它的生命周期太短,将不能显示。
     (2).在create函数的第二个参数中加入WS_VISIBLE 参数才行。否则必须调用ShowWindow
也可以在view的OnCreate消息响应函数中加入
     (3).CButton类的定义头文件在afxwin.h中,而stdafx.h包含了afxwin.h,所以可以直接使用。因为MFC中的每一个类中都有#include "stdafx.h"的声明。

 

第4课 1.在单文档中view挡在MainFrame的前面。此时如果编写针对MainFrame的mouseClick事件,将不会有反应。 2.消息响应会在3处修改代码,1处是在头文件中, //{{AFX_MSG(CDrawView) afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() 另一处是cpp文件的begin MessageMap和End MessageMap之间, BEGIN_MESSAGE_MAP(CDrawView, CView) //{{AFX_MSG_MAP(CDrawView) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() 最后是要有函数实现的代码。 void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) { // TOD Add your message handler code here and/or call default m_ptOrigin=m_ptOld=point; m_bDraw=TRUE; CView::OnLButtonDown(nFlags, point); } 3.画线:定义一个成员变量保存mouseDown的点m_Point 1)API函数方法画线用HDC 2)用CDC类成员函数画线。此时别忘记ReleaseDC 3)用CClientDC 4)用CWindowDC,用它甚至可以整个屏幕区域画线。 下面是上面4种方法的代码 /*HDC hdc; hdc=::GetDC(m_hWnd); MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL); LineTo(hdc,point.x,point.y); ::ReleaseDC(m_hWnd,hdc);必须成对使用。*/ /*CDC *pDC=GetDC(); pDC->MoveTo(m_ptOrigin); pDC->LineTo(point); ReleaseDC(pDC);必须成对使用。*/

//CClientDC dc(this); /*CClientDC dc(GetParent()); dc.MoveTo(m_ptOrigin); dc.LineTo(point);此处不需要ReleaseDC,因为CClientDC会自动释放DC*/

//CWindowDC dc(this); //CWindowDC dc(GetParent()); /*CWindowDC dc(GetDesktopWindow());//此时可以在整个屏幕上画线。 dc.MoveTo(m_ptOrigin); dc.LineTo(point);*/ /*CPen pen(PS_DOT,1,RGB(0,255,0)); CClientDC dc(this); CPen *pOldPen=dc.SelectObject(&pen); dc.MoveTo(m_ptOrigin); dc.LineTo(point); dc.SelectObject(pOldPen);*/ 5)用Bitmap填充所画的矩形。 CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CBrush brush(&bitmap); CClientDC dc(this); dc.FillRect(CRect(m_ptOrigin,point),&brush); //CBRUSH::FromHandle是静态成员函数,所以可以用下面的方法调用。 CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); CBrush *pOldBrush=dc.SelectObject(pBrush); dc.Rectangle(CRect(m_ptOrigin,point)); dc.SelectObject(pOldBrush); m_bDraw=FALSE; 6)用其它颜色画线 CClientDC dc(this); CPen pen(PS_SOLID,1,RGB(255,0,0)); CPen *pOldPen=dc.SelectObject(&pen);//选中红色画笔 if(m_bDraw==TRUE) { dc.SetROP2(R2_BLACK);//设置绘画模式 dc.MoveTo(m_ptOrigin); //dc.LineTo(point); dc.LineTo(m_ptOld); //dc.MoveTo(m_ptOrigin); dc.MoveTo(m_ptOld); dc.LineTo(point); //m_ptOrigin=point; m_ptOld=point; } dc.SelectObject(pOldPen); 4.MFC中隐式的包含了windows.h。为什么? 因为在AFXV_W32.h文件中: // This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. 在AFXWIN.h中 // Note: WINDOWS.H already included from AFXV_W32.H 5.如何从句柄获得对象的指针? 答FromHandle 6.类的静态成员函数可以由类名直接调用,也可以由对象调用。可以认为静态成员函数并不属于某个对象,它属于类本身。程序运行伊始,即使没有实例化类的对象,静态成员函数和静态成员变量已然有其内存空间。静态成员函数不能访问非静态成员变量!静态成员变量必须在类的外部初始化。当然如果并不打算用到静态成员变量,此时你可以不初始它。 7.理解代码区,数据区,堆,栈! 请见下面的简介: http://www.downcode.com/server/j_server/J_1010.Html 对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

 

 

 

第5课 1.CWnd::CreateSolidCaret创建插入符,ShowCaret()显示插入符。GetTextMetrics(),获得当前字体的一些信息。CWnd::CreateCaret()创建图象插入符 bitmap.LoadBitmap(IDB_BITMAP1);//此处的bitmap为成员变量!!! CreateCaret(&bitmap); ShowCaret(); TEXTMETRIC tm;//字体结构体 dc.GetTextMetrics(&tm);// m_ptOrigin.y+=tm.tmHeight;//获得字体高度。 2.VC中CString::LoadString(ID号),比较方便。 3.路径层的概念:有两种方法创建路径层: (1) pDC->BeginPath(); pDC->Rectangle(50,50,50+sz.cx,50+sz.cy); pDC->EndPath(); pDC->SelectClipPath(RGN_DIFF); (2) CSize sz=pDC->GetTextExtent(str); CRgn rn; rn.CreateRectRgn(0,50,sz.cx,sz.cy); pDC->SelectClipRgn(&rn,RGN_DIFF); 路径层有什么作用?可以保护我们先前的文本或者图像不被后来画的覆盖。 4.在View上输入文字的步骤。 CFont font;//创建字体对象 font.CreatePointFont(300,"华文行楷",NULL);//设置 CFont *pOldFont=dc.SelectObject(&font);//将字体选择到DC中 TEXTMETRIC tm;//创建字体信息对象 dc.GetTextMetrics(&tm);//获得当前字体信息 if(0x0d==nChar)//处理回车键 { m_strLine.Empty(); m_ptOrigin.y+=tm.tmHeight; } else if(0x08==nChar)//处理退格键 { COLORREF clr=dc.SetTextColor(dc.GetBkColor()); dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine); m_strLine=m_strLine.Left(m_strLine.GetLength()-1); dc.SetTextColor(clr); } else { m_strLine+=nChar; } CSize sz=dc.GetTextExtent(m_strLine);

CPoint pt;//处理光标的位置 pt.x=m_ptOrigin.x+sz.cx; pt.y=m_ptOrigin.y;

SetCaretPos(pt); dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);//输出字体

dc.SelectObject(pOldFont);//将原先的字体选择回去。 5.模拟卡啦OK变色的步骤。 (1)设置定时器 (2)在定时器中加入如下代码 //DEL m_nWidth+=5;//此为view的成员变量,初始值为0 //DEL //DEL //DEL CClientDC dc(this); //DEL TEXTMETRIC tm; //DEL dc.GetTextMetrics(&tm); //DEL CRect rect; //DEL rect.left=0; //DEL rect.top=200; //DEL rect.right=m_nWidth; //DEL rect.bottom=rect.top+tm.tmHeight;//此长方形的长度随着定时器的触发,逐渐增大 //DEL //DEL dc.SetTextColor(RGB(255,0,0)); //DEL CString str; //DEL str.LoadString(IDS_WEIXIN); //DEL dc.DrawText(str,rect,DT_LEFT);此函数的作用是将字符串输出到长方形中,但如果字符串的长度超过长方形的长度,多余的字符将被截断 //DEL //DEL rect.top=150; //DEL rect.bottom=rect.top+tm.tmHeight; //DEL dc.DrawText(str,rect,DT_RIGHT); //DEL //DEL CSize sz=dc.GetTextExtent(str);获得字符串的长度 //DEL if(m_nWidth>sz.cx)当长方形的长度大于字符串的长度后,将其重新归0 //DEL { //DEL m_nWidth=0; //DEL dc.SetTextColor(RGB(0,255,0)); //DEL dc.TextOut(0,200,str); //DEL } //DEL //DEL CView::OnTimer(nIDEvent); 6.SetTimer也可以用回调函数来操作,但并不方便。以下是步骤 (1) 在View的OnCreate消息响应函数中:SetTimer(1,1000,Timer2Proc); (2) 回调函数的实现: void CALLBACK EXPORT Timer2Proc( HWND hWnd, // handle of CWnd that called SetTimer UINT nMsg, // WM_TIMER UINT nIDEvent, // timer identification DWORD dwTime // system time ) { // MessageBox((((CMainFrame *)AfxGetMainWnd())->m_hWnd),"ddfaf","weixin",0); ; CMainFrame *pMain=(CMainFrame *)AfxGetApp()->m_pMainWnd;//获得MainFrame的指针 CTextView *pView=(CTextView *)pMain->GetActiveView();//获得view的指针 CClientDC dc(pView);//构造DC dc.TextOut(333,222,"hello world");

}//我们可以看出,使用回调函数时要获得窗口或者APP的指针,给我们的操作带来麻烦。并不方便。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值