一MFC 的概念和作用
1 什么是MFC?
全称Microsoft Foundation Class Library 我们称之为
微软基础类库,封装了绝大部分WIN32 api 函数,还封装
了程序流程。
1.1 硬盘存在形式就是一个库(静态库/动态库)
1.2 原理上还是一个程序框架
2 为什么使用MFC?
基于框架编程,提供工作效率,减少开发周期,节约开发
成本。
二几个重要头文件
afx.h - MFC 绝大部分类的声明
afxwin.h - 包含了afx.h 和windows.h
afxext.h - 包含了对扩展窗口类的支持
例如:工具栏,状态栏等...
附:******************
以Afx...开头的函数,可以确定为MFC 库中封装的全局函数
以::....开头的函数,可以确定为win32 API 函数
三使用MFC 制作程序的类型
1 使用MFC 库制作控制台程序
CWinApp theApp; - 多了全局变量
入口函数不同于以往main 函数
2 使用MFC 库制作静态库程序
3 使用MFC 库制作动态库程序
3.1 使用MFC 库制作自己的规则动态库
3.2 使用MFC 库制作自己的扩展动态库
区别:规则库可以被任何程序调用,扩展库只能被支持
MFC 的程序调用。
4 使用MFC 库制作自己窗口程序
单文档视图构架程序
CFrameWnd - 框架窗口类,封装了对框架窗口操作。
CWinApp - 应用程序类,负责管理程序流程。
CDocument -
文档类,负责管理数据(提取/转换/存储数据)
CView - 视图窗口类,负责管理视图窗口。
多文档视图构架程序
CMDIChildWnd - 子框架窗口类,负责管理子框架窗口
CMDIFrameWnd - 主框架窗口类,负责管理主框架窗口
CWinApp - 应用程序类,负责管理程序流程。
CDocument -
文档类,负责管理数据(提取/转换/存储数据)
CView - 视图窗口类,负责管理视图窗口。
对话框构架程序
CDialog - 对话框窗口类,负责管理对话框窗口
CWinApp - 应用程序类,负责管理程序流程。
四MFC 类的概述
1 CObject - MFC 库中绝大部分类的最基类
运行时类信息机制
动态创建机制
序列化机制
2 CCmdTarget - 消息映射机制的最基类
3 CWinThread/CWinApp - 应用程序类,负责程序流程
4 CDocument 及其子类- 文档类,负责管理数据。
5 Exceptions - 异常类,封装MFC 库中各种异常情况。
6 CFile 及其子类- 文件操作类,封装了读写文件的API
7 CWnd - 窗口类的最基类
8 Frame Windows - 框架窗口类,负责管理各种框架窗口
9 CDialog 及其子类- 对话框窗口类,负责管理各种对话框
对话框。
10 Views - 视图窗口类,负责管理各种视图窗口
11 Controls - 控件窗口类,负责管理各种控件窗口
12 CDC/CGdiObject 及其子类- 封装了绘图相关API 函数
13 CArray / CMap / CList 及其子类- 封装了C++语法中
相应的结构。
14 非CObject 类- 封装一些常用数据结构
五第一个MFC 程序
1 配置环境
1.1 删除入口WinMain
1.2 将头文件更改为<afxwin.h>。
1.3 Project->Settings 中设置使用MFC 库。
2 代码的书写
从CFrameWnd 类派生自己的框架窗口类(CMyFrameWnd)
从CWinApp 类派生自己的应用程序类(CMyWinApp)
重写了CWinApp::InitInstance(虚函数)
3 程序执行过程
3.1 构造theApp 对象CWinApp::CWinApp()
1)将&theApp 保存到当前程序模块状态信息中
2)将&theApp 保存到当前程序线程状态信息中
3)AfxGetApp/AfxGetThread - 返回&theApp
3.2 程序流程(WinMain)
1)利用AfxGetApp/AfxGetThread 获取&theApp
2)利用&theApp 调用应用程序类成员虚函数
InitApplication(初始化)
3)利用&theApp 调用应用程序类成员虚函数
InitInstance(创建、显示窗口)
4)利用&theApp 调用应用程序类成员虚函数
Run(消息循环)
4.1 利用&theApp 调用应用程序类成员虚函数
OnIdle(空闲处理)
4.2 利用&theApp 调用应用程序类成员虚函数
ExitInstance(善后处理)
关系************************
theApp
|->m_pMainWnd(pFrame 框架类对象地址)
AFX_MODULE_STATE aaa;//当前程序模块状态信息
AFX_MODULE_THREAD_STATE bbb;//当前程序线程状态信息
//构造theApp 对象
CWinApp::CWinApp(...)
{
AFX_MODULE_STATE* pModuleState=AfxGetModuleState()
//获取全局变量&aaa
AFX_MODULE_THREAD_STATE* pThreadState =
pModuleState->m_thread;
//获取全局变量&bbb
pThreadState->m_pCurrentWinThread = this;
//将&theApp 保存到全局变量bbb 的一个成员中
AfxGetThread()
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
//获取全局变量&bbb
CWinThread* pThread = pState->m_pCurrentWinThread;
//获取&theApp
return pThread;
}
pModuleState->m_pCurrentWinApp = this;
//将&theApp 保存到全局变量aaa 的一个成员中
AfxGetApp()
{
return AfxGetModuleState()->m_pCurrentWinApp;
}
}
****************************************
//体会是不是theApp 对象指导流程。
WinMain(...)
{
AfxWinMain(...)
{
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();//以上两句获取&theApp
pApp->InitApplication();
//利用theApp 对象调用CWinApp 类成员虚函数(初始化)
pThread->InitInstance();
//利用theApp 对象调用应用程序类的成员虚函数
pThread->Run()
//利用theApp 对象调用应用程序类的成员虚函数(消息循环)
{
CWinThread::Run()//函数内部this 为&theApp
{
while(没有消息)
{
this->OnIdle(...);//应用程序类成员虚函数(空闲处理)
}
do
{
if( GetMessage 抓到WM_QUIT)
return ExitInstance();
//应用程序类成员虚函数(善后处理)
}while(...)
}
}
}
}
Day 02
一窗口创建
1 加载菜单
2 调用CreateEx 注册窗口类,创建窗口
2.1 调用PreCreateWindow 设计并注册窗口类
WNDCLASS wndcls;
....
wndcls.lpfnWndProc = DefWindowProc;
最终调用win32 API 函数RegisterClass 注册了一个窗口类
2.2 调用AfxHookWindowCreate 函数
1)将pFrame(自己new 的框架类对象地址)保存到当前程序
线程信息中。
2)利用::SetWindowsHookEx 函数在程序中埋下一个钩子,
类型为WH_CBT.
2.3 利用win32 API 函数::CreateWindowEx 创建窗口,此函数
一旦执行触发钩子处理函数
3 钩子处理函数
3.1 将自己new 框架类对象地址和窗口句柄建立一对一的
绑定关系。
m_hWnd = hWnd - 通过pFrame 可以获取窗口句柄
m_permanentMap[hWnd] = pFrame
通过窗口句柄可以获取pFrame
3.2 利用win32 API 函数::SetWindowLong 将窗口处理函数更
改为AfxWndProc(真正窗口处理函数)
_afxWndFrameOrView==="AfxFrameOrView42sd"
CMyFrameWnd *pFrame = new CMyFrameWnd;
pFrame->Create( NULL, "MFCCreate" )//函数内部this 为pFrame
{
//加载菜单
CreateEx( ..,NULL..)//函数内部this 为pFrame
{
CREATESTRUCT cs;
cs.lpszClass = NULL;//下边将更改
......
cs.hInstance = AfxGetInstanceHandle();
PreCreateWindow(cs)
{
AfxDeferRegisterClass(...)
{
WNDCLASS wndcls;
....
wndcls.lpfnWndProc = DefWindowProc;//下边更改
_AfxRegisterWithIcon(&wndcls,"AfxFrameOrView42sd")
{
&wndcls->lpszClassName = "AfxFrameOrView42sd";
AfxRegisterClass(&wndcls)
{
::RegisterClass(&wndcls);
}
}
}
cs.lpszClass = "AfxFrameOrView42sd";
} AfxHookWindowCreate(pFrame)//参
数
为
自
己
new 的
框
架
类
对
象
地
址
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
//获取全局变量&ccc(当前程序线程信息)
::SetWindowsHookEx(WH_CBT...);
//在程序中埋下一个类型为WH_CBT 的钩子
pThreadState->m_pWndInit = pFrame;
//将自己new 的框架类对象地址pFrame 保存到ccc 的一个成员中
} ::CreateWindowEx(...);//此
函
数
一
旦
执
行
WM_CREATE 消
息
出
现
//立即被钩子勾到钩子处理函数中。
}
}
*********************************************************
//钩子处理函数
_AfxCbtFilterHook(...wParam..)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
//获取全局变量&ccc
CWnd* pWndInit = pThreadState->m_pWndInit;
//从ccc 中获取pFrame===pWndInit
HWND hWnd = (HWND)wParam;//获取窗口句柄
pWndInit->Attach(hWnd)//函数内部this 为pFrame===pWndInit
{
CHandleMap* pMap = afxMapHWND(TRUE)
{
AFX_MODULE_THREAD_STATE* pState =
AfxGetModuleThreadState();
//获取全局变量&bbb
pState->m_pmapHWND = new CHandleMap(...);
//将new 出来的映射类对象地址保存bbb 的一个成员中
return pState->m_pmapHWND;
}
pMap->SetPermanent(m_hWnd = hWnd, pFrame)
//函数内部this 为pMap(映射类对象地址)
{
m_permanentMap[hWnd] = pFrame;
}
}
WNDPROC afxWndProc = AfxGetAfxWndProc();
//获取AfxWndProc 函数的地址
::SetWindowLong(hWnd, GWL_WNDPROC,(DWORD)afxWndProc);
//将窗口处理函数更改为AfxWndProc(真正的窗口处理函数)
}
***************************************************
以WM_CREATE 消息为例
AfxWndProc(....)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd)
{
CHandleMap* pMap = afxMapHWND()
{
AFX_MODULE_THREAD_STATE* pState =
AfxGetModuleThreadState();
//获取&bbb
return pState->m_pmapHWND;
//返回上边保存的映射类对象地址
}
pWnd = (CWnd*)pMap->LookupPermanent(hWnd)
//函数内部this 为pMap(映射类对象地址)
{
return m_permanentMap[hWnd];//获取pFrame
}
} AfxCallWndProc(pWnd...)//参
数
的
pWnd===pFrame
{
pWnd->WindowProc(...)
{
//回到自己代码
}
}
}
Day 03
一MFC 消息映射机制(3)
1 消息映射机制的使用
1)类必须从CCmdTarget 类派生
2)类内必须添加声明宏DECLARE_MESSAGE_MAP()
3) 类外必须添加实现宏
BEGIN_MESSAGE_MAP( theClass, baseClass )
END_MESSAGE_MAP( )
2 消息映射机制的实现
2.1 数据结构
struct AFX_MSGMAP_ENTRY(静态数组每个元素类型)
{
UINT nMessage; // 消息ID
UINT nCode; // 通知码
UINT nID; // 命令ID/控件ID
UINT nLastID; // 最后一个控件ID
UINT nSig; // 消息处理函数的类型
AFX_PMSG pfn; // 消息处理函数的地址(指针)
};
struct AFX_MSGMAP(静态变量类型)
{
const AFX_MSGMAP* pBaseMap;//
const AFX_MSGMAP_ENTRY* lpEntries;//
};
2.2 宏展开
见代码
2.3 宏展开各部分的作用
_messageEntries[] - 静态数组
每个元素保存消息ID 对应的消息处理函数的指针
messageMap - 静态变量
负责获取父类静态变量地址(连接链表)
负责获取相应类的静态数组首地址
GetMessageMap() - 虚函数
获取本类静态变量地址(获取链表头节点)
2.4 消息映射机制的执行过程
1)利用框架类对象(pFrame)调用GetMessageMap 获取链表
头节点(本类静态变量地址)pMessageMap
2)利用pMessageMap 的第二个成员获取相应类的静态数
组首地址,在数组中查找消息ID 对应处理函数指针
如果找到了4,如果没找到执行3
3)利用pMessageMap 的第一个成员获取父类静态变量地址
如果为NULL,结束查找,如果不为NULL 执行2
4)利用找到的这个数组元素的第六个成员
(消息处理函数地址)完成消息的处理。
二MFC 消息的分类
1 windows 标准例如:键盘/鼠标/定时器....
ON_WM_XXX
2 自定义消息
#define WM_MYMESSAGE WM_USER+n
ON_MESSAGE
3 命令消息(WM_COMMAND)
ON_COMMAND
ON_COMMAND_RANGE( 起始ID,终止ID,处理函数)
//以WM_CREATE 消息为例(想着点WM_COMMAND/WM_PAINT)
AfxWndProc(...)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
//获取和hWnd 绑定在一起框架类对象地址(pFrame===pWnd)
AfxCallWndProc(pWnd..)//参数pWnd===pFrame
{
pWnd->WindowProc(...)//函数内部this 为pFrame===pWnd
{
OnWndMsg(...)//函数内部this 为pFrame===pWnd
{
const AFX_MSGMAP* pMessageMap = GetMessageMap();
//获取链表头节点(本类静态变量地址)
AFX_MSGMAP_ENTRY* lpEntry;
for (; pMessageMap != NULL;//遍历链表找东西
pMessageMap = pMessageMap->pBaseMap)
{
lpEntry = AfxFindMessageEntry
(pMessageMap->lpEntries,message...);
if( lpEntry != NULL )
{
goto LDispatch;
}
}
LDispatch:
union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn;//获取&OnCreate
int nSig = lpEntry->nSig;//AfxSig_lwl
switch (nSig)
{
case AfxSig_lwl:
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
break;
.....
}
}
}
}
}
Day 04
一MFC 的菜单
1 相关类
WIN32 - HMENU
MFC - CMenu 类对象
CMenu - 封装了操作菜单的各种API 函数,还封装了很重要成员
m_hMenu(保存菜单句柄)
2 菜单使用
2.1 添加菜单资源
2.2 设置菜单(将菜单挂到窗口中)
1)在创建主框架窗口的(Create)过程中
2)在框架窗口的WM_CREATE 消息处理中
CMenu menu;
menu.LoadMenu
CFrameWnd::SetMenu
2.3 设置菜单项状态
ON_WM_INITMENUPOPUP
::CheckMenuItem / CMenu::CheckMenuItem
::EnableMenuItem / CMenu::EnableMenuItem
2.4 命令消息(WM_COMMAND)的处理顺序
Frame-->App(CFrameWnd::OnCmdMsg 函数执行先后顺序决定)
2.5 上下文(右键)菜单
ON_WM_CONTEXTMENU
::TrackPopupMenu / CMenu::TrackPopupMenu
二工具栏
1 相关类
CToolBarCtrl - 父类为CWnd,封装了关于工具栏控件的操作
CToolBar - 父类为CControlBar,封装工具栏和框架窗口
之间的关系,包含工具栏的创建
2 工具栏的使用
2.1 添加工具栏资源
2.2 创建工具栏
CToolBar::Create / CToolBar::CreateEx
2.3 加载工具栏资源
CToolBar::LoadToolBar
2.4 工具栏的停靠(船坞化)
1)工具栏准备停靠CToolBar::EnableDocking
2)框架窗口允许停靠CFrameWnd::EnableDocking
3)框架窗口确定停靠位置
CFrameWnd::DockControlBar
2.5 工具栏的显示和隐藏
CFrameWnd::ShowControlBar
CWnd::IsWindowVisible - 可以判断窗口显示/隐藏状态
2.6 工具栏
CBRS_TOOLTIPS - 工具栏具有标签提示
CBRS_GRIPPER - 把手/夹子
CBRS_SIZE_DYNAMIC - 工具栏可以变形
练习:添加一个菜单“工具栏”
1 当工具栏显示菜单项勾选, 工具栏隐藏菜单项非勾选
2 菜单项每点击一次工具栏显示/隐藏状态切换一次
3 不要任何变量
三状态栏
1 相关类
CStatusBar - 父类CControlBar,封装了状态各种操作,以及
状态栏的创建
2 状态栏的使用
2.1 创建状态栏
CStatusBar::Create / CStatusBar::CreateEx
2.2 设置状态栏指示器
CStatusBar::SetIndicators
2.3 设置指示器的风格和宽度
CStatusBar::SetPaneInfo
2.4 设置指示器的文本内容
CStatusBar::SetPaneText
Day 05
一视图窗口
1 相关问题
MFC 视图窗口- 提供了一个用于显示数据窗口,和用户进行交互
相关类CView 及其子类- 父类CWnd
2 视图窗口的使用
2.1 代码的书写
1)从CView 派生了一个自己的视图窗口类(CMyView)并重写
父类纯虚函数OnDraw
2)new 了CMyView 类对象,并利用这个对象调用Create 函数
完成视图窗口的创建
3)第一个视图窗口的ID,一般AFX_IDW_PANE_FIRST
关系图:***************************
theApp
|->m_pMainWnd (pFrame)
|->m_pViewActive(pView)
3 命令消息(WM_COMMAND)处理顺序
View-->Frame-->App
(CFrameWnd::OnCmdMsg 函数执行先后决定)
二运行时类信息机制(4)
1 运行时类信息机制作用
程序在执行过程中可以获取对象相关类的信息
(对象是否属于该类)
2 运行时类信息机制使用
2.1 类必须从CObject 派生
2.2 类内必须添加声明宏DECLARE_DYNAMIC
2.3 类外必须添加实现宏IMPLEMENT_DYNAMIC
CObject::IsKindOf - 可以判断对象是否属于某个类
3 运行时类信息机制的实现
3.1 数据结构
struct CRuntimeClass (静态变量类型)
{
LPCSTR m_lpszClassName;//类名称
int m_nObjectSize; //类大小sizeof
UINT m_wSchema; //类的版本0XFFFF
CObject* (PASCAL* m_pfnCreateObject)();
//动态创建机制使用,运行时类信息机制为NULL
CRuntimeClass* m_pBaseClass;
//父类静态变量地址(用于连接链表)
CRuntimeClass* m_pNextClass;//为NULL
};
3.2 宏展开的代码
见代码
3.3 宏展开各部分的作用
classCDog - 静态变量
保存类的相关信息例如:类大小/名称/版本..
GetRuntimeClass() - 虚函数
获取本类静态变量地址(链表头节点)
3.4 IsKindOf 函数的执行过程
利用本类对象yellowdog 调用虚函数GetRuntimeClass 获取
本类静态变量地址(链表头节点)
利用本类静态变量地址与目标进行比对如果相等证明对象
属于该类,如果不相等循环比较
循环比较过程中只要有一次相等证明对象属于该类,循环
结束一次都不相等证明对象不属于该类
**************
RUNTIME_CLASS( theClass ) - 括号内的类的静态变量地址
(&theClass::classtheClass)
三动态创建机制(5)
1 作用
在不知道类名情况下,将类对象创建出来。
2 使用
2.1 类必须从CObject 类派生
2.2 类内必须添加声明宏DECLARE_DYNCREATE
2.3 类外必须添加实现宏IMPLEMENT_DYNCREATE
CRuntimeClass::CreateObject - 动态创建类对象
3 实现
3.1 区别(和运行时类信息机制比较)
classCDog - 静态变量
第四个成员不再为NULL,保存了一个静态函数的地址
函数的区别
多了一个静态函数CreateObject
3.2 作用
CreateObject() - 静态函数
new 了一个CDog 类的对象并返回对象地址
classCDog - 静态变量
将新增加静态函数CreateObject 的地址保存在第四个
成员中
GetRuntimeClass() - 虚函数
获取本类(CDog)的静态变量地址(链表头节点)
3.3 CRuntimeClass::CreateObject 执行过程
1)利用本类静态变量(classCDog)的第四个成员
2)调用成员中保存新增加静态函数(CDog::CreateObject)
完成对象的创建(这个函数内部new 了一个CDog 类的
对象,并返回对象地址)
四窗口切分
1 窗口切分的分类
动态切分- 程序在执行过程中根据用户的需要实时完成切分
最多2*2
静态切分- 窗口创建时就已经完成切分。
CSplitterWnd - 父类为CFrameWnd
2 静态切分
2.1 重写CFrameWnd::OnCreateClient 虚函数
2.2 在这个函数中调用
CSplitterWnd::CreateStatic(创建不规则框架窗口)
2.3 调用CSplitterWnd::CreateView 给不规则框架的客户区
设置视图窗口。
RUNTIME_CLASS(CDog)->CreateObject( )
//函数内部this 指针为&classCDog(链表头节点)
{
pObject = (*m_pfnCreateObject)()
//调用静态变量第四个成员(CDog::CreateObject)
{
return new CDog;
}
}
Day 06
一MFC 的文档
1 文档相关
提供了管理数据的功能,还封装了数据和视图窗口的操作。
CDocument - 父类CCmdTarget
2 创建窗口
2.1 利用pFrame 调用LoadFrame 创建框架窗口
2.2 框架窗口的WM_CREATE 消息处理中创建视图窗口
2.3 视图窗口的WM_CREATE 消息处理中将视图类对象和文档类
建立绑定关系
m_viewList.AddTail(pView);
pView->m_pDocument = this;
经过分析:
文档类用一个链表保存和它关联的视图类对象地址
可知一个文档类对象可以对应多个视图类对象
视图类用一个成员保存和它关联的文档类对象地址
可知一个视图类对象只能对应一个文档类对象
3 文档类和视图类的关系
CView::GetDocumment - 获取和视图对象相关联的文档类对象
CDocument::UpdateAllViews - 刷新和文档类对象关联的
视图类对象(视图窗口)能够调用
CView::OnUpdate
4 命令消息的传递(WM_COMMAND)
View-->Document-->Frame-->App
CMyFrameWnd *pFrame = new CMyFrameWnd;
CCreateContext cct;
cct.m_pCurrentDoc = new CMyDoc;
cct.m_pNewViewClass = RUNTIME_CLASS( CMyView );
pFrame->LoadFrame( ...., &cct )//函数内部this 为pFrame
{
Create(...., &cct )//函数内部this 为pFrame
{
CreateEx(...,&cct )//函数内部this 为pFrame
{
....
::CreateWindowEx(..,&cct);//创建主框架窗口,触发
//WM_CREATE 消息
}
}
}
**********************************************
//处理框架窗口的WM_CREATE 消息
CFrameWnd::OnCreate(lpcs)//函数内部this 为pFrame
{
CCreateContext* pContext = lpcs->lpCreateParams;
//重新获取&cct === pContext
OnCreateHelper(..., &cct )//函数内部this 为pFrame
{
OnCreateClient(.., &cct)//函数内部this 为pFrame
{
CreateView( &cct,..)//函数内部this 为pFrame
{
CWnd* pView=&cct->m_pNewViewClass->CreateObject();
//动态创建视图类对象并接受对象地址
pView->Create(..,&cct)//函数内部this 为pView
{
CreateEx(..,&cct)//函数内部this 为pView
{
......
::CreateWindowEx(...,&cct);//成功创建视图窗口
//触发视图窗口的WM_CREATE 消息
}
}
}
}
}
}
******************************************************
处理视图窗口的WM_CREATE 消息
CEditView::OnCreate(lpcs)//函数内部this 为pView
{
CCtrlView::OnCreate(lpcs)//函数内部this 为pView
{
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
//重新获取&cct
&cct->m_pCurrentDoc->AddView(pView)
//函数内部this 为文档类对象地址参数为视图类对象地址
{
m_viewList.AddTail(pView);
//文档类对象的一个链表成员保存视图类对象地址
pView->m_pDocument = this;
//视图类对象的一个普通成员保存文档类对象地址
}
}
}
**********************************************
//WM_COMMAND 传递路径
OnCommand(...)//函数内部this 为pFrame
{
CWnd::OnCommand(...)//函数内部this 为pFrame
{
OnCmdMsg(...)//函数内部this 为pFrame
{
pView->OnCmdMsg(...)//目的地- CCmdTarget::OnCmdMsg
//函数内部this 为pView
{
m_pDocument->OnCmdMsg()
//目的地- CCmdTarget::OnCmdMsg
}
CWnd::OnCmdMsg(..)//目的地- CCmdTarget::OnCmdMsg
//函数内部this 为pFrame
pApp->OnCmdMsg(...)//目的地- CCmdTarget::OnCmdMsg
//函数内部this 为&theApp
}
}
}
Day 07
1 马志国mazhiguo01@163.com
-------------------------------------
day01
什么是MFC? 框架类库
第一个机制:入口函数机制
day02
第二个机制:窗口创建机制
替换窗口处理函数,由MFC 提供
对象与窗口句柄绑定
day03
第三个机制:消息映射
ON_WM_
ON_COMMAND
ON_NOTIFY
ON_MESSAGE
day04
菜单、工具栏和状态栏
CMenu CToolBar CStatusBar
day05
视图
第四个机制:运行时类信息(CRuntimeClass),存在一个类的信息链表
第五个机制:动态创建(本质是new 对象)
通常的编程方式,程序员使用系统的类创建对象,调用成员函数完成
相关功能。有了动态创建,系统的代码可以创建程序员定义的类的
对象,换言之,底层代码可以创建上层类的对象。
day06
文档类-管理数据
切分窗口-CSplitterWnd,切分窗口类,完成动态切分或者静态切分
----------------------------------
day07
一单文档视图架构应用程序
1 相关类
CWinApp-应用程序类
CFrameWnd-框架窗口类,协调各个不同的类的工作
CView-视图类,显示数据,接收用户输入。
CDocument-文档类,管理数据。
MVC 架构-Model(文档类)、View(视图)、Controller 控制器(框架)。
引入文档模板类,可以以更加规则和优雅的方式创建应用程序。
CDocTemplate-文档模板类。
CSingleDocTemplate(
UINT nIDResource,//资源ID
CRuntimeClass* pDocClass,//文档类的运行时类信息
CRuntimeClass* pFrameClass,//框架类的运行时类信息
CRuntimeClass* pViewClass //视图类的运行时类信息
);
定义时,视图类、框架类和文档类都需要支持动态创建
2 断言宏的使用技巧
注意:将使用MFC 动态库修改为使用MFC 静态库时,遇到断言错误。
VERIFY、ASSERT 等都是MFC 的断言宏,确保宏的参数值为真。
3 单文档程序的创建过程
3.1 构造单文档模板对象
3.2 将文档模板对象添加到应用程序
AddDocTemplate(pTemplate);
{
//1 创建文档管理对象
if (m_pDocManager == NULL)
m_pDocManager = new CDocManager;
//2 将文档模板对象添加到文档管理对象中
m_pDocManager->AddDocTemplate(pTemplate);
{
...
//将模板对象的地址保存到链表中
m_templateList.AddTail(pTemplate);
}
}
3.3 新建文档
OnFileNew();
{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
{
//1 获取链表中保存的第一个文档模板对象的地址
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
//2 调用文档模板的函数新建文档
pTemplate->OpenDocumentFile(NULL);
{
//2.1 动态创建文档对象
pDocument = CreateNewDocument();
//2.2 动态创建框架对象和框架窗口
pFrame = CreateNewFrame(pDocument, NULL);
{
//2.2.1 动态创建框架对象
CFrameWnd* pFrame =
(CFrameWnd*)m_pFrameClass->CreateObject();
//2.2.2 创建框架窗口
pFrame->LoadFrame(m_nIDResource,...);
//2.2.3 当框架窗口创建时,产生WM_CREATE 消息,在
CFrameWnd::OnCreate()函数中,动态创建视图对象和窗口
//2.2.4 当视图窗口创建时,产生WM_CREATE 消息,在
CView::OnCreate()函数中,文档与视图相互保存对方的地址
}
}
}
}
4 类与类(对象与对象)之间的关系
CWinApp 类
|->m_pDocManager(CDocManager 类)
|->m_templateList (CDocTemplate 类)
|->CSingleDocTemplate
|->m_pOnlyDoc (CDocument 类)
|->m_pDocClass
|->m_pFrameClass
|->m_pViewClass
|->m_pMainWnd (CFrameWnd 类)
|->m_pActiveView (CView 类)
|->m_pDocument (CDocument 类)
|->m_viewList(CView 类)
总结:MFC 类与类之间的关系都是通过包含对方的地址产生的
5 处理命令消息的顺序
View->Document->Frame->App
6 使用MFC 向导生成文档视图应用程序时,根据项目的具体要求,
选择相应的选项,例如:是否需要文档类、选择哪个视图基类?
注意:一个文档可以对应多个视图,但是一个视图只能对应一个文档
二多文档视图架构应用程序
1 与单文档的区别:
可以同时管理多个文档
多文档有两个框架类,一个是主框架类,一个是子框架类。
主框架和子框架使用不同的菜单资源和图标资源
主框架窗口的菜单项至少是两项
Day 08
一多文档视图架构应用程序
1 与单文档的区别:
可以同时管理多个文档
多文档有两个框架类,一个是主框架类,一个是子框架类。
主框架和子框架使用不同的菜单资源和图标资源
主框架窗口的菜单项至少是两项
2 相关类
CWinApp
CMDIFrameWnd-多文档主框架类
CMDIChildWnd-多文档子框架类
CView/CEditView
CDocument
CMultiDocTemplate-多文档模板类
CMultiDocTemplate(
UINT nIDResource, //子框架的资源ID
CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass,//子框架类的运行时类信息
CRuntimeClass* pViewClass
);
文档、子框架和视图对象的创建是通过文档模板动态创建的
而主框架对象单独创建
3 创建过程
4 实现菜单功能
4.1"新建"-调用OnFileNew()函数即可,每调用一次该函数,文档
子框架与视图各创建一份。
4.2"新建视图"-只希望创建框架和视图,不创建文档,使用当前的
活动窗口对应的文档。最终效果一个文档对应多个视图。
1 获取活动的框架窗口
CFrameWnd::GetActiveFrame
2 获取活动视图
CFrameWnd::GetActiveView
3 获取视图对应的文档
CView::GetDocument
4 获取文档对应的文档模板对象
CDocument::GetDocTemplate
5 使用文档模板创建框架对象及窗口
CDocTemplate::CreateNewFrame
6 使得框架窗口的状态是显示的和活动的
CFrameWnd::InitialUpdateFrame
4.3 实现同一个文档的多个视图数据实时同步
4.3.1 编辑视图中数据发生变化的消息
ON_CONTROL_REFLECT(EN_CHANGE,...)
4.3.2 通知所有视图数据更新
CDocument::UpdateAllViews
4.3.3 视图更新函数(虚函数,可重写)
CView::OnUpdate
二MFC 绘图
1 绘图设备类
决定图形绘制到哪儿,相当于绘图的纸。
1.1 CDC 类
绘图设备类的顶层父类。封装了一般的绘图设备,例如:
打印机、显示器等。
1.2 CWindowDC 类
父类是CDC 类,封装的是指定窗口的区域。包括窗口的
客户区和非客户区。
1.3 CClientDC 类
父类也是CDC 类,封装的也是指定窗口的区域,但是只
包含客户区。
1.4 CPaintDC 类
父类也是CDC 类,封装的也是指定窗口的区域,也是只
包含客户区。只能用在WM_PAINT 的消息处理函数中。
1.5 CMetaFileDC 类
父类也是CDC 类,与其它DC 区别最大,保存绘制命令的DC。
保存后,可以通过它重新执行绘制命令绘制图形。
2 CDC 类的使用
2.1 创建DC
virtual BOOL CreateDC(
LPCTSTR lpszDriverName,//设备的驱动名称
LPCTSTR lpszDeviceName,//设备的名称
LPCTSTR lpszOutput, //设备接口
const void* lpInitData//初始化参数
);
如何是显示器设备:
CreateDC("DISPLAY",NULL,NULL,NULL);
2.2 使用
2.3 删除DC
CDC::DeleteDC
3 CWindowDC/CClientDC 的使用
直接构造即可使用
4 CPaintDC
右击窗口类添加WM_PAINT 的消息处理函数使用即可
5 CMetaFileDC 的使用
5.1 创建DC
CMetaFileDC::CreateDC
5.2 在DC 上绘制
5.3 关闭,返回句柄
CMetaFileDC::Close
5.4 使用保存的绘制命令(可以使用多次)
CDC::PlayMetaFile
5.5 删除DC
DeleteMetaFile
绘图对象类
决定使用什么对象绘制,相当于绘图的笔。
Day 09
一MFC 绘图对象
1 相关类
1.1 CPen-画笔
1.2 CBrush-画刷
1.3 CFont-字体
1.4 CBitmap-位图
1.5 CPalette-调色板,引入调色板可以减少位图所占的空间大小
RGB(0~255,0~255,0~255),24 位真彩色
800*600 的位图,RGB 表示,800*600*3
800*600 的位图,使用调色板(使用颜色表中索引值表示颜色),
800*600*1
1.6 CRgn-区域,可以通过将两个不同的区域进行几何运算得到
复杂的区域,而且,可以进行多次几何运算。
2 使用
2.1 画笔、画刷和字体的使用步骤:
2.1.1 构造或者创建绘图对象
2.1.2 将绘图对象选入到绘图设备中
2.1.3 使用绘图对象绘制图形
2.1.4 还原默认的绘图对象
2.1.5 删除绘图对象
2.2 位图的使用步骤
2.2.1 定义位图对象,并加载位图资源
2.2.2 创建与当前dc 兼容的dc
2.2.3 将位图对象选入到兼容dc
2.2.4 将位图从兼容dc 拷贝到当前dc
BitBlt/StretchBlt
2.2.5 恢复兼容dc 的位图
2.2.6 删除兼容dc
2.2.7 删除位图对象
2.3 区域的使用步骤
2.3.1 创建几何区域
CRgn::CreateXXX
2.3.2 将两个区域进行几何运算
CRgn::CombineRgn
2.3.3 使用画刷填充几何区域
CDC::FillRgn
2.3.4 使用画刷填充边界
CDC::FrameRgn
使用:CWnd::SetWindowRgn,设置窗口的区域, 使用它
可以创建异形窗口
二简单的鼠标绘图的例子
1 图形的类型,直线、矩形和椭圆。
数据:起点坐标、终点坐标和图形类型
2 处理的消息
LBUTTONDOWM:确定起点坐标,开始绘制
MOUSEMOVE:动态的绘制图形
LBUTTONUP:结束绘制
Day 10
一MFC 的文件操作
1 相关类
1.1 CFile 类
封装了文件句柄以及操作文件的API。提供了文件内容的读写
操作;还可以获取和设置文件的属性。
1.2 CFileFind 类
提供了文件查找功能
2 使用
2.1 CFile 类的使用
2.1.1 文件内容读写
2.1.2 设置/获取文件属性
2.2 CFileFind 类的使用
2.2.1 开始查找
CFileFind::FindFile
2.2.2 查找下一个(得到第一个文件的信息,返回值表示
下一个文件是否存在)
CFileFind::FindNextFile
2.2.3 获取/判断文件信息
CFileFind::GetXXX/IsXXX
2.2.4 结束查找
CFileFind::Close
例子1:使用CFileFind 类查找c 盘根目录下的文件和文件夹
例子2:使用CFileFind 类查找c 盘下的所有文件和文件夹
提示:1 用到递归
2 排除dot 目录
3 调用GetFilePath 获取目录
二序列化
引入CArchive 类,带来的好处:1 可以设置文件读写的缓冲区大小
2 读写各种基本数据类型,不需要类型转换。
1 概念
将数据以二进制流的方式写入到文件或者从文件中读取。
2 使用
2.1 打开或者新建文件
CFile::Open
2.2 文件读写
2.2.1 定义CArchive 对象
2.2.2 具体的数据读写
CArchive::operator >> "读取"
CArchive::operator << "写入"
2.2.3 关闭CArchive 对象
CArchive::Close
2.3 关闭文件
CFile::Close
三对象的序列化(MFC 的第六个机制)
1 概念
序列化对象-将对象的类信息以及对象的成员变量以二进制流的
方式依次写入到文件的过程。
(运行时类信息是序列化的必要条件)
反序列化对象-从文件中读取类的信息,创建对象,然后读取文件
中的成员变量初始化新建的对象的过程。
(动态创建是序列化的必要条件)
2 使用
2.1 定义支持序列化的类
2.1.1 派生自CObject 类
2.1.2 添加序列化的声明宏和实现宏
2.1.3 重写虚函数Serilize(),在函数中,完成类的数据成员的
序列化
2.2 读写对象
读写对象时传入的参数是对象的地址,步骤与读写基本类型
的数据一样。
3 原理
3.1 展开宏的结构体
struct AFX_CLASSINIT
{
//构造函数
AFX_CLASSINIT(CRuntimeClass* pNewClass)
{
AfxClassInit(pNewClass);
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
//将当前的运行时类信息保存到应用程序的m_classList 链表中
pModuleState->m_classList.AddHead(pNewClass);
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
}
}
};
_init_CStudent 是一个全局的结构体变量,类型是结构体
AFX_CLASSINIT。进入_tmain()函数之前,将当前类的
运行时类信息保存到模块状态信息的m_classList 链表中
3.2 写入对象的过程
ar.WriteObject(pOb);
{
//获取当前类的运行时类信息
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
//将对象的类的信息写入到文件
WriteClass(pClassRef);
{
pClassRef->Store(*this);
{
//类名称长度
WORD nLen = (WORD)lstrlenA(m_lpszClassName);
//依次将版本、类名称长度写入文件
ar << (WORD)m_wSchema << nLen;
//将类名称写入文件
ar.Write(m_lpszClassName, nLen*sizeof(char));
}
}/
/由于虚函数机制,调用CStudent::Serialize()函数,
//将类的成员变量依次写入到文件
((CObject*)pOb)->Serialize(*this);
{
CObject::Serialize(ar);
if (ar.IsStoring())
{
ar<<m_strName<<m_nAge;
}
...
}
}
3.3 读取对象的过程
ar.ReadObject(RUNTIME_CLASS(CStudent));
{
//得到当前类的运行时类信息
ReadClass(pClassRefRequested, &nSchema, &obTag);
{
CRuntimeClass::Load(*this, &nSchema);
{
ar >> wTemp;
ar >> nLen;
ar.Read(szClassName, nLen*sizeof(char));
szClassName[nLen] = ‘\0‘;
//在链表中根据类的名称循环查找得到运行时类信息
for (pClass = pModuleState->m_classList; pClass != NULL;
pClass = pClass->m_pNextClass)
{
if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
{ AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
return pClass;
}
}
}
}/
/动态创建对象
pOb = pClassRef->CreateObject();
//使用从文件中读取的类的成员初始化新建的对象
pOb->Serialize(*this);
{
CObject::Serialize(ar);
{
...
else
{
ar>>m_strName>>m_nAge;
}
}
}
}
Day 11
一带版本的类的序列化
1 解决的问题
新的程序打开原来的文件的问题(兼容问题)
2 解决的步骤:
2.1 在序列化的实现宏的参数中设置类的版本,设置时,版本号与
VERSIONABLE_SCHEMA 进行位或。
2.2 修改Serilize()函数
调用CArchive::GetObjectSchema()函数,得到版本号,然后根据
不同的版本,进行不同的加载操作。
二为画图程序增加保存功能
1 添加图形类,增加对序列化的支持
2 由于需要保存多个图形,所以使用集合类,选择使用CObArray
CObArray 是一个动态的数组,数组元素类型是CObject*
3 在文档类中添加成员变量
CObArray m_ShapeArray;
4 在视图类鼠标弹起的消息处理函数中将图形添加到数组中
5 首先解决重绘问题
在视图的OnDraw()函数中使用文档数据重绘
6 修改DrawShape()函数,增加图形类型参数
7 添加文档类的成员函数ClearShapeArray(),清空集合。
8 实现文档类的Serilize()函数,保存和加载图形数据
9 分别在文档的析构和新建文档时,清空集合
10 为了设置保存的文件类型,修改文档的字符串资源
11 双击打开
//可以通过外部命令打开程序
EnableShellOpen();
//将文件类型写入到注册表
RegisterShellFileTypes(TRUE);
原理:双击某一个文件时,根据文件的后缀在注册表中
查找对应的应用程序,找到后,启动该程序,并且加载
文件数据。
通过在MFC 的工程向导的第四步中的Advanced 按钮中设置
文件类型,程序自动增加以上两句代码
三多文档视图应用程序的例子
Day 12
一MFC 对话框
1 分类
模式和非模式两种
2 相关类
CDialog 类-对话框类的父类,用于创建一般的对话框。
CCommonDialog 类-父类是CDialog 类,通用对话框类,包含了一系列
的可以直接使用的通用对话框,以它子类的方式提供。
文件对话框、颜色对话框、字体对话框、打印对话框
页面设置对话框、查找替换对话框。
CPropertyPage 类-父类也是CDialog 类,属性页对话框。可以完成
标签式属性页和向导式属性页。
3 CDialog 类的使用
3.1 基于模式对话框的应用程序
3.1.1 添加对话框资源,资源ID 设置为构造函数的参数
3.1.2 创建和显示
CDialog::DoModal()
3.1.3 关闭
CDialog::OnOK()/OnCancel()
3.2 基于非模式对话框的应用程序
3.2.1 添加对话框资源,资源ID 设置为构造函数的参数
3.2.2 创建和显示,与一般框架的创建和显示的过程相同。
3.2.3 关闭,需要程序员自己处理
1 重写CDialog::OnOK/OnCancel 函数,在函数中:
DestroyWindow();
2 重写CWnd::PostNcDestroy 函数,在函数中:
delete this;
3.3 CDialog::DoModal()函数的执行流程
3.3.1 查找和加载对话框资源
3.3.2 将父窗口设置为不可用状态
3.3.3 创建对话框,进入对话框的消息循环
3.3.4 点击OK 或者Cancel 按钮后,退出消息循环
3.3.5 隐藏对话框窗口
3.3.6 将父窗口设置为可用的和活动的状态
3.3.7 销毁对话框窗口
3.3.8 返回DoModal()函数的执行结果
二控件操作
1 控件的初始化放到对话框的消息WM_INITDIALOG 处理函数中
重写CDialog::OnInitDialog()函数。
控件操作的第一种方式:
通过控件ID 得到控件对象地址,CWnd::GetDlgItem(int nID)
控件操作的第二种方式:
对话框数据交换技术DDX,Do Data Exchange
2 对话框数据交换技术DDX
2.1 DDX 的概念
将控件与类的成员变量绑定,通过操作成员变量的方式间接的
操作控件。
2.2 相关函数
2.2.1 绑定函数
DDX_Control()-控件类型的绑定
DDX_Text()-值类型的绑定
2.2.2 数据交换函数
DoDataExchange()
2.2.3 UpdateData(BOOL)
UpdateData(TRUE)-将用户在控件中输入的数据传递给变量
UpdateData(FALSE)-将变量的值显示到控件上
2.3 原理
2.3.1 DDX_Control,控件类型的绑定
DDX_Control()
{
//1 根据控件的ID,得到控件的句柄
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
rControl.SubclassWindow(hWndCtrl)
{
Attach(hWnd);
{
//创建映射对象
CHandleMap* pMap = afxMapHWND(TRUE);
pMap->SetPermanent(m_hWnd = hWndNew, this);
{
//以句柄为键,以控件类型的变量的地址为值
//建立映射关系。
m_permanentMap[(LPVOID)h] = permOb;
}
}
}
}
2.3.2 DDX_Text,值类型的绑定
DDX_Text(pDX,IDC_EDIT1,m_strText);
{
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
if (pDX->m_bSaveAndValidate)
{
int nLen = ::GetWindowTextLength(hWndCtrl);
::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen),
nLen+1);
value.ReleaseBuffer();
}
else
{
AfxSetWindowText(hWndCtrl, value);
}
}
三使用DDX 完成登录的例子
四控件的介绍
1 静态控件
包括图片、静态文本和分组框。默认控件ID 都是IDC_STATIC,
所以不能通过向导绑定成员变量;如需绑定,必须修改控件ID。
图形、静态文本控件对应的控件类是CStatic,而分组框对应
的控件类是CButton。
Day 13
四控件的介绍
1 静态控件
包括图片、静态文本和分组框。默认控件ID 都是IDC_STATIC,
所以不能通过向导绑定成员变量;如需绑定,必须修改控件ID。
图形、静态文本控件对应的控件类是CStatic,而分组框对应
的控件类是CButton。
2 按钮控件
包括一般按钮、复选按钮和单选按钮。三者所对应的控件类都是
CButton。如果需要在同一个对话框上添加多个单选分组时,需要
设置Group 属性。
3 下拉框(组合框)和列表框
组合框中的选项可以单选,也可以编辑。列表框中的选项可以
单选或多选,不可编辑。组合框和列表框中选项其实是字符串。
另外,组合框可以通过属性的方式添加选项。
组合框的控件类是CComboBox;列表框的控件类是CListBox
1 添加选项
CComboBox::AddString
CListBox::AddString
2 删除选项
CComboBox::DeleteString
CListBox::DeleteString
3 清空选项
CComboBox::ResetContent
CListBox::ResetContent
4 查找选项
CComboBox::FindString
CListBox::FindString
5 获取当前选择项
CComboBox::GetCurSel
CListBox::GetCurSel
6 获取选项的数量
CComboBox::GetCount
CListBox::GetCount
7 设置/获取选项的附加数据
CListBox::SetItemData/GetItemData
CComboBox::SetItemData/GetItemData
五简单的动画播放的例子
1 CFileDialog 类的使用
1.1 构造函数
CFileDialog(
BOOL bOpenFileDialog,\\标识是文件打开对话框还是另存为对话框
LPCTSTR lpszDefExt = NULL,\\默认的扩展名
LPCTSTR lpszFileName = NULL,\\默认的文件名
DWORD dwFlags = OFN_HIDEREADONLY ,\\对话框的风格
LPCTSTR lpszFilter = NULL, \\设置文件类型控件中的选项
CWnd* pParentWnd = NULL\\通常设置为NULL 即可。
);
文件类型过滤的字符串格式:
1 多个选项之间以"|"隔开;
2 每个选项由显示和过滤两部分组成,这两部分以"|"隔开;
3 整个字符串以"||"结束
"视频文件(*.avi)|*.avi|所有文件(*.*)|*.*||";
1.2 创建和显示窗口
CFileDialog::DoModal
1.3 获取选择的文件信息
CFileDialog::GetXXX
六进度条/滑块/旋转按钮三个控件
1 设置/获取控件表示的数值范围
CSpinButtonCtrl::SetRange/GetRange
CProgressCtrl::SetRange/GetRange
CSliderCtrl::SetRange/GetRange
2 设置单位
CSliderCtrl::SetPageSize/SetLineSize
CProgressCtrl::SetStep
Day 14
一进度条/滑块/旋转按钮三个控件
1 设置/获取控件表示的数值范围
CSpinButtonCtrl::SetRange/GetRange
CProgressCtrl::SetRange/GetRange
CSliderCtrl::SetRange/GetRange
2 设置单位
CSliderCtrl::SetPageSize/SetLineSize
CProgressCtrl::SetStep
3 设置/获取控件的进度
CSpinButtonCtrl::SetPos/GetPos
CProgressCtrl::SetPos/GetPos
CSliderCtrl::SetPos/GetPos
二列表控件
1 相关类
CListCtrl-控件类,父类是CWnd。通常在对话框中使用。
CListView-视图类,父类是CCtrlView。CListView 其实是在
CView 的客户区放置了一个CListCtrl 控件。
CListView=CView+CListCtrl。
2 CListCtrl 的使用
2.1 介绍
控件的风格包括图标、小图标、列表和报表四种。
控件中每个数据项可以包含文本和图标,不同数据项图标
可以不同。如果以报表的方式显示,还可以设置列。
2.2 使用
2.2.1 设计和设置控件的图标列表
CListCtrl::SetImageList
2.2.2 插入数据项
CListCtrl::InsertItem
2.2.3 插入控件的列
CListCtrl::InsertColumn
2.2.4 设置列的文本
CListCtrl::SetItemText
2.2.5 修改控件的显示风格
CWnd::ModifyStyle
2.2.6 设置/获取数据项的附加数据
CListCtrl::SetItemData/GetItemData
2.2.7 设置背景图片
CListCtrl::SetBkImage
注释:设备背景图片,需要Ole 库的初始化,而且,通常
会将字体的背景色设置为透明。
示例:AfxOleInit();
m_wndList.SetBkImage("F:\\bliss.bmp");
m_wndList.SetTextBkColor(CLR_NONE);
...
三树控件
1 相关类
CTreeCtrl-继承自CWnd,控件类,通常在对话框中使用。
CTreeView-继承自CCtrlView,视图类。其实相当于在CView
中包含了一个CTreeCtrl 控件。
2 CTreeCtrl 与CListCtrl 的区别
树控件的节点之间的关系包括父子关系和兄弟关系,只能通过
节点句柄标识某个节点。列表控件的数据项之间是兄弟关系,
数据项是通过索引值标识。
3 使用
几乎所有的成员函数都有节点句柄参数。
3.1 设置图标列表
CTreeCtrl::SetImageList
3.2 插入节点
CTreeCtrl::InsertItem
3.3 设置节点高度
CTreeCtrl::SetItemHeight
3.4 设置节点的展开状态
CTreeCtrl::Expand
...
Day 15
一属性页对话框
1 分类
标签式-主要用于配置参数、选项等数据
向导式-通常引导用户一步步的选择和设置,最终完成某些功能。
2 相关类
CPropertyPage-页面对话框类
CPropertySheet-表单类(框架)
属性页对话框由一个表单对象+多个页面对象组成。
3 标签式属性页的使用(配置图形的线宽和颜色)
3.1 添加对话框资源,修改语言和字体,生成相应的类,注意
父类选择CPropertyPage。
3.2 添加CPropertySheet 类的派生类CSetupSheet
3.3 在CSetupSheet 类中添加页面对话框类的成员变量,在构造
函数中,添加页面
CSetupSheet::AddPage
3.4 在菜单的处理函数中,创建和显示标签式属性页
CSetupSheet::DoModal
3.5 将应用按钮设置为可用
CPropertyPage::SetModified(TRUE);
3.6 通过添加虚函数的方式添加按钮的处理函数
CPropertyPage::OnApply
CPropertyPage::OnOK
CPropertyPage::OnCancel
4 向导式属性页的使用
4.1 添加对话框资源,修改语言和字体,生成相应的类,注意
父类选择CPropertyPage。
4.2 添加CPropertySheet 类的派生类CSetupSheet
4.3 在CSetupSheet 类中添加页面对话框类的成员变量,在构造
函数中,添加页面
CSetupSheet::AddPage
4.4 设置显示方式为向导模式
CPropertySheet::SetWizardMode
4.5 在菜单的处理函数中,创建和显示标签式属性页
CPropertySheet::DoModal
4.6 设置每个页面的向导按钮
4.6.1 在哪儿设置?
CPropertyPage::OnSetActive()
4.6.2 通过什么函数设置?
GetParent()
CPropertySheet::SetWizardButtons()
4.7 通过添加虚函数的方式添加按钮的处理函数
CPropertyPage::OnWizardBack
CPropertyPage::OnWizardFinish
CPropertyPage::OnWizardNext
二MFC 线程
1 MFC 按照用途对线程分类
工作者线程-通常用于后台的、耗时的操作,通用没有用户界面
用户界面线程-通常用于需要和用户交互的操作,拥有单独的
用户界面。
2 工作者线程的使用步骤
2.1 定义线程函数,函数原型如下:
UINT MyControllingFunction( LPVOID pParam );
注意:函数要么是全局函数,要么是类的静态成员函数
2.2 创建和启动线程
AfxBeginThread(AFX_THREADPROC pfnThreadProc,
LPVOID pParam, ...);
注意:第二个参数是主线程与子线程传递参数的
3 用户界面线程的使用步骤
3.1 添加CWinThread 类的派生类
3.2 在派生类的InitInstance()函数中创建用户界面
3.3 创建和启动线程
AfxBeginThread( CRuntimeClass* pThreadClass,
...);
4 线程同步类
5 上机题
5.1 创建单文档视图程序,不包含文档类。
5.2 切分窗口的三个视图类
5.2.1 CMyFormView (左边)
创建步骤与页面对话框类似
5.2.2 CMyListView (右边)
右击工程,添加CListView 类的派生类,并且添加
WM_CREATE 的消息处理函数,在函数中,完成控件
的初始化。
5.2.3 CEditView (底部)
5.3 在CMainFrame::OnCreateClient()函数中,创建切分窗口
5.4 删除自动生成的视图
5.5 在CMyFormView 中添加其它两个视图对象的指针变量。
注意在构造函数中初始化
5.6 在CMainFrame::OnCreateClient()函数中,创建切分窗口后,
将其它两个视图对象的地址保存到CMyFormView 的指针变量中
5.7 处理添加按钮的消息函数
Day 16
一COM 组件的应用[ActiveX 控件]
1 COM 组件的优势
1.1 大的项目由多个组件组成的,项目更能够适应需求的变更。
1.2 组件是二进制级别的复用
1.3 组件与具体的编程语言无关
2 COM 组件的缺点
2.1 学习难度大,对程序员的要求高
2.2 组件的使用需要注册,与当前倡导的绿色软件矛盾的。
二ActiveX 控件的概念、开发、注册和使用
1 概念
基于COM 组件的,使用像一般控件一样方便。
2 使用MFC ActiveX 向导开发组件
2.1 工程中接口和类的介绍
2.1.1 第一个接口用来添加控件的属性和方法
2.1.2 第二个接口用来添加控件的事件的
2.1.3 App 类-应用程序类,通常完成其它库的初始化
2.1.4 Ctrl 类-控件类,实现了控件的所有功能。使用OnDraw()
函数,完成控件的绘制。
2.1.5 PropPage 类-设置控件的属性页
3 组件中接口的概念
接口是一组纯虚函数的集合。它只描述是什么样的功能,
没有功能的具体实现。具体实现交给接口的子类完成。
在我们的工程中交给Ctrl 类完成。
4 开发步骤
4.1 通过第一个接口添加方法,自动会在Ctrl 类中添加该方法,
在Ctrl 类中实现该方法即可。
4.2 通过第一个接口添加属性,自动在Ctrl 类中添加一个成员
变量和一个消息处理函数,当变量的值发生变化时,该函数
就执行。
4.3 通过第二个接口添加事件
库存事件-名称是由系统提供的,只需在组合框中选项事件
名称即可。库存事件采用自动通知
自定义事件-名称是由用户提供的,是由用户进行手动通知。
在相应的函数内,调用FireMyMsg()函数。
5 使用ActiveX Control Test Container 测试控件
包括控件的属性、方法和事件这三方面的测试。
6 控件注册
一个ActiveX 控件在使用前,首先需要去注册。
6.1 在使用VC6.0 开发控件时,当编译成功后,控件自动注册。
6.2 如果在开发项目时,使用第三方控件,微软提供了一个
小的工具regsvr32.exe 帮助我们方便注册控件
在运行框中输入:
regsvr32 /u "组件所在的文件路径" 注册/卸载组件
7 控件的使用
7.1 窗口程序中使用控件
方式一:
1 右击对话框窗口的空白处,选择Insert ActiveX Control 菜单
在弹出的对话框中,选择需要的ocx 控件。
2 为ocx 绑定成员变量,这时会提示添加控件的封装类,按
提示添加即可。
3 可以像使用一般控件一样使用ocx 控件了。
方式二:
1 "Project"->"Add to Project"->"Components and Controls"
->弹出添加控件对话框。选择相应的控件,点击插入,这时
在工程中添加了控件的封装了,并且在工具栏中添加了控件
的图标
2 可以像使用一般控件一样使用ocx 控件了。
7.2 html 网页程序中使用控件
在html 中使用控件时,使用的标签是<object>
示例:
<object id="McdCtrl"
classid="clsid:66C3EA36-7FFE-4674-9C0E-E8ECE3749F19"
width="250" height="200">
</object>
clsid:是组件ID,用GUID(全局唯一标识符)标识。它是
在开发组件时,由编译器自动生成。
8 注册组件时,将哪些信息写入到注册表?
regedit-打开注册表
根据组件的ID,找到组件所在的文件路径。
9 常用的ActiveX 控件
MS DataGrid-常用于显示数据库中的表的数据
MS Comm-常用在工业控制领域中,完成串口通信
Windows Media Player-视频播放器
Day 17
一vc 访问数据库技术
1 ODBC-Open Database Connectivity,微软开发式数据互联。
是一组用于访问和操作数据库的API。MFC 将这组API 封装成
ODBC 类。使用相同的API 函数访问不同的数据库管理系统,但是
只能访问关系型数据库。而且,首先需要将不同的数据库设置为
ODBC 数据源。
2 DAO-基于ODBC 的,目前已经被淘汰
3 OLE DB-基于COM 技术,提供了一组访问和操作数据库的接口。
既可以访问关系型又可以访问非关系型数据库。性能也比ODBC
有了很大提高。接口复杂,学习的门槛高,并没有流行起来。
4 ADO-基于OLE DB,对OLE DB 进一步的封装,提供了一组简单的
接口。逐渐的被广大的c++程序员接受,成为使用最广泛的访问
和操作数据库的技术。
5 ADO.NET-基于net 平台,VB.net、C#和VC 都可以使用的访问和
操作数据库的技术。ADO.NET 是一组类。
二ODBC 类的使用
1 相关类
CDatabase 类-功能主要是连接和关闭数据库。另外,也提供了
执行Sql 语句的功能。
CRecordset 类-提供对数据的增、删、改、查的操作。
CRecordView 类-专门显示数据库数据的视图类
2 操作步骤
2.1 设置ODBC 数据源
控制面板->管理工具->ODBC 数据源
2.2 打开数据库
CDatabase::Open(LPCTSTR lpszDSN,//数据源名称
... );
通过执行Sql 语句的方式对数据增、删、改。
2.3 打开表
CRecordset::Open(
UINT nOpenType ,//选择CRecordset::forwardOnly ,只读记录集
LPCTSTR lpszSQL,//查询语句
...);
2.3.1 获取字段的数量
CRecordset::GetODBCFieldCount
2.3.2 获取字段的信息
CRecordset::GetODBCFieldInfo
2.3.3 获取字段的值
CRecordset::GetFieldValue
2.3.4 游标操作
CRecordset::MoveNext
CRecordset::IsEOF
2.4 关闭记录集
CRecordset::Close
2.5 关闭数据库
CDatabase::Close
3 CReocrdView 类的使用
三ADO 的使用
1 准备工作
1.1 组件的文件名称:msado15.dll
1.2 组件的文件路径:
"C:\Program Files\Common Files\System\ado\msado15.dll"
1.3 引入ADO 组件
#import "组件的路径" no_namespace rename("EOF","AdoEOF")
1.4 使用组件前,都需要初始化COM 库。
CoInitialize(NULL);
编译工程,生成msado15.tlh 和msado15.tli 两个文件,相当于
组件对应的封装类。
2 ADO 组件的主要接口介绍
2.1 Connection 接口,功能与ODBC 的CDatabase 类相同。使用的
是Connection 接口的智能指针类,_ConnectionPtr。
2.2 Recordset 接口,功能与ODBC 的CRecordset 类相同。使用的
是Recordset 接口的智能指针类,_RecordsetPtr。
3 ADO 组件的使用方式
将ADO 组件的接口封装成C++的类,将接口函数,封装成类的
成员函数。调用程序直接使用C++的封装类,无需担心参数
转换带来的麻烦。
4 Connection 接口
4.1 连接数据库
Open ( _bstr_t ConnectionString,//连接字符串
_bstr_t UserID, //登录名称
_bstr_t Password, //密码
long Options//数据库的打开方式
);
不同的数据库产品所使用的连接字符串各不相同。即使是相同
的数据库产品,如果版本不同,连接字符串也不相同。
通过udl 文件的配置得到连接字符串。
Access:
Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=F:\db\odbc.mdb;
Persist Security Info=False
5 CRecordset 接口
5.1 打开表
Open (
const _variant_t & Source,//可以是表名、Sql 语句、存储过程
const _variant_t & ActiveConnection, //活动连接
enum CursorTypeEnum CursorType,//游标类型
enum LockTypeEnum LockType, //记录的锁定类型
long Options //表示第一个参数到底是什么,adCmdTable,adCmdText
);
游标类型
enum CursorTypeEnum
{
adOpenUnspecified = -1,//不指定
adOpenForwardOnly = 0,//静态的单向游标
adOpenKeyset = 1,//动态游标的一种,称键集游标
adOpenDynamic = 2,//动态游标
adOpenStatic = 3//静态游标,双向的
};
记录的锁定类型
enum LockTypeEnum
{
adLockUnspecified = -1,//不指定
adLockReadOnly = 1,//只读记录集
adLockPessimistic = 2,//悲观锁
adLockOptimistic = 3,//乐观锁
adLockBatchOptimistic = 4//批处理的乐观锁
};
5.2 字段操作
->Fields->GetCount(),字段数量
->Fields->GetItem(nIndex)->GetName(),字段名称
->Fields->GetItem(nIndex)->Value,字段的值
5.3 游标操作
MoveNext()
IsEOF()
Day 18
一Recordset 接口
1 字段操作
Fields->GetCount(),字段数量
Fields->GetItem(nIndex)->GetName(),字段名称
Fields->GetItem(nIndex)->Value,字段的值
2 游标操作
MoveNext()
MoveFirst()
MovePrevious()
MoveLast()
Move(long nNumber)
IsEOF()
IsBOF()
二通过记录集的方式实现数据的增、删、改
1 添加新的记录
1.1 添加一条新记录
AddNew()
1.2 设置记录中每个字段的值
SetFieldValue()
1.3 更新到数据库
Update()
2 删除记录
2.1 将游标移动到要删除的记录
2.2 执行删除操作
Delete()
2.3 更新到数据库
Update()
3 修改记录
3.1 将游标移动到要修改的记录
3.2 重新设置记录的值
SetFieldValue()
3.3 更新到数据库
Update()
三通过直接执行Sql 语句的方式实现数据的增、删、改
1 Connection 接口的Execute()函数
Execute (
_bstr_t CommandText,//Sql 语句
VARIANT * RecordsAffected,//影响到的记录的数量
long Options //adCmdText
);
如果Sql 语句是一个查询操作,返回的记录集是只读的,游标
也是单向的静态游标。所以,更多的我们使用它完成增、删
和修改操作。
2 Recordset 接口的Open()函数
Open(
const _variant_t & Source,//可以是表名、Sql 语句、存储过程
const _variant_t & ActiveConnection, //活动连接
enum CursorTypeEnum CursorType,//游标类型
enum LockTypeEnum LockType, //记录的锁定类型
long Options //表示第一个参数到底是什么,adCmdTable,adCmdText
);
如果Sql 语句是一个查询操作,可以执定返回记录集的游标类型
和记录的锁定类型。所以,更多的我们使用它完成查询操作。
四事务处理
Connection 接口提供了对事务处理的操作。
BeginTrans()-启动事务
RollbackTrans()-回滚事务
CommitTrans()-提交事务
五通过数据库如何管理图片、视频等大二进制数据?
在数据库中存储图片、视频等文件的路径。
第四部分windows 的网络通信编程
1 原始的Socket 函数
2 以WSA 开头的socket 函数
基于Windows 平台,结合了Windows 特性的一组API 函数。
3 MFC 的socket 类
CAsyncSocket 类-同步类。
CSocket 类-继承自CAsyncSocket 类,异步类。
VC6.0 集成了socket 库的1.1 版本,xp 操作系统自带了2.2 版本的
socket 库。2.2 版本socket 库的相关文件
头文件:#include <winsock2.h>
dll 文件:ws2_32.dll
lib 文件:ws2_32.lib
使用socket 库首先需要初始化,函数:
int WSAStartup (
WORD wVersionRequested,//请求使用的socket 库的版本
LPWSADATA lpWSAData//返回可用的版本信息
);
TCP 通信
TCP 服务器步骤:
1 创建套接字
2 绑定地址和端口
3 监听
4 等候客户端连接
5 数据收发
6 关闭套接字
查看网络端口状态netstat -an
TCP 客户端步骤:
1 创建套接字
2 连接服务器
3 数据收发
4 关闭套接字
Day19
网络:
一、使用MFC 的类完成简单的文件传输
不要把界面与业务逻辑掺杂一块儿
分层。把对业务逻辑的操作封装成一个类,用按钮使用这个类。
二、FeiQ 的例子
1.功能分析
上线
下线
信息收发
文件传输
掉线检测
2.工程中类的介绍
FeiQ 既包含了socket 通信的服务器,又包含了客户端,既包含了TCP 通
信,
又包含了UDP 通信
CUserServer - UDP 的服务器端
CUserClient - UDP 的客户端
CFileServer - TCP 的服务器端
CFileClient - TCP 的客户端
CFileThread - 用于文件创数的用户界面线程的线程类
CUserView - 用户列表视图
CChatView - 用户聊天视图
3.使用UDP 的广播添加列表数据(上线)
设置套接字的选项,可以设置为广播模式setsockopt()
4.掉线检测如何实现
4.1 CMainFrame 中创建和启动定时器,每隔10 秒调用一次定时器处理函
数,在函数中,
发送广播数据,在服务器收到广播数据后,将每个添加的数据项的附
加数据设置为1,
而且每隔10 秒就会做这件事
4.2 CUserView 中创建和启动定时器,每隔20 秒调用一次定时器处理函数,
在函数中,遍历
整个控件,如果数据项的附加数据值为1,将它设置为0,如果为0,
则删除该数据项
正常情况:0 1 0 1 0 1 0 1 0 1
掉线情况:0 1 0 1 0 1 0 1 0 0...删除该数据项
三、VOD 视频点播系统
1.Video On Demands
2.VOD 服务器
1.1 皮肤库的使用
1.2 类VC 界面的设计
1.3 DataGrid 控件
1.4 ADO 组件的封装类
1.5 socket 通信
3.VOD 客户端
3.1 Windwos Media Player 控件
3.2 socket 通信
四、开发步骤
1.VOD 服务器
1.1 完成底部对话框的设计
1.2 将DataGrid 控件铺满视图的客户区。
VODDEV 项目
1 创建项目目录,包括源码、文档、数据库、资源、可执行文件等
2 在源码目录下创建工程空间VODSYS,目录为src,去掉自动生成的VODSYS
3 创建MFC 单文档应用程序,文档视架构的支持,View 继承自CFormView,
设置输出为../../bin/server(两处设置)
3.1 在工程中,添加类vc 界面的工具条。
3.1.1 sizecbar.h sizecbar.cpp scbarg.h、scbarg.cpp 四个文件复制到工程
thirdpart 目录下。
3.1.2 在菜单Project->Add to project->Files 将四个文件加入工程中,此时
在ClassView 中将出现了一个称为CCoolBar 的类。
3.1.3 在stdafx.h 文件中加上
//浮动时候替换原来TOOL WINDOWS 的框架
#define _SCB_REPLACE_MINIFRAME
#include "thirdpart\sizecbar.h"
#include "thirdpart\scbarg.h"
3.1.4 为CMainFrame 增加成员变量:
CCoolBar m_LeftCtrBar; //左面的控制窗口
CCoolBar m_BottomCtrBar; //最下面的控制窗口
3.1.5 创建和停靠工具栏
3.1.6 该ControlBar 在浮动的时候顶部的把手会消失,变成了普通的
ToolWindow 类型的标题栏。为了避免这种情况,
我们需要在CMainFrame::OnCreate()中,在EnableDocking()后加
入:
#ifdef _SCB_REPLACE_MINIFRAME
m_pFloatingFrameClass =
RUNTIME_CLASS(CSCBMiniDockFrameWnd);
#endif //_SCB_REPLACE_MINIFRAME
并在stdafx.h 中加上#define _SCB_REPLACE_MINIFRAME,在
两个头文件前面
4 设置工具栏上按钮的功能和状态,分别添加两种消息
5 设置皮肤
1 拷贝skin 目录到当前的工程中
(皮肤文件、h 文件、dll 文件、lib 文件)
2 在项目的头文件stdafx.h 中包含头文件,引入lib 文件
6 在左边的控制窗口中添加树控件
1 在CMainFrame 中添加成员变量m_wndTree
2 在CMainFrame 的OnCreate()中动态创建树控件
7 在底部的控制窗口中添加对话框
1 添加对话框资源,设置风格style:child;border:none
2 双击资源窗口生成对话框类CDlgVideo
3 在CMainFrame 的OnCreate()中创建和显示对话框
8 在CFormView 视图中添加MS DataGrid 控件(COM 组件)
Microsoft DataGrid Control 6.0
CDataGrid、CColumns CColunm 添加到工程
1 为控件绑定成员变量m_wndGrid
2 控件铺满窗口的客户区,给视图添加WM_SIZE 的消息处理
设计视频编辑对话框。
---------------------------------------
VODServer 对数据库的访问和操作
1 视频数据的显示,使用DataGrid 组件显示
操作步骤:
1 拷贝ado 的封装类到当前项目中,并且添加到项目中。
2 在stdafx.h 中,包含封装类的头文件
3 在CMainFrame 类中,添加成员变量
CAdoConnection m_adoConnection;
并且在构造函数中,连接数据库
m_adoConnection.ConnectAccess ("../../DB/VODDB.mdb");
4 在视图类View 中,添加成员变量
CAdoRecordSet m_adoRecordSet;
5 在视图类的OnInitialUpdate 函数中,添加用于
绑定记录集与datagrid 代码
6 在视图类中添加BindDataGrid 函数并实现
7 注意COM 的初始化,在App 的InitInstance 中完成
8 注意数据库文件的位置,把DB 目录拷贝到指定位置
9 当一个工程中的类非常多,我可以通过添加文件夹
的方式对类进行分类,以便于查看和管理所有的类,
但是它不会影响到真正的文件目录。
2 在不同的控件中显示视频类型信息(树控件、组合框控件)
2.1 添加并实现CTypeManger 类
2.1.1 添加CType 结构的定义
2.1.2 实现GetAllType()函数
2.2 在界面的控件中调用该类完成类型信息的显示
2.2.1 树控件的操作
1>在CMainFrame 类中添加函数InitTypeTreeCtrl()
2>在CMainFrame 类的OnCreate 函数中调用
2.2.2 组合框控件中添加类型
1>在CDlgVideo 中添加控件的初始化函数
InitVideoTypeCtrl()
2>在CMainFrame 类的OnCreate 函数中,创建和显示
对话框之后调用。
3 实现在对话框中对视频数据的增删改操作,重新显示操作
后的数据
3.1 添加操作视频信息表的类CVideoManager 和CVideo 结构体
3.2 添加和实现用于增、删、改的函数
3.3 使用CVideoManager 实现对视频表的操作
3.3.0 当DataGrid 控件选择项发生改变时,将数据显示到
对话框上
首先添加DataGrid 控件的SelChange 消息处理函
数,实现值的传递。
3.3.1 在DataGrid 控件中,选择一条记录,将该记录
显示到对话框。插入按钮的文本变为"更新"
在对话框中修改数据,点击更新,将新数据更新
到数据库后,DataGrid 显示新数据
3.3.2 点击"新建"按钮,对话框数据清空,更新按钮
的文本变为"插入",输入新的数据,点击“插入”按钮,
数据插入到数据库。DataGrid 从数据库
中获取新数据显示。
3.3.3 在DataGrid 控件中,选择一条记录,将该记录
显示到对话框。点击删除按钮,在数据库中删除
数据,DataGrid 从数据库
中获取新数据显示。
3.3.4 插入和更新的操作放到同一个按钮中实现了。
实现步骤:
"新建"、"插入"、"删除"按钮添加消息处理函数
1>"新建"的实现
清空所有控件数据,修改按钮的文本
2>"插入"、"更新"的实现
根据视频的ID 是否为空,判断是插入还是更新操作
操作完成后调用BindDataGrid 重新显示数据
3>"删除"的实现
获取要删除视频数据的ID,执行删除操作
操作完成后调用BindDataGrid 重新显示数据
清空控件中的数据
---------------------------------------------
媒体类型的增、删、改操作,树控件与数据库数据的操作。
用户信息的增、删、改和查询操作。
一项目中的socket 通信
1 基于连接的TCP 通信,TCP 服务器/客户端
2 基本的步骤:
2.1 定义用于传输的数据包结构(传输协议)
2.2 定义和实现网络通信的封装类
2.3 界面对封装类的调用
3 VODServer 关于网络通信的实现步骤:
3.0 socket 库的初始化
1 在App 的InitInstance 函数中:
if(!AfxSocketInit())
AfxMessageBox("Failed ",
MB_OK| MB_ICONSTOP);
2 在stdafx.h 文件中添加头文件
#include "afxsock.h"//socket 头文件
3.1 添加两个相关类,CNetServer 和CNetClient。并且
在CNetClient 类定义的前面添加数据包结构的定义
3.2 完成CNetServer 类的编写
3.3 完成CNetClient 类的编写
3.3.1 完成InitClient 函数的编写
3.3.2 完成OnLogin 函数的编写
3.3.3 返回所有的视频类型信息
BOOL OnAllVideoTypes();
3.3.4 返回指定类型ID 的所有视频信息
BOOL OnVideosByTypeID();
3.3.5 处理客户端请求的视频文件
BOOL OnMediaData();
3.3.6 原始的数据收发函数
BOOL RecvData(LPVOID pData,UINT nLen);
BOOL SendData(DWORD dwCmdID,LPVOID
pData,UINT nLen );
BOOL SendRaw(LPVOID pData,UINT nLen);
3.4 界面对CNetServer 类的调用
3.4.1 在CMainFrame 中包含头文件
#include "NetServer.h"
3.4.2 在CMainFrame 类中添加成员变量
CNetServer m_NetServer;
3.4.3 在CMainFrame 的OnCreate 函数中启动服务器
m_NetServer.InitServer();
4 VODClient 的实现:
4.1 皮肤的添加、工具条的添加以及登录对话框的添加
4.2 添加Media Player ActiveX 控件,并在view 中处理控件的大小。
4.3 VODClient 网络数据传输的实现ClientSocket
4.3.1 在工程中,添加CClientSocket 类,拷贝服务器的数据包结构到
CClientSocket 类的头文件中。
4.3.2 定义并实现CClientSocket 类中的相关函数
4.3.3 在界面中使用CClientSocket 类
3.4 界面对CNetServer 类的调用
3.4.1 在CMainFrame 中包含头文件
#include "NetServer.h"
3.4.2 在CMainFrame 类中添加成员变量
CNetServer m_NetServer;
3.4.3 在CMainFrame 的OnCreate 函数中启动服务器
m_NetServer.InitServer();
4 VODClient 的实现:
4.1 皮肤的添加、工具条的添加以及登录对话框的添加。
4.2 添加Media Player ActiveX 控件,并在View 中处理
控件的大小
4.3 VODClient 网络数据传输的实现
4.3.1 在工程中,添加CClientSocket 类,拷贝服务器的数据包结构到
CClientSocket 类的头文件中
4.3.2 定义并实现CClientSocket 类中的相关函数
4.3.3 在界面中使用CClientSocket 类
本文出自 “日知其所无” 博客,谢绝转载!
原文地址:http://shenyantao.blog.51cto.com/1957956/1606491