zoukankan      html  css  js  c++  java
  • MFC DAY06 07 08 09

    一 切分窗口
    1 类型
    动态切分-程序在运行时,由用户拖动分隔条动态的切分窗口。
    每一个视图窗口使用的是相同的视图类。
    静态切分-在编码创建时已经完成窗口切分。每一个视图窗口
    可以使用不同的视图类。
    2 相关类
    CSplitterWnd类-完成窗口切分的类。
    #include <afxext.h>//扩展窗口的头文件
    3 使用
    3.1 动态切分
    3.1.1 在CMainFrame中定义切分窗口对象
    3.1.2 通过使用CCreateContext结构指定使用的视图类
    3.1.3 创建动态切分
    CSplitterWnd::Create
    注意:切分数量不能超过2*2
    3.2 静态切分
    3.1.1 在CMainFrame中定义切分窗口对象
    3.1.2 在CMainFrame::OnCreateClient()函数中,完成切分
    CFrameWnd::OnCreateClient-虚函数,会被
    CFrameWnd::OnCreate调用,作用创建框架窗口的客户
    区对象。
    1 创建静态切分
    CSplitterWnd::CreateStatic
    2 创建视图
    CSplitterWnd::CreateView
    3.1.3 切分窗口的再切分
    1再切分对象的父窗口是前一个切分对象,而不是主窗口
    2设置在切分对象的ID
    CSplitterWnd::IdFromRowCol
    3 创建视图
    4 获取指定视图
    CSplitterWnd::GetPane
    5 设置/获取当前活动视图
    CSplitterWnd::SetActivePane/GetActivePane
    6 设置分隔条的位置(水平/垂直)
    CSplitterWnd::SetRowInfo
    CSplitterWnd::SetColumnInfo
    无论是动态切分还是静态切分,切分出来的每一个视图窗口都是
    独立的。
    二 文档类
    1 相关类
    CDocument类-继承自CCmdTarget类,意味着文档类也可以处理
    命令消息。
    2 使用(在视图类中显示文档类的数据)
    2.1 相关函数
    2.1.1 CView::OnInitialUpdate()-初始化视图对象
    被框架窗口的函数调用,在第一次附加文档之后,视图窗口
    初始化显示之前。
    2.1.2 CView::GetDocument()
    获取与视图关联的文档
    2.1.3 CFrameWnd::InitialUpdateFrame()-初始化更新框架
    在框架窗口创建后调用该函数,引起该框架内所有的视图窗口
    的OnInitialUpdate()函数的调用。
    2.2 实现步骤:
    2.2.1 在App::InitInstance()函数中:
    1 创建框架对象 new CMainFrame
    2 定义结构体变量 CCreateContext cxt;保存视图类的
    运行时类信息的地址,创建文档,保存文档对象地址。
    3 调用LoadFrame函数,创建框架窗口,并把变量cxt
    作为该函数的参数。
    4 作为应用程序主窗口,显示和更新
    2.2.2 在文档中添加成员变量m_strData,并初始化
    2.2.3 重写CView::OnInitialUpdate()函数,在函数中,
    把文档中的数据显示到视图。
    2.2.4 在LoadFrame函数之后,调用了InitialUpdateFrame()
    函数。
    2.3 思考问题:
    1 视图对象是在什么时候被动态创建?
    2 文档与视图的关系什么?关系什么时候建立?
    2.3.1 在CFrameWnd::OnCreate()函数中:
    OnCreate->OnCreateHelper->OnCreateClient
    ->CreateView(),CreateView()函数的执行流程:
    //1 动态创建视图对象
    m_pNewViewClass->CreateObject(); 587行
    //2 创建视图窗口
    pView->Create(...); 597行
    2.3.2 在CView::OnCreate()函数中:(viewcore.cpp)
    调用m_pCurrentDoc->AddView(this);
    AddView()函数的执行流程:
    void CDocument::AddView(CView* pView)
    {
    ...
    //将视图的地址保存到文档对象的链表中
    m_viewList.AddTail(pView);
    //将文档地址保存到视图对象的变量中
    pView->m_pDocument = this;
    ...
    }
    视图类与文档类相互保存对方的地址。一个文档可以对应
    多个视图,但是一个视图只能对应一个文档。
    2.4 对命令消息的相应顺序
    ActiveView->Document->Frame->App
    2.4.1 CFrameWnd::OnCmdMsg
    2.4.2 CView::OnCmdMsg
    顺序可以重写OnCmdMsg()函数修改,但是通常不去修改。
    三 单文档视图架构程序
    mvc架构-m:model,模型,管理和保存数据。
    v: view , 视图,显示数据
    c: controller, 控制器 ,接收和分发命令。
    m: Document,文档
    v: View, 视图
    c: Frame, 框架
    1 相关类
    CWinApp/CFrameWnd/CView/CDocument
    文档模板类-统一的方式创建框架、视图、文档对象。
    CDocTemplate-抽象基类,提供了所有文档模板的功能。
    CSingleDocTemplate-单文档模板类
    CSingleDocTemplate(
    UINT nIDResource,//资源ID
    CRuntimeClass* pDocClass,//文档类的运行时类信息
    CRuntimeClass* pFrameClass,//框架类的运行时类信息
    CRuntimeClass* pViewClass//视图类的运行时类信息
    );
    注意:定义文档、框架和视图类时需要动态创建的支持

    --------------------------------------------------

    一 单文档视图架构应用程序
    1 概念
    在某一时刻只能管理一个文档
    2 实现过程
    2.1 AddDocTemplate()函数
    void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
    {
    if (m_pDocManager == NULL)
    m_pDocManager = new CDocManager;
    m_pDocManager->AddDocTemplate(pTemplate);
    }
    void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
    {
    ...
    //在文档模板链表中添加新建的文档模板
    m_templateList.AddTail(pTemplate); 534行
    }
    结论:
    1 应用程序没有直接管理模板,而是交给文档管理类管理模板
    2 在文档管理类使用链表保存文档模板,可以管理多个模板
    2.2 OnFileNew()函数
    void CWinApp::OnFileNew()
    {
    if (m_pDocManager != NULL)
    m_pDocManager->OnFileNew();
    }
    void CDocManager::OnFileNew()
    {
    ...
    //获取保存的文档模板
    CDocTemplate* pTemplate =
    (CDocTemplate*)m_templateList.GetHead();
    //调用文档模板的OpenDocumentFile()函数
    pTemplate->OpenDocumentFile(NULL); 827行
    }
    CDocument* CSingleDocTemplate::OpenDocumentFile(...)
    {
    //创建新的文档对象
    pDocument = CreateNewDocument(); 112行
    //创建新的框架对象和框架窗口
    pFrame = CreateNewFrame(pDocument, NULL); 132行
    }
    CFrameWnd* CDocTemplate::CreateNewFrame(...)
    {
    //创建新的框架对象
    CFrameWnd* pFrame = 264行
    (CFrameWnd*)m_pFrameClass->CreateObject();
    //创建新的框架窗口
    if (!pFrame->LoadFrame(m_nIDResource,...); 277行
    }
    调用LoadFrame,产生WM_CREATE消息,在消息处理函数
    OnCreate()中,调用CreateView()函数,创建视图对象和
    视图窗口。
    创建视图窗口时,产生WM_CREATE消息,在消息处理函数
    OnCreate()中,调用AddView()函数,文档与视图相互保存
    对方的地址。
    3 类与类(对象与对象)之间的关系
    CWinApp
    |->m_pDocManager(CDocManager*)
    |->m_templateList (CSingleDocTemplate*)
    |->m_pOnlyDoc (CDocument*)

    |->m_pMainWnd(CFrameWnd*)
    |->m_pActiveView(CView*)
    |->m_pDocument (CDocument*)
    |->m_viewList (CView*)
    结论:
    MFC各个类之间的关系通过包含对方地址产生的。
    4 对命令消息的相应顺序
    View->Document->Frame-App
    二 多文档视图应用程序
    1 概念
    同时管理多个文档
    2 相关类
    CWinApp
    CMDIFrameWnd-多文档的主框架类(1个对象)
    CMDIChildWnd-多文档的子框架类(多个对象)
    CView/CDocument-视图/文档(多个对象)
    CMultiDocTemplate-多文档模板类
    CMultiDocTemplate(
    UINT nIDResource,//*子框架窗口的资源ID
    CRuntimeClass* pDocClass,//文档类运行时类信息
    CRuntimeClass* pFrameClass,//*子框架的运行时类信息
    CRuntimeClass* pViewClass //视图类的运行时类信息
    );
    多文档中主框架窗口和子框架窗口分别拥有自己的菜单和图标。
    主框架的对象以及窗口自己创建,而子框架、文档和视图使用
    模板创建。
    多文档中主框架窗口的菜单项至少有两项
    3 创建(多个视图数据同步的例子)
    3.1
    "新建视图"菜单
    -只创建子框架和视图窗口,文档不创建,使用当前的活动视图
    对应的文档。一个文档对应多个视图窗口。
    "新建"菜单
    -执行OnFileNew()函数,文档、子框架和视图都会被创建。
    3.2
    ON_CONTROL_REFLECT(EN_CHAGE,OnEnChange)//消息映射宏,
    捕捉到视图的内容发生变化的消息。在消息处理函数中:
    3.2.1 把活动视图的内容保存到文档
    3.2.2 通知其它视图从文档获取最新数据
    3.3
    重写CView::OnUpdate()函数,在函数中,获取文档数据,显示
    到当前视图。
    4 类之间的关系与单文档类似...

    三 MFC绘图
    1 相关类
    1.1 绘图设备类
    CDC-绘图设备类的父类,封装的是一般的绘图设备,例如:
    打印机、显示器等。
    CWindowDC-父类是CDC类,封装的是指定窗口。包括窗口
    客户区和非客户区。
    CClientDC-父类是CDC类,封装的是指定窗口的客户区。
    CPaintDC-父类是CDC类,封装的是指定窗口的客户区。该类
    只能用在WM_PAINT消息处理函数中。
    CMetaFileDC-父类是CDC类,保存绘制的命令。可以在需要
    的时候,重新执行这些绘制命令。

    1.2 绘图对象类

    2 使用
    2.1 CDC类的使用
    2.1.1 创建
    virtual BOOL CreateDC(
    LPCTSTR lpszDriverName,//设备驱动的名称
    LPCTSTR lpszDeviceName,//设备名称
    LPCTSTR lpszOutput, //NULL
    const void* lpInitData//初始化参数
    );
    如果描述的设备是显示器,("DISPLAY",NULL,NULL,NULL);
    2.1.2 绘图或者输出文本
    例如:TextOut()函数,输出文本
    2.1.3 删除
    CDC::DeleteDC()
    2.2 CMetaFileDC类的使用
    2.2.1 创建
    CMetaFileDC::Create
    2.2.2 绘制
    ...
    2.2.3 关闭,返回句柄 HMETAFILE
    CMetaFileDC::Close
    2.2.4 重新执行绘制命令
    CDC::PlayMetaFile(HMETAFILE )
    2.2.5 删除
    DeleteMetaFile(HMETAFILE)

    -----------------------------

    一 MFC绘图
    1 绘图设备类
    2 绘图对象类
    CGdiObject类-所有绘图对象的父类,抽象父类,不会直接使用
    CPen类-画笔
    CBrush类-画刷
    CFont类-字体

    CBitmap类-位图
    CRgn类-区域(可以进行计算的区域)
    CPalette类-调色板
    3 使用
    3.1 画笔、画刷和字体的使用步骤
    3.1.1 创建或者构造绘图对象
    3.1.2 将绘图对象选入到当前设备
    3.1.3 使用绘图对象
    3.1.4 恢复到默认的绘图对象
    3.1.5 删除绘图对象
    3.2 位图的使用步骤
    3.2.1 创建与当前窗口dc的兼容dc
    CDC::CreateCompatibleDC
    3.2.2 加载位图(将位图对象与位图资源建立关联)
    CBitmap::LoadBitmap
    3.2.3 将位图对象选入到兼容dc中
    CDC::SelectObject
    3.2.4 将位图从兼容dc拷贝到当前dc
    CDC::BitBlt
    CDC::StretchBlt-可以拉伸或者压缩图片
    3.2.5 绘图兼容dc的默认位图对象
    3.2.6 删除兼容dc和位图对象
    使用该功能,可以被视图添加背景图片

    3.3 CRgn类的使用步骤
    3.3.1 创建几何区域
    CRgn::CreateXXX
    3.3.2 将两个几何区域进行运算的到复杂的几何区域
    CRgn::CombineRgn
    注意:运算可以进行多次
    3.3.3 填充几何区域
    CDC::FillRgn
    3.3.4 填空几何区域的边框
    CDC::FrameRgn
    应用:
    CWnd::SetWindowRgn-设置不规则的窗口形状

    CPalette类-调色板,作用降低位图占用的空间大小。
    RGB(0~255,0~255,0~255),24位真彩色。
    800*600的位图,真彩色位图:800*600*3个字节
    调色板:3*48 48色位图:800*600*1(颜色表中的索引值)+3*48
    二 MFC绘图的例子
    1 分析
    1.1 图形包括 直线、矩形和椭圆,所需数据是起点和终点。
    1.2 处理的消息:
    1.2.1 LBUTTONDOWN-记录图形的起点坐标,开始画线
    1.2.2 MOUSEMOVE-判断如果开始画线,擦除原来的线
    (用与屏幕相同的颜色在相同位置画线),画出新的线。
    1.2.3 LBUTTONUP-画线结束。
    2 实现
    2.1 绘图如何解决屏幕闪烁?
    办法:1 使用双缓冲区绘图 2 局部刷新代替全部刷新
    2.2 OpenGL库,Direct Draw
    三 MFC的文件操作
    1 相关类
    CFile类-封装了文件句柄和相关操作的win32 api。
    CFileFind类-文件查找。
    2 CFile类的使用
    2.1 打开或者新建文件
    CFile::Open
    2.2 文件读写
    CFile::Read/Write
    注意:通常放到异常处理结构中。读写操作时,注意当前
    的文件指针。
    2.3 关闭文件
    CFile::Close
    2.4 获取/设置文件的状态信息(属性)
    CFile::GetStatus/SetStatus
    3 CFileFind类的使用
    3.1 开始查找,返回值代表是否找到文件
    CFileFind::FindFile
    3.2 查找一下,(获取第一个文件信息,返回下一个文件是否存在)
    CFileFind::FindNextFile
    3.3 获取和判断文件信息
    CFileFind::GetXXX和IsXXX
    3.4 关闭查找
    CFileFind::Close
    作业:
    1 使用CFileFind类查找并输出C盘根目录下的文件和目录
    2 使用CFileFind类查找并输出C盘下所有的文件和目录

    ------------------------------------------

    一 序列化
    1 概念
    以二进制流的方式将数据依次写入到文件或者从文件中读取
    2 相关类
    CFile类
    CArchive类-提供具体读写文件的操作,代替CFile::Read/Write
    优点:1 可以设置缓冲区大小 2 读写各种数据类型更方便。
    3 使用
    3.1 打开或者新建文件
    3.2 文件读写操作
    3.2.1 定义CArchive类的对象
    3.2.2 使用">>","<<"进行文件读写
    3.2.3 关闭CArchive对象
    3.3 关闭文件
    二 对象的序列化(MFC的第6个机制),有的书上称为串行化
    1 概念
    序列化对象(至少需要运行时类信息的支持)
    以二进制流的方式将对象的类的信息以及对象的成员变量依次写入
    到文件的过程,称为序列化对象。
    反序列化对象(至少需要动态创建的支持)
    以二进制的方式从文件中读取类的信息创建对象,然后依次读取
    保存的值初始化新创建的对象。这个过程称为反序列化对象。
    2 实现
    2.1 定义支持序列化的类
    2.1.1 派生自CObject类
    2.1.2 添加序列化的声明和实现宏
    2.1.3 重写CObject::Serialize 函数,在函数中,将类的
    成员变量序列化。
    2.2 使用
    对象的序列化的过程与一般变量类似,注意在读写时,">>"
    "<<"函数的参数是对象的地址。
    3 实现原理
    3.1 展开宏
    3.1.1 一个动态创建宏和一个友元函数
    3.1.2 结构体类型的变量_init_CStudent的作用是
    将当前类的运行时类信息的地址保存到应用程序的链表中
    struct AFX_CLASSINIT
    {
    //构造函数
    AFX_CLASSINIT(CRuntimeClass* pNewClass)
    {
    AfxClassInit(pNewClass);
    }
    };
    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
    {
    //获取应用程序的模块状态信息
    AFX_MODULE_STATE* pModuleState =
    AfxGetModuleState();
    AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
    //将当前类的运行时类信息的地址保存到应用程序的链表中
    pModuleState->m_classList.AddHead(pNewClass);
    AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
    }
    3.2 序列化对象的过程
    CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb)
    {
    ar.WriteObject(pOb);
    return ar;
    }
    ar.WriteObject(pOb)
    {
    //1 获取当前类的运行时类信息的地址
    CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
    //2 将类的版本号、类名称长度和类名写入文件
    WriteClass(pClassRef);
    //3 将类的成员变量姓名和年龄依次写入到文件
    ((CObject*)pOb)->Serialize(*this)
    {
    CObject::Serialize(ar);
    if (ar.IsStoring())
    {
    ar<<m_strName<<m_nAge;
    }
    else
    {
    ar>>m_strName>>m_nAge;
    }
    }
    }
    WriteClass(pClassRef)
    {
    pClassRef->Store(*this); 252行
    }
    pClassRef->Store(*this)
    {
    //获取类名称字符串长度
    WORD nLen = (WORD)lstrlenA(m_lpszClassName);
    //首先写入类的版本和类名称长度
    ar << (WORD)m_wSchema << nLen;
    //其次写入类名称字符串
    ar.Write(m_lpszClassName, nLen*sizeof(char));
    }
    3.3 反序列化对象的过程
    CArchive& AFXAPI operator>>(CArchive& ar, CStudent* &pOb)
    {
    pOb = (CStudent*)
    ar.ReadObject(RUNTIME_CLASS(CStudent));
    return ar;
    }
    ar.ReadObject(RUNTIME_CLASS(CStudent))
    {
    //1 从文件中读取类名,遍历链表找到运行时信息
    CRuntimeClass* pClassRef = ReadClass(...); 125行
    //2 使用运行时类信息的变量创建对象
    pOb = pClassRef->CreateObject(); 150行
    //3 从文件中读取成员变量初始化新建的对象
    pOb->Serialize(*this); 161行
    {
    ...
    }
    }
    CRuntimeClass* pClassRef = ReadClass(...)
    {
    pClassRef = CRuntimeClass::Load(); 301行
    }
    CRuntimeClass::Load(...)
    {
    //依次从文件中,读取类的版本、类名称长度和类名
    ar >> wTemp; *pwSchemaNum = wTemp;
    ar >> nLen;

    if (nLen >= _countof(szClassName) ||
    ar.Read(szClassName, nLen*sizeof(char)) != nLen*sizeof(char))
    {
    return NULL;
    }
    //将类名保存在szClassName这个数组中
    szClassName[nLen] = '';
    //获取应用程序的模块状态信息
    AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
    AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
    //遍历模块状态信息中保存各个类的运行时类信息变量地址的链表
    for (pClass = pModuleState->m_classList; pClass != NULL;
    pClass = pClass->m_pNextClass)
    {
    比较类的名称,如果在链表中找到,则返回变量的地址
    if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
    {
    AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
    return pClass;
    }
    }

    }

    三 MFC对话框
    1 分类
    模式和非模式
    2 相关类
    CDialog类-父类是CWnd,本质上是一个窗口,拥有自己的资源,
    方便的拖放控件。所有对话框类的父类。
    CCommonDialog类-通用对话框类,包括文件对话框、颜色对话框
    字体对话框、查找替换对话框、打印和打印设置对话框。
    CPropertyPage类-属性页对话框。
    3 在Win32工程中使用MFC的类创建基于对话框的应用程序
    3.1 模式对话框
    3.1.1 创建和显示
    CDialog::DoModal()
    3.1.2 关闭
    CDialog::OnOK/OnCancel
    3.1.3 对话框的初始化
    CDialog::OnInitDialog
    3.2 非模式对话框
    3.2.1 创建和显示
    创建和显示与一般的框架窗口过程相似
    3.2.2 关闭
    非模式对话框的关闭需要程序员处理
    1 重写CDialog::OnOK和OnCancel这两个虚函数,在
    函数中,DestroyWindow()
    2 重写CWnd::PostNcDestroy()虚函数。在函数中,
    delete this;
    3.2.3 对话框的初始化
    CDialog::OnInitDialog
    思考:为什么模式对话框不需要程序员去销毁?
    提示: 跟一下DoModal()函数的执行过程

  • 相关阅读:
    用醋泡脚有什么好处
    用姜泡脚有什么好处
    坚持跑步与读书,方不辜负此生
    干货!几招教你降低论文重复率!!
    Android Handler 源码分析(详细)
    教你控制 RecyclerView 滑动的节奏
    鸟哥的Linux私房菜:基础学习篇 —— 第六章笔记
    鸟哥的Linux私房菜:基础学习篇 —— 第五章笔记
    synchronized(this) 与synchronized(class) 之间的区别
    Android 扩大 View 的点击区域
  • 原文地址:https://www.cnblogs.com/Renekton/p/3864149.html
Copyright © 2011-2022 走看看