一.Win32基本程序概念

所有的windows程序都必须载入windows.h

MFC程序都有一个Stdafx.h文件,它载入了MFC框架必须的文件.

Windows程序以消息为基础,以事件驱动之.

应用程序获得的”输入”分类:

1.由硬件产生的消息,如鼠标移动或键盘按下,这种消息放在系统队列.

2.由Windows系统或其他Windows程序传送过来的消息,这种消息放在程序队列.

while GetMessage(&msg,NULL,NULL,NULL)//获得消息

{

TranslateMessage(&msg);//翻译消息,如将键盘按键的WM_KEYXXX转换为WM_KEYCHART

DispatchMessage(&msg);//派送消息.通过USER模块的协助,将消息送到所属窗口

}

处理WM_COMMAND时:

wParam的低16位表示产生消息的控件的ID,而高16位为通知码(通知码是什么?)

DialogBox:启动一个对话框

EndDialog:关闭一个对话框

对话框处理消息后应该返回TRUE;如果未处理消息,则应该返回FALSE,让系统的默认对话框函数处理.

WM_CLOSE:用户可根据自己的意愿来选择是否关闭窗口.如果需要关闭窗口,就执行DestroyWindows来发送一个WM_DESTROY消息.

WM_DESTROY:关闭窗口,但程序还在运行,如果需要彻底关闭应用程序,就需要执行PostQuitMessage(0)来产生一个WM_QUIT消息

WM_QUIT:当GetMessage捕获到WM_QUIT消息时传回0,从而退出while循环,进而结束整个程序.WM_QUITE是不会到达窗口的消息处理函数的.

win32应用程序的完整退出过程:

1.点击窗口右上角的关闭按钮,发送WM_CLOSE消息。

2.在WM_CLOSE消息处理中调用DestroyWindow函数,发送WM_DESTROY消息。

3.在WM_DESTROY消息处理中调用PostQuitMessage(0)函数,发送WM_QUIT消息到消息队列中。

4.GetMessage捕获到WM_QUIT,返回0,退出循环(应用程序真正退出)。

按照上述正常流程,WM_QUIT是不会到达窗口过程的。(因为在GetMessage截获了WM_QUIT消息之后,程序已经彻底退出了!)

空闲时间的处理:OnIdle

while (TRUE)

{

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

{
   if(msg.message == WM_QUIT)

break;

TranslateMessage(&msg);
    DispatchMessage(&msg);

}

else

OnIdle();//空闲的时候调用

}

创建一个进程:CreateProcess;进程结束自己的生命(退出):ExitProcess;结束另一个进程的生命:TerminateProcess(不建议使用)

创建一个线程:CreateThread

进程建立后,主线程也产生.执行程序代码,是线程的工作.

线程建立后,一般使用CloseHandle断开线程和创建者的关系.

二.C++的重要性质

MFC有两个非常重要的虚函数:于document有关的的serialize函数和与view有关的OnDraw函数

调用父类方法: rectangle.CShape::aa();

对于普通的方法,到底调用哪个方法是有指针的类型决定,而不是指针实际指向的对象.

CSquare square;
CSquare * pSquare;
CRectangle *pRectangle; pSquare = □
pRectangle = □
//调用各自的方法
pSquare->aa(); //CSquare.aa()
pRectangle->aa(); //CRectangle.aa()
 

而如果是虚拟函数则完全不同,实际调用的是指针实际指向的对象的方法.

CSquare square;
CSquare * pSquare;
CRectangle *pRectangle; pSquare = □
pRectangle = □
//调用实际指向的对象的方法
pSquare->aa(); //CSquare.aa()
pRectangle->aa(); //CSquare.aa()

纯虚函数:

virtual void aa()=0;//注意"=0"

纯虚函数不能有实现,它的存在只是为了在派生类中被重新定义.

拥有纯虚函数的类,就是抽象类,它是不能够被实例化的.

如果一个抽象类的子类没有实现它的纯虚函数,那么这个子类也是一个抽象类,不能被实例化.

虚函数派生下去仍为虚函数,而且可以省略virtual关键字

static成员不属于对象的一部分,而是类的一部分.

不要把static成员变量的初始化操作安排在构造函数里,因为构造函数可能多次调用,而变量的初始值却只应该设定一次.

可在类以外的任何位置初始化,比如main,全局函数等:

double SavingAccount::m_rate = 0.0075;注意SavingAccount的类型也出现在初始设定句里.

初始化static成员变量时,不受任何存取权限的束缚.

如果要在产生对象钱存取类的private static成员变量,需要一个static成员函数,如setRate:

public:

static setRate(double newRate){m_rate = newRate};

new不但分配对象所需的空间,同时还会引发构造函数的执行.

当派生类的对象诞生之时,构造函数的执行是由最基类至最尾端派生类.当对象要毁灭前,析构函数的执行顺序则是反其道而行.

C++的template有两种,一种针对function,另一种针对class.

使用RTTI,注意事项:

1.编译时需选用 /GR选项(/GR的意思就是enable C++ RTTI)

2.include typeinfo.h

3.使用typeid运算子.

三.MFC六大关键技术之仿真

宏定义中的#,##:

#:宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing operator),简单说就是在它引用的宏变量的左右各加上一个双引号。

##:它可以拼接符号(Token-pasting operator)(可以拼接表达式)

但有小问题要注意,宏中遇到#或##时就不会再展开宏中嵌套的宏了。什么意思了?比如使用char *pChar =STRING(__FILE__);虽然__FILE__本身也是一个宏,但编译器不会展开它,所以pChar将指向"__FILE__"而不是你要想的形如"D:\XXX.cpp"的源文件名称。因此要加一个中间转换宏,先将__FILE__解析成"D:\XXX.cpp"字符串。

CCmdTarget及其子类才具有消息处理能力.

类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变。

消息传递时:先调用OnCommand,然后Cwnd的OnCommand调用OnCmdMsg

处理CFrameWnd的WM_COMMAND的顺序:

1.AfxWndProc

2.AfxCallWndProc

3.CWnd::WindowProc

4.CFrameWnd:: OnCommand

5.CWnd:OnCommand

6.CFrameWnd::OnCmdMsg

7.CFrameWnd::GetActiveView

8.CView::OnCmdMsg()

9.CCmdTarget::OnCmdMsg()

五.

Map可视之为表格,由成对的两两对象所构成,很容易由一对象得知成对的另一对象.

数据处理类(CArray,CList,CMap及其子类)都支持Serialization,只需使用很少代码就可以读写到文件.

CTime:表现绝对时间.取得当前时间:GetCurrentTime

CTimeSpan:以秒数表示时间.

只有派生自CWnd的类才能收到WM_XXXX窗口消息(WM_COMMAND除外)

CWnd的成员变量m_hWnd就是窗口handle.

CDocTemplate,CSingleDocTemplate,CMultiDocTemplate:

Document Template扮演黏胶的角色,把Document,View,Frame胶黏在一起.CSingleDocTemplate一次只支持一种文件类型,CMultiDocTemplate可同时支持多种文件类型.注意,这和MDI程序或SDI程序无关,换句话说,MDI程序也可以使用CSingleDocTemplate,SDI程序也可以使用CMultiDocTemplate.

所有派生自CObject的类,都能取得运行时的类信息(RTTI),Serialization(文件读写),动态产生对象等.

应用程序一定要改写虚拟函数InitInstance,因为它在CWinApp中只是个空函数.

窗口创建过程:

//1.
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd();
return TRUE;
} //2.
CMyFrameWnd::CMyFrameWnd()
{ //2
Create(NULL,"Hello MFC",WS_OVERLAPPEDWINDOW ,rectDefault,NULL,NULL);
} //3.
CFrameWnd::Create() //4.
CWnd::CreateEx()//调用PreCreateWindow来给于程序员修改窗口类的机会.然后创建windows窗口 //5
CFrameWnd::PreCreateWindow()//注册窗口类,子类可覆写此函数以修改该窗口类.

MAKEINTRESOURCE:通过ID获得资源字符串名称

修改默认的窗口类:

覆写PreCreateWindow,在此实现里:先调用基类的方法:CFrameWnd::PreCreateWindow,之后利用GetClassInfo获得窗口类的副本,更改这个窗口类,再以AfxRegisterClass重新注册.(注意窗口类只需要注册一次,声明一个静态变量来区分是否注册需要的窗口类)

消息第一时间并不是由窗口处理,而是由全局函数AfxWndProc处理

MFC把消息主要分为三大类:

1.标准Windows消息(除了WM_COMMAND外的WM_XXX),派生自CWnd的类,都可以接收这类消息.

2.命令消息WM_COMMAND.凡由UI对象产生的消息都是这种命令消息,可能来自菜单或加速键或工具栏按钮.凡派生于CCmdTarget的类,都可以接收这类消息.

3.Notification消息.这类消息由控件产生,为的是向其父窗口(通常是对话框)通知某种情况.例如当在Listbox上选择一个项目,ListBox就会产生LBN_SELCHANGE传递给父创库哦.这类消息消息也是以WM_COMMAND形式呈现.

如果类的成员函数是一个callback函数,必须声明它为static.这样才能让编译器不给成员函数添加隐藏参数this.

覆写CWinApp的OnIdle可在空闲时处理别的事情.

七.

CDocument可以简单的看成负责处理数据的类.它一般和CView搭配使用.

有关文件读写的操作在CDocument的Serialize函数中进行,有关画面显示的操作在CView的OnDraw或OnPaint函数中进行.

构建MDI主窗口,有两个步骤:

1.new一个CMDIFrameWnd对象

2.调用这个对象的LoadFrame函数.

LoadFrame内部将调用Create,后者将调用CreateWindowEx.

View是Document对外显示的接口,但它并不能独立,它必须依存在一个所谓的Document Frame窗口内.

一份Document可以映射给许多个Views显示,不同的Views可以对应到同一份巨大的Document的不同局部.

在CMyDoc中改写Serialize,从而实现文件的存取操作.

让CChildFrame一开始显示的时候就为最大化:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_VISIBLE | WS_MAXIMIZE; if( !CMDIChildWnd::PreCreateWindow(cs) )
return FALSE; return TRUE;
}

CSingleDocTemplate只支持一种文件类型,而CMultiDocTemplate支持多种文件类型,就如他们的成员函数:

class CSingleDocTemplate:public CDocTemplate
{
protected:
CDocument * m_pOnlyDoc;
}; class CMultiDocTemplate:public CDocTemplate
{
protected:
CPtrList m_docList;
};

CDocTemplate,CDocument,CFrameWnd,CView之间的关系:

CWinApp拥有一个对象指针:CDocManager * m_pDocManager.

CDocManager拥有一个指针链表CPtrList m_templateList,用来维护一系列的Document Template.一个程序若支持两种文件类型,就应该有两份Document Templates,应用程序应该在CMyWinApp::InitInstance中以AddDocTemplate将这些Document Templates加入到由CDocManager所维护的链表里.

CDocTemplate拥有三个成员变量,分别持有Document,Frame,View的CRuntimeClass指针,另有一个成员变量m_nIDResource,用来表示此Document显示时应该采用的UI对象.这四份数据应该在CMyWinApp::InitInstance函数构造CDocTemplate时指定,成为构造函数的参数.但使用者欲打开一份文件,CDocTemplate即可借由Document/Frame/View之RumtimeClass指针进行动态创建.

CDocment有一个成员变量CDocTemplate * m_pDocTemplate,回指其Document Template,另有一个成员变量CPtrList m_viewList,表示它可以同时维护一系列的Views.

CFrameWnd有一个成员变量CView * m_pViewActive,指向当前活动的View.

CView有一个成员变量CDocument * m_pDocument,指向相关的Document.

在Win7下使用VC6.0绘图时,如果所绘内容不能及时显示,需要关掉视觉效果的”启用桌面组合”

CDocument::SetModifiedFlag():设置后,说明文档有改动.

当点击”File/Open”或”File/New”时,就会产生一组Document/View/Frame

CharLower:将字符串转换为小写

CharUpper:将字符串转换为大写

Serializable的必要条件:

1.从CObject派生下来.

2.类的声明必须有DECLARE_SERIAL宏

3.类的实现部分必须有IMPLEMENT_SERIAL宏

4.改写Serialize虚函数.

5.此类必须有一个default构造函数(也就是无参数构造函数)

CObject提供了一个虚函数IsSerializable(),让程序在运行时判断某类的schema号码是否为0XFFFF,借此得知它是否可以Serialize.

当一个Document对应多个View时,如果其中一个View修改了内容(Document的内容相应有更改),这时其他的View并不会自动更新,需要做下面的工作才能让其他的View反映新内容:

1.在合适位置调用CDocument::UpdateAllViews,这个函数会遍历所有隶属的Views,并通知他们(就是调用View的OnUpdate).

2.CView::OnUpdate:可以把更新的工作放到这里.

九.

和消息处理有关的的函数AfxWndProc ,AfxCallWndProc ,WindowProc,OnCommand,OnCmdMsg,DefWindowProc

static CWnd* PASCAL FromHandlePermanent(HWND hWnd);//通过窗口句柄返回CWnd指针.

CDC::FromHandle(HDC hDC)同样也可以通过HDC获得CDC*.

在窗体创建前(CreateEx函数里)调用AfxHookWindowCreate函数将窗口函数偷换为AfxWndProc.所以一切消息的起源是从AfxWndProc开始.

AfxWndProc –>AfxCallWndProc –>pWnd->WindowProc->CWnd::OnWndMsg

OnWndMsg是用来分辨并处理消息的专职机构(区分WM_COMMAND,WM_NOTIFY,普通消息,自定义消息).

CWnd::GetStyle():获得窗体的类型(请参考GetWindowLong)

CWinThread不会处理消息.见BEGIN_MESSAGE_MAP(CWinApp,CCmdTarget);

虚拟函数CWnd::OnCommand区分了WM_COMMAND类别,并调用了CWnd::OnCmdMsg();

CFrameWnd处理WM_COMMAND消息流程:

CWnd:OnWndMsg –> CFrameWnd::OnCommand –> CWnd:OnCommand  -> CFrameWnd::OnCmdMsg –> (GetActiveView()->OnCmdMsg) –> CWnd::OnCmdMsg  -> (theApp->OnCmdMsg)

分支1(GetActiveView()->OnCmdMsg)->(GetDocument()->OnCmdMsg)

分支2 CDocument::OnCmdMsg)->CCmdTarget::OnCmdMsg

CFrameWnd::OnCmdMsg:调用顺序View.OnCmdMsg,CWnd::OnCmdMsg,pApp->OnCmdMsg()(如果其中一个处理OnCmdMsg成功,不会再处理之后的OnCmdMsg)

CWnd并未改写OnCmdMsg,所以CWnd::OnCmdMsg其实就是CCmdTarget::OnCmdMsg

OnCmdMsg是专门用来处理命令消息的函数.

十.

CDialog的数据验证在DoDa;taExchange函数里进行

不让多文档应用程序启动的时候自动创建窗体:

在合适位置增加代码:cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing,如下:

BOOL CScribbleApp::InitInstance()
{
//......
    cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;//启动的时候不自动创建一个新child窗口
if (!ProcessShellCommand(cmdInfo))
return FALSE;
    pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow(); return TRUE;
}

十一.

BOOL IntersectRect( LPCRECT lpRect1, LPCRECT lpRect2 );

比较两个矩形是否有交集.

CRect::InflateRect

增大或减小矩形

要使View窗口具备滚动条,必须做下列事情:

1.定义Document的大小

2.以CScrollView取代CView

3.只要Document的大小改变,就要将尺寸传给CScrollView的SetScrollSizes函数.如果程序设定Document为固定大小,那么当然只需要一开始做一次滚动条设定操作即可.

4.注意装置坐标(窗口坐标)和逻辑坐标(Document坐标)的转换.

CView::OnInitialUpdate

这个函数在View第一次附着到Document但尚未显示时,有Framework调用.它会调用OnUpdate,不带任何Hint参数.

MFC笔记的更多相关文章

  1. MFC笔记10

    1. CDC MemDC1; MemDC1.SetBkMode(OPAQUE); 背景模式,VC6下面有三种:/* Background Modes */#define TRANSPARENT 1// ...

  2. MFC笔记7

    1.VS中显示行号 工具 -> 选项 -> 文本编辑器 -> C/C++ -> 行号 2.VS中调整字体大小 工具 -> 选项 -> 环境->字体和颜色 3. ...

  3. MFC笔记6

    1.MFC文件的读写操作 写操作 创建一个编辑框(IDC_INFOR_EDIT1),在里面输入信息,创建一个按钮(IDC_BUTTON),点击按钮会触发(OnBnClickedButton2()函数) ...

  4. MFC笔记5

    1.MessageBox()             引用自(http://www.douban.com/note/40199603/) 一 函数原型及参数 function MessageBox(h ...

  5. MFC笔记3

    1. C6有默认的提示代码功能,但是其默认的快捷键是Ctrl + Space,这一般情况下是切换输入法快捷键,所以,只需重新设置一下快捷键就可以实现提示代码功能,具体设置位置如下: 工具(T) -&g ...

  6. MFC笔记2

    1.Create()函数创建,该函数原型如下: BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* ...

  7. MFC笔记1

    1.在对话框文档中定义两个定时器,每间隔5秒弹出一个消息框提示“定时器1”,每隔5秒弹出一个消息框提示“定时器2” UINT ID_TIMER1 = 1 , ID_TIMER2 = 2;   //设置 ...

  8. MFC笔记(DN)

    01:MFC应用程序编程 02:MFC菜单.工具栏.状态栏 03:视图窗口

  9. MFC笔记<持续更新>

    1.设置垂直滚动条的位置在末尾 SCROLLINFO si; GetScrollInfo(SB_VERT, &si, SIF_PAGE | SIF_RANGE | SIF_POS); si.f ...

随机推荐

  1. POJ 3922 A simple stone game

    题目: E - A simple stone game Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d &am ...

  2. 在html使用a标签 直接下载图片 不通过后台实现直接下载

    由于a标签在HTML中链接图片会被识别并打开到网页上 如果想下载这个图片的话 就需要连接到后台读取文件并生成一个头信息下载.不过可以先给a标签加上一个download属性即可直接下载了. <a ...

  3. 在网上浏览.NET的所有代码,并且让你的Visual Studio的go to definition(F12)指向在线代码

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:在网上浏览.NET的所有代码,并且让你的Visual Studio的go to definition(F ...

  4. Day 2 @ RSA Conference Asia Pacific & Japan 2016

    上午有两场summits,议题分别是: sum-w01: G2B: Cyber-Business in Myanmar, Indonesia and Thailand sum-w02: Achievi ...

  5. Day 3 @ RSA Conference Asia Pacific & Japan 2016 (morning)

    09.00 – 09.45 hrs Tracks Cloud, Mobile, & IoT Security    A New Security Paradigm for IoT (Inter ...

  6. eclipse package,source folder,folder区别及相互转换

    今天遇到一个问题:在com.a.b.c这个包路径下建一个package,但是不知为什么就会自动编程folder,而且在这个“package”下的所有property文件读不到.所以看了一下文章:在ec ...

  7. strcmp函数和strcpy函数

    (一)strcmp函数 strcmp函数是比較两个字符串的大小,返回比較的结果.一般形式是: i=strcmp(字符串,字符串); 当中,字符串1.字符串2均可为字符串常量或变量:i   是用于存放比 ...

  8. (转)Java Ant build.xml详解

    1,什么是ant ant是构建工具2,什么是构建概念到处可查到,形象来说,你要把代码从某个地方拿来,编译,再拷贝到某个地方去等等操作,当然不仅与此,但是主要用来干这个3,ant的好处跨平台   --因 ...

  9. Java Stax操作XML简介

    使用stax操作xml 非常的简单,它的读取过程像是一个光标在移动.针对不同的节点做不同的处理. 先看一个基于光标的模型处理xml: public class StaxTest { @Test pub ...

  10. Objective-C:内存管理

    1 传统内存管理 Objective-C对象的生命周期可以分为:创建.存在.消亡. 1.1 引用计数 类似Java,Objective-C采用引用计算(reference counting)技术来管理 ...