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, , ))
return FALSE; if (!m_wndSplitterTop.CreateStatic(&m_wndSplitter, , , WS_CHILD | WS_VISIBLE, m_wndSplitter.IdFromRowCol(, )))
{
return FALSE;
} if (!m_wndSplitterTop.CreateView(, , RUNTIME_CLASS(CLeftView), CSize(, ), pContext))
{
return FALSE;
} if (!m_wndSplitterTop.CreateView(, , RUNTIME_CLASS(CSpliteDemoView), CSize(, ), pContext))
{
return FALSE;
} if (!m_wndSplitterTop.CreateView(, , RUNTIME_CLASS(CSpliteDemoView), CSize(, ), pContext))
{
return FALSE;
} if (!m_wndSplitter.CreateView(, , RUNTIME_CLASS(CCtrlsView), CSize(, ), pContext))
{
return FALSE;
} m_pLeftView = reinterpret_cast<CLeftView*>(m_wndSplitterTop.GetPane(, ));
m_pMidView = reinterpret_cast<CSpliteDemoView*>(m_wndSplitterTop.GetPane(, ));
m_pRightView = reinterpret_cast<CSpliteDemoView*>(m_wndSplitterTop.GetPane(, )); m_pCtrls = reinterpret_cast<CCtrlsView*>(m_wndSplitter.GetPane(, )); 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() - ;
if (nHeight < )
nHeight = ;
m_wndSplitterTop.MoveWindow(rect.left, rect.top, rect.right, nHeight); m_wndSplitter.SetRowInfo(, nHeight, );
m_wndSplitter.RecalcLayout(); m_wndSplitterTop.GetClientRect(rect);
int nWidth = rect.Width() / ;
m_wndSplitterTop.GetPane(, )->MoveWindow(rect.left, rect.top, nWidth, rect.bottom);
m_wndSplitterTop.GetPane(, )->MoveWindow(nWidth, rect.top, nWidth * , rect.bottom);
m_wndSplitterTop.GetPane(, )->MoveWindow(nWidth * , rect.top, rect.right, rect.bottom); m_wndSplitterTop.SetColumnInfo(, nWidth, );
m_wndSplitterTop.SetColumnInfo(, nWidth, );
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, );
} 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 ;
} LRESULT CSpliteDemoView::OnInputText(WPARAM wParam, LPARAM lParam)
{
CString str = *(CString*)(wParam);
CListCtrl* pListCtrl = &GetListCtrl();
pListCtrl->InsertItem(pListCtrl->GetItemCount(), str);
return ;
}
5. 工作线程的设计
创建线程, 在需要此工作线程事件触发时创建即可.
void CChildFrm::CreateWorkThread()
{
if (!m_hWorkThread)
{
m_hWorkThread = CreateThread(NULL, , WordThreadFun, this, , &m_dwWordThreadId);
Sleep(); // 稍微等一下,切换一下线程,等待线程创建
}
}
框架中, 创建一个事件用于等持线程退出. 在析构函数或其它不需要此工作线程的地方, 发送一个退出的消息.
CChildFrm::CChildFrm()
{
m_hWorkThreadExit = ::CreateEvent(NULL, TRUE, TRUE, _T("")); CreateWorkThread();
} CChildFrm::~CChildFrm()
{
if (m_hWorkThreadExit)
{
::PostThreadMessage(m_dwWordThreadId, WM_QUIT, , );
WaitForSingleObject(m_hWorkThreadExit, );
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 = {};
::PeekMessage(&msg, NULL, , , PM_REMOVE);
while (isRun)
{
GetMessage(&msg, NULL, , );
switch (msg.message)
{
case WM_QUIT:
isRun = FALSE;
break;
case WM_GETTIME:
{
SYSTEMTIME systime = {};
::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, );
}
break;
default:
break;
}
} if (pMain->m_hWorkThread)
{
CloseHandle(pMain->m_hWorkThread);
pMain->m_hWorkThread = NULL;
} ::SetEvent(pMain->m_hWorkThreadExit);
return ;
}
源码:
http://download.csdn.net/detail/diysoul/9631904
MFC单文档多视图程序设计与Splitter拆分窗口的更多相关文章
- MFC单文档
一.创建并运行MFC单文档程序 1.创建单文档程序 这里使用的是VS2017.首先,打开VS2017,选择文件->新建->项目,然后选择Visual C++ -> MFC /ATL& ...
- MFC单文档框架分析及执行流程(转)
原文转自 https://blog.csdn.net/u011619422/article/details/40402705 首先来分析一下MFC单文档类的结构: 它包括如下几个类: CAboutDl ...
- VC-基础:MFC单文档程序架构解析
MFC单文档程序架构解析 这里我以科院杨老师的单文档程序来分析一下MFC单文档的程序架构,纯属个人见解,不当之处烦请指教! 首先我们了解到的是 图(一) theApp 是唯一一个在程序形成的时候就存在 ...
- MFC单文档程序架构解析
MFC单文档程序架构解析 MFC单文档程序架构解析 这里我以科院杨老师的单文档程序来分析一下MFC单文档的程序架构,纯属个人见解,不当之处烦请指教! 首先我们了解到的是 图(一) theApp 是唯一 ...
- MFC单文档程序结构
MFC单文档程序结构三方面: Doc MainFrame View
- VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误
1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...
- MFC单文档视图程序简介
在视图应用程序中,应用程序的数据由文档对象代表,数据的视图由视图对象代表.MFC的Cdocument类是文档对象的基类,Cview类是视图对象的基类.应用程序的主窗口,其操作功能在MFC的Cframe ...
- MFC单文档视图中嵌入GLFW窗口
开始学习OpenGL由于有一段时间,但是glfw只有窗口区,虽然通过某种手段(移步这里)可以加入工具栏,但仍然无法作为一个标准的GUI,而直接在MFC或Qt里面使用OpenGL API感觉有诸多制肘, ...
- 【2016.3.30项目技术记录】]VS2010自动生成MFC单文档框架程序的修改:去除属性框,在CViewTree类中添加鼠标单击响应
转自http://blog.csdn.net/yanfeiouc2009/archive/2010/06/07/5653360.aspx 手头上有个东西要用到单文档,由于想省事,直接用VS2010做了 ...
随机推荐
- Ducci序列 (Ducci Sequence,ACM/ICPC Seoul 2009,UVa1594)
题目描述: 题目思路: 直接模拟 #include<stdio.h> #include<string.h> #define maxn 105 int less(const ch ...
- spark集群安装部署
通过Ambari(HDP)或者Cloudera Management (CDH)等集群管理服务安装和部署在此不多介绍,只需要在界面直接操作和配置即可,本文主要通过原生安装,熟悉安装配置流程. 1.选取 ...
- IMX6移植htop
top命令查看CPU利用率并不是很方便,因此打算移植htop到imx6上,主要包括以下几个步骤: - 资源下载 htop 下载http://hisham.hm/htop/releases/1.0.1/ ...
- spring学习(一)——控制反转简单例子
spring框架是一个开源的轻量级的基于IOC与AOP核心技术的容器框架,主要是解决企业的复杂操作实现. 那IOC与AOP,到底如何解释呢,在看spring视频中,两个专业术语一定必须要懂得. IOC ...
- Scrum 冲刺博客,项目总结
1.各个成员在 Alpha 阶段认领的任务 数据库环境的搭建,连接数据库:张陈东芳 数据库语句sql语句:张陈东芳 商品实体类的实现:吴敏烽 获取所有商品信息的实现:吴敏烽 根据商品编号获得商品资料: ...
- idea快捷键操作
在编写代码的时候直接输入psv就会看到一个psvm的提示,此时点击tab键一个main方法就写好了. psvm 也就是public static void main的首字母. 依次还有在方法体内键入f ...
- 【Linux】- CentOS搭建FTP服务器
1.安装vsftpd yum install -y vsftpd 2.启动vsftpd服务 service vsftpd start 3.查看运行状态 netstat -nltp | 完毕!!! 参考 ...
- 安全的API接口解决方案
在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...
- Visual Studio 2013中使用Ribbon For WPF
1.首先需要 下载Ribbon For WPF.目前最新的版本是Microsoft Ribbon for WPF October 2010. 下载 链接: https://www.microsoft. ...
- 【bzoj5107】[CodePlus2017]找爸爸 dp
题目描述 给出两个基因串,你需要在其中插入任意个空格,使得两个串长度相同.如果两个串的某同一位置都是字母则获得某给定收益,对于每个串的每个长度为k的连续空格段要付出a(k-1)+b的损失.求最大净收益 ...