孙鑫vc++笔记Word下载.docx
《孙鑫vc++笔记Word下载.docx》由会员分享,可在线阅读,更多相关《孙鑫vc++笔记Word下载.docx(30页珍藏版)》请在冰豆网上搜索。
ssay()"
endl;
};
classStudent:
publicPerson
Student()
voidsay()
Student'
Students;
intmain()
s.p->
say();
//这里将调用子类的方法
return0;
}
什么都不用做,直接用向导生成一个MFC窗口。
下面是结构图,有五个类
是这样命名的,开头的C表示Class,C+工程名+(App,Doc,View...)
其中CMainFrame表示一个窗口(主窗体,包括标题栏,菜单...),XXApp表示运用程序,XXDOC表示文档类(加载数据,实现数据的存储与操作分离),XXView也表示一个窗口(相当于Windows的客户区)
下面看看MFC中类的主要继承关系:
由于继承树太大,这里只罗列了CWnd的继承关系
API中CreateWindowEx和CreateWindow几乎是一样的,Ex表示扩展,多了一个参数
下面用API模拟CWnd
just模拟
//下面是模仿封装API函数
classCWnd
BOOLCreateEX(
DWORDdwExStyle,//extendedwindowstyle
LPCTSTRlpClassName,//registeredclassname
LPCTSTRlpWindowName,//windowname
DWORDdwStyle,//windowstyle
intx,//horizontalpositionofwindow
inty,//verticalpositionofwindow
intnWidth,//windowwidth
intnHeight,//windowheight
HWNDhWndParent,//handletoparentorownerwindow
HMENUhMenu,//menuhandleorchildidentifier
HINSTANCEhInstance,//handletoapplicationinstance
LPVOIDlpParam//window-creationdata
);
BOOLShowWindow(intnCmdShow);
BOOLUpdateWindow();
HWNDm_hWnd;
BOOLCWnd:
:
CreateEx(
DWORDdwExStyle,//extendedwindowstyle
LPCTSTRlpClassName,//registeredclassname
LPCTSTRlpWindowName,//windowname
DWORDdwStyle,//windowstyle
intx,//horizontalpositionofwindow
inty,//verticalpositionofwindow
intnWidth,//windowwidth
intnHeight,//windowheight
HWNDhWndParent,//handletoparentorownerwindow
HMENUhMenu,//menuhandleorchildidentifier
HINSTANCEhInstance,//handletoapplicationinstance
LPVOIDlpParam//window-creationdata
);
m_hWnd=:
CreateWindowEx(dwExstyle,lClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,
hMenu,hInstance,lParam);
if(m_hWnd!
=NULL)
returnTRUE;
else
returnFALSE;
ShowWindow(intnCmdShow)
return:
ShowWindow(m_hWnd,nCmdShow);
//调用的是SDK全局函数,加个:
说明是全局的
UpdateWindow()
UpdateWindow(m_hWnd);
intWINAPIWinMain(
HINSTANCEhInstance,//handletocurrentinstance
HINSTANCEhPrevInstance,//handletopreviousinstance
LPSTRlpCmdLine,//commandline
intnCmdShow//showstate
)
{
WNDCLASSwndclass;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
wndclass.hInstance=hInstance;
...
CWndcwnd;
cwnd.CreateEx(dwExstyle,...,...);
cwnd.ShowWindow(nCmdShow);
cwnd.UpdateWindow();
while(GetMessage(&
msg,NULL,0,0))
{
TranslateMessage(&
msg);
DispatchMessage(&
}
}
下面是重头戏(引用了某位仁兄的,太详细了)
重点:
MFC运行机制
提示:
对于不想理解内部运行过程的,可以不看这一章,可以看了后面的界面设计再回头来看这一章,可能感觉更深刻。
这一次课和上一次的课的重点就是MFC的窗口类创建过程,而要反复说明的就是:
MFC的程序和C语言的程序,从执行原理上说,是完全一致的。
抓住这一点,那么对于理解MFC程序的运行机制也就相对于简单了。
C中的main函数就相当于MFC中的WinMain函数。
感兴趣的可以利用VC的断点设置自己跟踪下面讲述的各个函数,就明白它的执行顺序了。
一、C语言程序执行步骤
在C语言中,大约的步骤如下:
1,全局变量内存分配
2,进入main函数
二、MFC程序的运行步骤(主要是初始化)
打开一个MFCAPPWizard(exe)工程,跟踪其执行步骤,可以发现,是以下顺序:
1)CXXApp中的全局变量定义
CXXApptheApp;
2)调用CXXApp构造函数
CXXApp:
CXXApp(){}
3)进入Winmain函数(_tWinMain为宏,值为WinMain)
_tWinMain(){}
4)完成初始化工作:
包括窗口类注册、窗口产生、显示和更新
pThread->
InitInstance()
对于MFC程序,MainFrame,View,ToolBar,Controlbar等都是窗口,所以下面的窗口注册与创建、显示等要反复调用多次,一次对应一个窗口
(1)注册窗口类
AfxEndDeferRegisterClass
(2)创建窗口
CMainFrame:
PreCreateWindow()//反复调用一次是给我们修改窗口属性的机会
CFrameWnd:
Create()
(3)消息循环
PumpMessage()
补充1:
在MFC中,由于涉及到(窗口)类定义,所以定义全局变量的时候,需要进行更多的步骤。
全局变量涉及到类定义(类似于C中的类型定义)的话,那么需要遵循以下步骤(以MFC的窗口类为例)
1)设计一个窗口类
2)注册窗口类
3)创建窗口
4)显示及更新窗口
5)消息循环
补充2:
其他需要注意的几点
1,每一个MFC程序,有且只有一个从WinApp类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身。
在WIN32程序当中,表示应用程序是通过WINMAIN入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。
在基于MFC应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。
2,_tWinMain函数中通过调用AfxWinMain()函数来完成它要完成的功能。
(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。
3,设计窗口类:
在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。
4,PreCreateWindow()是个虚函数,如果子类有则调用子类的。
5,CreateWindowEx()函数参数与CREATESTRUCT结构体成员完全一致,CreateWindowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前通过可PreCreateWindow(cs)修改cs结构体成员来修改所要的窗口外观。
6,注意两个函数。
:
TranslateMessage(&
m_msgCur)函数进行消息(如键盘消息)转换
DispatchMessage(&
m_msgCur)函数分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。
)
7,可以认为View类窗口是CMainFram类窗口的子窗口。
DOCument类是文档类。
DOC-VIEW结构将数据本身与它的显示分离开。
文档类用于数据的存储,加载;
视类用于数据的显示,修改
8,CTEApp:
InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。
语句如下:
CSingleDocTemplate*pDocTemplate;
pDocTemplate=newCSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTEDoc),
RUNTIME_CLASS(CMainFrame),//mainSDIframewindow
RUNTIME_CLASS(CTEView));
AddDocTemplate(pDocTemplate);
//增加到模板
补充3:
本课涉及到MFC函数的源文件位置
根目录
找到您安装VC98下MFC的位置,比如我的机子上为:
D:
\ProgramFiles\MicrosoftVisualStudio\VC98\MFC。
下面提供的就是相对路径了。
CWinApp构造函数:
MFC=>
SRC=>
APPCORE.CPP
AfxWinMain:
MFC=>
WINMAIN.CPP
AfxEndDeferRegisterClass:
PreCreateWindow()函数所在文件:
WINFRM.CPP
Create()函数路径:
CWnd:
CreateEx()函数路径:
WINCORE.CPP
CWinThread:
Run()方法路径:
THRDCORE.CPP
创建按钮
1在CMainFrame创建
双击CMainFrame,添加数据成员,CButtonm_btn
在OnCreate方法添加如下代码:
[html]
viewplain
copy
1.m_btn.Create(TEXT("
first
Button"
),BS_PUSHBUTTON|WS_CHILD,CRect(0,0,100,100),this,123);
2.m_btn.ShowWindow(SW_NORMAL);
2在CXXView创建
双击CXXView,添加数据成员,CButtonm_btn
在CXXView右键AddwindowsMessageHandler添加WM_CREATE消息处理,然后生成OnCreate函数
在OnCreate函数添加如下代码
Button2"
),BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,CRect(0,0,100,100),this,123);
两个代码效果是等价的:
第四讲
1.在单文档中view挡在MainFrame的前面。
此时如果编写针对MainFrame的mouseClick事件,将不会有反应。
2.消息响应会在3处修改代码,1处是在头文件中,
//{{AFX_MSG(CDrawView)
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);
afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);
afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
另一处是cpp文件的beginMessageMap和EndMessageMap之间,
BEGIN_MESSAGE_MAP(CDrawView,CView)
//{{AFX_MSG_MAP(CDrawView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
//Standardprintingcommands
ON_COMMAND(ID_FILE_PRINT,CView:
OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,CView:
ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView:
OnFilePrintPreview)
END_MESSAGE_MAP()
最后是要有函数实现的代码。
voidCDrawView:
OnLButtonDown(UINTnFlags,CPointpoint)
//TODAddyourmessagehandlercodehereand/orcalldefault
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种方法的代码
/*HDChdc;
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);
LineTo(point);
ReleaseDC(pDC);
//CClientDCdc(this);
/*CClientDCdc(GetParent());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
此处不需要ReleaseDC,因为CClientDC会自动释放DC*/
//CWindowDCdc(this);
//CWindowDCdc(GetParent());
/*CWindowDCdc(GetDesktopWindow());
//此时可以在整个屏幕上画线。
/*CPenpen(PS_DOT,1,RGB(0,255,0));
CClientDCdc(this);
CPen*pOldPen=dc.SelectObject(&
pen);
dc.SelectObject(pOldPen);
5)用Bitmap填充所画的矩形。
CBitmapbitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
CBrushbrush(&
bitmap);
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)用其它颜色画线
CPenpen(PS_SOLID,1,RGB(255,0,0));
//选中红色画笔
if(m_bDraw==TRUE)
dc.SetROP2(R2_BLACK);
//设置绘画模式
//dc.LineTo(point);
dc.LineTo(m_ptOld);
//dc.MoveTo(m_ptOrigin);
dc.MoveTo(m_ptOld);
//m_ptOrigin=point;
m_ptOld=point;
4.MFC中隐式的包含了windows.h。
为什么?
因为在AFXV_W32.h文件中:
//ThisisapartoftheMicrosoftFoundationClassesC++library.
//Copyright(C)1992-1998MicrosoftCorporation
//Allrightsreserved.
在AFXWIN.h中
//Note:
WINDOWS.HalreadyincludedfromAFXV_W32.H
5.如何从句柄获得对象的指针?
答FromHandle
6.类的静态成员函数可以由类名直接调用,也可以由对象调用。
可以认为静态成员函数并不属于某个对象,它属于类本身。
程序运行伊始,即使没有实例化类的对象,静态成员函数和静态成员变量已然有其内存空间。
静态成员函数不能访问非静态成员变量!
静态成员变量必须在类的外部初始化。
当然如果并不打算用到静态成员变量,此时你可以不初始它。
7.理解代码区,数据区,堆,栈!
请见下面的简介:
对于一个进程的内存空间而言,可以在逻辑上分成3个部份:
代码区,静态数据区和动态数据区。
动态数据区一般就是“堆栈”。
“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。
进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。
一个堆栈可以通过“基地址”和“栈顶”地址来描述。
全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即