MFC单文档多视图程序设计与Splitter拆分窗口

1. 创建不同的子frame.

在文档视图程序中 CMainFrame(class CMainFrame : public CMDIFrameWndEx) 继承自 CMDIFrameWnd (CMDIFrameWndEx 为 CMDIFrameWnd子类). 因此可以将 m_pMainWnd 转为 CMDIFrameWnd 的指针, 再调用 CreateNewChild 创建一个子frame. 此时可根据传入的具体的类名, 强制转换为所需的对象.

    CMDIFrameWnd* pMdiFrmWnd = reinterpret_cast<CMDIFrameWnd*>(m_pMainWnd);
    m_pChildFrm = reinterpret_cast<CChildFrm*> (pMdiFrmWnd->CreateNewChild(RUNTIME_CLASS(CChildFrm), IDR_MAINFRAME));
    m_pChildFrm->ShowWindow(SW_SHOW);

2. CSplitterWnd 拆分窗口.

拆分窗口在 CMDIChildWnd 子类的 OnCreateClient 方法中进行. 首先使用 CreateStatic 可以将窗口进行拆分, 最大支持 16 x 16.
然后 CreateView 对不同的区域设置不同的 CView, 完成之后使用 CSplitterWnd 对象的 GetPane 方法可以取得不同区域的CWnd指针, 将其强转为设置的 CView 子类即可.
注意: (1) CreateStatic 创建的每一个区域都必须使用 CreateView 设置一个 CView的子类, 或者使用另一个 CSplitterWnd 填充进行继续拆分.
        (2) CreateView 传入的必须是 CView 的子类, 不能使用Ctrl或Dialog, 对于控件如CEdit, 可以使用 CEditView 代替, 其它如CCtrlView类等. 对于使用资源的对话框类, 可以使用 CFormView.

BOOL CChildFrm::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
{
    // 创建拆分窗口
    if (!m_wndSplitter.CreateStatic(this, 2, 1))
        return FALSE;

    if (!m_wndSplitterTop.CreateStatic(&m_wndSplitter, 1, 3, WS_CHILD | WS_VISIBLE, m_wndSplitter.IdFromRowCol(0, 0)))
    {
        return FALSE;
    }

    if (!m_wndSplitterTop.CreateView(0, 0, RUNTIME_CLASS(CLeftView), CSize(0, 0), pContext))
    {
        return FALSE;
    }

    if (!m_wndSplitterTop.CreateView(0, 1, RUNTIME_CLASS(CSpliteDemoView), CSize(0, 0), pContext))
    {
        return FALSE;
    }

    if (!m_wndSplitterTop.CreateView(0, 2, RUNTIME_CLASS(CSpliteDemoView), CSize(0, 0), pContext))
    {
        return FALSE;
    }

    if (!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CCtrlsView), CSize(0, 0), pContext))
    {
        return FALSE;
    }

    m_pLeftView = reinterpret_cast<CLeftView*>(m_wndSplitterTop.GetPane(0, 0));
    m_pMidView = reinterpret_cast<CSpliteDemoView*>(m_wndSplitterTop.GetPane(0, 1));
    m_pRightView = reinterpret_cast<CSpliteDemoView*>(m_wndSplitterTop.GetPane(0, 2));

    m_pCtrls = reinterpret_cast<CCtrlsView*>(m_wndSplitter.GetPane(1, 0));

    return TRUE;
}

3. CSplitterWnd 大小调整

窗口大小改变后会调用 OnSize 方法(需在消息映射表中添加ON_WM_SIZE()), 此时一般需要修改 splitter及各个子 view的大小和位置. 其中 splitter 调整后需要调用 SetRowInfo 和 SetColumnInfo 来重新设置分隔条的位置.
注意,初始化过程中 OnSize 方法会被多次调用, 部分窗口可能还没有创建, 因此需要作判断.

BEGIN_MESSAGE_MAP(CChildFrm, CMDIChildWndEx)
    ON_WM_SIZE()
    ON_MESSAGE(UM_INPUT_TEXT, &CChildFrm::OnInputText)
END_MESSAGE_MAP()

void CChildFrm::OnSize(UINT nType, int cx, int cy)
{
    CMDIChildWndEx::OnSize(nType, cx, cy);

    if (::IsWindow(m_wndSplitterTop))
    {
        CRect rect;
        GetClientRect(rect);
        m_wndSplitter.MoveWindow(rect);

        int nHeight = rect.Height() - 50;
        if (nHeight < 0)
            nHeight = 0;
        m_wndSplitterTop.MoveWindow(rect.left, rect.top, rect.right, nHeight);

        m_wndSplitter.SetRowInfo(0, nHeight, 0);
        m_wndSplitter.RecalcLayout();

        m_wndSplitterTop.GetClientRect(rect);
        int nWidth = rect.Width() / 3;
        m_wndSplitterTop.GetPane(0, 0)->MoveWindow(rect.left, rect.top, nWidth, rect.bottom);
        m_wndSplitterTop.GetPane(0, 1)->MoveWindow(nWidth, rect.top, nWidth * 2, rect.bottom);
        m_wndSplitterTop.GetPane(0, 2)->MoveWindow(nWidth * 2, rect.top, rect.right, rect.bottom);

        m_wndSplitterTop.SetColumnInfo(0, nWidth, 0);
        m_wndSplitterTop.SetColumnInfo(1, nWidth, 0);
        m_wndSplitterTop.RecalcLayout();

        m_wndSplitter.GetClientRect(rect);

        m_pCtrls->OnSize(nType, cx, cy);
    }
}

4. Frame中的消息分发

一个 frame 中通常包含多个子 view. 某个子 view 的消息通常需要传递到其它的子 view 中, 亦或者某些耗时操作需要到子线程中处理后更新到界面, 此时都需要涉及消息处理.
某个子 view 通知到其它的子 view时, 通常时先传递到 frame中, 再进行分发处理. 然后其它感兴趣的子 view 再响应此消息.
对于子线程的处理结果, 最好是 PostMessage 返回一个 new 创建的对象, 由 frame 使用 SendMessage 通知到各个子 view 处理后, 再释放.

void CCtrlsView::OnBnClickedButtonConfirm()
{
    CString* pStrText = new CString();
    CWnd* pWnd = GetDlgItem(IDC_EDIT);
    pWnd->GetWindowTextW(*pStrText);
    pWnd->SetWindowText(_T(""));
    GetParentFrame()->SendMessage(UM_ADD_TEXT, (WPARAM) pStrText, 0);
}

LRESULT CChildFrm::OnInputText(WPARAM wParam, LPARAM lParam)
{
    m_pLeftView->SendMessage(UM_ADD_TEXT, wParam, lParam);
    m_pMidView->SendMessage(UM_ADD_TEXT, wParam, lParam);
    m_pRightView->SendMessage(UM_ADD_TEXT, wParam, lParam);

    CString* pStr = (CString*) wParam;
    if (pStr)
    {
        delete pStr;
        pStr = NULL;
    }
    return 0;
}

LRESULT CSpliteDemoView::OnInputText(WPARAM wParam, LPARAM lParam)
{
    CString str = *(CString*)(wParam);
    CListCtrl* pListCtrl = &GetListCtrl();
    pListCtrl->InsertItem(pListCtrl->GetItemCount(), str);
    return 0;
}

5. 工作线程的设计

  创建线程, 在需要此工作线程事件触发时创建即可.

void CChildFrm::CreateWorkThread()
{
    if (!m_hWorkThread)
    {
        m_hWorkThread = CreateThread(NULL, 0, WordThreadFun, this, 0, &m_dwWordThreadId);
        Sleep(10); // 稍微等一下,切换一下线程,等待线程创建
    }
}

  框架中, 创建一个事件用于等持线程退出. 在析构函数或其它不需要此工作线程的地方, 发送一个退出的消息.

CChildFrm::CChildFrm()
{
    m_hWorkThreadExit = ::CreateEvent(NULL, TRUE, TRUE, _T(""));

    CreateWorkThread();
}

CChildFrm::~CChildFrm()
{
    if (m_hWorkThreadExit)
    {
        ::PostThreadMessage(m_dwWordThreadId, WM_QUIT, 0, 0);
        WaitForSingleObject(m_hWorkThreadExit, 2000);
        CloseHandle(m_hWorkThreadExit);
        m_hWorkThreadExit = NULL;
    }
}

  工作线程函数体中处理不同的消息, 其它线程使用 PostThreadMessage 通知工作线程工作. 工作线程退出时, 设置事件为有信号状态.

DWORD WINAPI CChildFrm::WordThreadFun(LPVOID lpParam)
{
    CChildFrm* pMain = (CChildFrm*)lpParam;
    ::ResetEvent(pMain->m_hWorkThreadExit);

    BOOL isRun = TRUE;
    MSG msg = {0};
    ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
    while (isRun)
    {
        GetMessage(&msg, NULL, 0, 0);
        switch (msg.message)
        {
        case WM_QUIT:
            isRun = FALSE;
            break;
        case WM_GETTIME:
            {
                SYSTEMTIME systime = {0};
                ::GetLocalTime(&systime);
                CString* pStr = new CString();
                pStr->Format(_T("%04d-%02d-%02d %02d:%02d:%02d"), systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond);

                pMain->PostMessage(UM_ADD_TEXT, (WPARAM) pStr, 0);
            }
            break;
        default:
            break;
        }
    }

    if (pMain->m_hWorkThread)
    {
        CloseHandle(pMain->m_hWorkThread);
        pMain->m_hWorkThread = NULL;
    }

    ::SetEvent(pMain->m_hWorkThreadExit);
    return 0;
}

源码:

http://download.csdn.net/detail/diysoul/9631904

时间: 2024-10-13 12:17:46

MFC单文档多视图程序设计与Splitter拆分窗口的相关文章

MFC单文档的视图分割

最近做的工作里包括了MFC单文档的分割,过程很简单,但还是想记录下来. 如下进行了单文档分割为三个视图的操作: 1 利用类向导建立额外的两个view  基类是CView 2 在mainFirm.cpp中包含两个新加的view的头文件 3 在mainFirm.h中添加分割窗口的成员变量CSplitterWnd m_wndSplitter; 4 在mainFirm.cpp中重写oncreateclient BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT

VC项目开发之单文档多视图实现-非分割窗口[转]

k_eckel:http://www.mscenter.edu.cn/blog/k_eckel 多视图是VC开发中经常要用到的技术之一,一般地实现单文档多视图有两种方式 1)通过视图分割的技术(使用CSplitterWnd实现),将窗口分割为多个部分,每个部分显示各自显示不同的视图,这种技术实现起来比较简单,并且相关的资料也很多. 2)通过一个文档关联多个视图,窗口显示整个视图. 第二种实现较第一种复杂,这里给出详细的实现方法. Step 1:使用VC 6.0新建一个Project,命名为:Mu

C++MFC编程笔记day07 MFC单文档绘图保存、多文档绘图保存

完善绘图例子(day06中的),加上保存功能 1 设计和编写图形类 CShape 1.1 成员变量 CPoint m_ptBegin; CPoint m_ptEnd; UINT m_nType; 1.2 支持序列化 1.2.1 继承自CObject 1.2.2 添加序列化的声明宏和实现宏 1.2.3 重写虚函数Serilize(),在函数中,完成成员变量的序列化 2 由于保存多个图形,引入MFC的集合类CObArray,保存的是CObject 对象的地址. 3 图形数据需要保存到文档类中,在该类

openGL三维网格坐标,旋转,缩放,灯光设置,纹理读取,模型读取(MFC单文档)

最近学习计算机图形学写的基于opengGL的作业 源码下载链接:链接:http://pan.baidu.com/s/1slANShZ 密码:hbwj 1.三维网格坐标建立 2.基本3维图形创建 3.鼠标相应旋转缩放 4.键盘相应旋转缩放 5.灯光设置 6.纹理载入映射 7.读取模型 关于MFC配置编写openGL网上有很多教程 需要的函数创建一般是: OnCreat() OnDestroy() Onsize() PreCreateWindow() OnDraw() 在我的MFC单文档项目中ena

7.MFC单文档视图构架程序

一.单文档视图构架程序 1.相关问题 只能管理一个文档(只有一个文档类对象) 2.相关类 CWinApp / CFrameWnd / CView / CDocument CDocTemplate - 文档模板类 CSingleDocTemplate - 当文档模板类 CDocManager - 文档管理类 3.关系图

[转载]MFC一个文档不同视图

MDI(MultipleDocument Interface)是Windows界面的一种规范,它建立多个窗口来浏览文档数据,如Windows中的ProgramManager等都是按MDI规范实现的.在实际工程软件开发中,许多程序员将其作为一种实现多窗口的标准方法.微软基础类库(MicrosoftFoundationClassLibrary,简称MFC库),是微软公司为方便Windows程序开发所提供的一个功能强大的通用类库.MFC的核心是以类的形式封装了大量WindowsAPI.在可视化编程语言

MFC单文档下使用非模态对话框

由于自己写的程序是自动获取桌面实时图像,所以用模态对话框导致程序出错,目前粗鄙的理解是模态对话框会让对话框所在线程暂停,当关闭对话框后才能继续操作,而非模态对话框可以不必让程序暂停. 下面记录非模态对话框的创建过程: 1 在单文档中新建一个对话框资源并生成对话框类 CRadiusDlg 2 在视图类C**view.cpp中添加对话框的头文件,并添加一个对话框类的指针变量CRadiusDlg *pModalessDlg; 3 在菜单栏添加一个用于显示对话框的菜单项,并在响应事件处,添加事件处理代码

MFC单文档分割区(CSplitterWnd)

用VS08程序向导,单文档程序,默认设置生成的.工程名为3view; 其中默认生成的视图类CMy3viewView,对应3viewView.h,3viewView.cpp; 默认生成的文档类为:3viewDoc.h,3viewDoc.cpp; 在主框架头文件MainFrm.h中添加如下头文件: //为了后面好创建程序默认的视CMy3viewView: #include "3viewDoc.h"#include "3viewView.h" 并添加如下变量 CSplit

VTk与MFC单文档程序联合编程

兴趣需要,想做下VTK与MFC想结合的程序,MFC快要在桌面程序上面失去市场份额了,现在大多使用QT来做,但是本科的时候学的就是MFC,也相对来说比较熟悉,所以就想使用MFC来写一个简单的单文档程序.首先我们需要在编译的时候将USEGUISUPPORT->USEMFC勾选上,才能在MFC平台上使用VTK.网络上现在大多流行两种VTK和MFC的方法,其实两者结合的关键就是将VTK的绘制窗口vtkrenderwindow与MFC中的view窗口相一致,让VTK上的绘制图形能够在MFC上的VIEW类上