利用窗口分割将多EXE嵌入统一程序(MFC)

窗口分割的必要性:有时候我们需要在一个窗口内显示不同的信息,类似于下图所示,每个窗口直接交互并不大,或者我们需要将一个exe嵌入到一个窗口中,这样就用到了窗口分割。窗口分割技术在MFC的单文档文件中比较容易实现,其他编程语言或者对话框可能也可以实现,但是实现起来比较复杂,与此同时没有现成的例子或者函数。

利用窗口分割将多EXE嵌入统一程序(MFC)_第1张图片

实现窗口分割的步骤:

(1)建立一个单文档程序:新建—项目—Visual C++—MFC应用程序,选择单文档,不需要拆分窗口,因为如果选择了拆分窗口,系统会给你定义一个窗口分割变量,不如自己直接定义可操作性强。这里我建立的程序名称叫DisplayCenter。

(2)在在MainFrm.h中添加分割窗口的变量声明。

//分割窗口变量
	CSplitterWnd VSplitter; //用于纵向切割
	CSplitterWnd HSplitter1; //用于横向切割
	CSplitterWnd HSplitter2; //用于横向切割
//标识窗口分割是否完成
	BOOL IsSplitDone;

为什么要定义三个分割窗口的变量呢?因为后面我们肯定要调整分割窗口的大小,如果你要设置的N个窗口一样大,那就完全没必要用多个分割窗口变量,但是往往我们分隔的窗口如图6所示,并非一样大,那么就需要定义几个不同的分割变量,来对应控制相应的大小,这个在后面会讲到。最后一个布尔型变量用于标志窗口分割是否已经完成,为什么需要这个变量呢?因为后面我们可能要调整每个窗口的大小,但是调整和创建是有先后顺序的,也就是要先对大窗口进行分割,分割完了才能调整每个小窗口的大小,有了这个变量,就方便我们对窗口分割是否完成做好判断。

(3)并在CMainFrame的构造函数中,初始化IsSplitDone为FALSE。

CMainFrame::CMainFrame()
{
	// TODO: 在此添加成员初始化代码
	IsSplitDone = FALSE;
}

(4)重载OnCreateClient()函数,进行窗口的分割

在类视图中点击CmainFrame,然后点击属性中的重写栏,找到OnCreateClient并添加,如图7所示:

                                                         利用窗口分割将多EXE嵌入统一程序(MFC)_第2张图片

在重载函数中添加窗口分割代码:

//获取客户区大小
	CRect cr;
	GetClientRect(&cr);


	// 如果纵向分割(分成*2的)不成功,返回
	if(!VSplitter.CreateStatic(this,1,2))
	{
		return FALSE;
	}
	//纵向分割完成后对第一行一列横向分割,分成2*1的
	if(HSplitter1.CreateStatic(&VSplitter,2,1,WS_CHILD|WS_VISIBLE, 
		VSplitter.IdFromRowCol(0, 0))==NULL) 
	{
		return FALSE; //将第行列再分开行列
	}

	//绑定相应的视类
	if (!HSplitter1.CreateView(0,0,RUNTIME_CLASS(PPIshow),CSize(100,200),pContext) )
	{
		return FALSE;
	}
	if (!HSplitter1.CreateView(1,0,RUNTIME_CLASS(CDisplayCenterView),CSize(100,200),pContext) )
	{
		return FALSE;
	}
	//纵向分割完成后对第一行二列横向分割,分成2*1的
	if(HSplitter2.CreateStatic(&VSplitter,2,1,WS_CHILD|WS_VISIBLE, 
		VSplitter.IdFromRowCol(0, 1))==NULL) 
	{
		return FALSE; //将第行列再分开行列
	}
	//绑定相应的视类
	if (!HSplitter2.CreateView(0,0,RUNTIME_CLASS(CDisplayCenterView),CSize(100,200),pContext) )
	{
		return FALSE;
	}
	if (!HSplitter2.CreateView(1,0,RUNTIME_CLASS(CDisplayCenterView),CSize(100,200),pContext) )
	{
		return FALSE;
	}

	//标志位置为True,标志窗口分割完成,用于后面onsize判断
	IsSplitDone = TRUE;
	return TRUE;

对于其中CreateStatic、CreateView函数每个参数的含义,具体用法这里不再赘述,具体可查询MSDN,这里简单的说明一下,CreateStatic是创建静态窗口分割,就是把窗口分割开来,分割完了之后,每个窗口肯定要显示一些东西,那么就需要与视类进行绑定,CreateView完成的就是与视类进行绑定的作用。

(5)头文件声明

在(4)中进行视类绑定的时候,调用了一些视类,要把视类想对应的头文件引用声明在MainFrm.cpp里面,也就是:

//调用了其他的视类和文档类,进行声明
#include "DisplayCenterView.h"
#include "DisplayCenterDoc.h"
#include "PPIshow.h"
//调用了打开exe的Windows API,进行声明
#include "shellapi.h"

(6)创建一个自己的视类

从(4)中绑定视类中可以看到,我们的第一个窗口绑定的是一个名叫PPIshow的类,其他三个是自动生成的View类,这个PPIshow类是我自己创建的一个视类,这也是非常正常的,一般我们都要自己写视类,一般的视类都基类都是Cview,同时我重载了Ondraw函数;激活了WM_CREATE消息,也就是OnCeate函数,用于视类的初始化;激活了WM_SIZE消息,也就是OnSize函数,用于控制窗口大小变化时候的窗口处理。此外,这样的视类是没法直接绑定的,会提示说创建空白文档失败,此时你要在这个视类的源文件(cpp文件)和头文件(h文件)中声明,声明的位置如图8、图9所示,声明之后,即可正常绑定视类。

IMPLEMENT_DYNCREATE(PPIshow,CView)

DECLARE_DYNCREATE(PPIshow)

                               利用窗口分割将多EXE嵌入统一程序(MFC)_第3张图片

                                                                       利用窗口分割将多EXE嵌入统一程序(MFC)_第4张图片

(7)在分割窗口中嵌入EXE

在分割窗口中绑定视类之后,有时候我们要将这个视类里面嵌入一个我们自己写的EXE,这个我仅以一段代码例子来进行简单介绍,需要调用的头文件为#include"shellapi.h"。

//查看P显和B显是否已经打开,默认开P显
	CWnd* pWnd = CWnd::FindWindowA(NULL,"PPI显示器");
	CWnd* BWnd = CWnd::FindWindowA(NULL,"B显");
	//如果没有打开,那么把P显最大化打开,B显最小化打开(即不显示)
	if (!pWnd)
	{
		HINSTANCE m=ShellExecute(m_hWnd,"open","ppiView.exe",NULL,NULL,SW_SHOWMAXIMIZED);
	}

	if (!BWnd)
	{
		HINSTANCE m=ShellExecute(m_hWnd,"open","BView.exe",NULL,NULL,SW_SHOWMINIMIZED);
	}
	//缓冲毫秒,防止程序卡死
	Sleep(500);
	//查找P显的窗口,并将P显嵌入到相应的窗口里面
	m_hFig = ::FindWindow(NULL,"PPI显示器");   
	if(::IsWindow(m_hFig))   
	{   
		//通过SetParent设置父窗口将P显嵌入
		::SetParent(m_hFig,this->m_hWnd);  
		CWnd * pWnd = NULL; 
		//找到相应的CWnd
		pWnd = FromHandle(m_hFig);
		//获取客户区大小,方便填满
		CRect rect;   
		this->GetClientRect(&rect); 
		pWnd->MoveWindow(&rect,false); 
		//去掉边框什么的
		pWnd->ModifyStyle(WS_CAPTION|WS_BORDER|WS_THICKFRAME,0); 
		//将EXE显示出来
		pWnd->ShowWindow(SW_SHOW);
	}


	m1_hFig = ::FindWindow(NULL,"B显");   
	if(::IsWindow(m1_hFig))   
	{   
		//::SetParent(m_hFig,this->GetSafeHwnd());  
		::SetParent(m1_hFig,this->m_hWnd);  
		CWnd * pWnd = NULL;   
		pWnd = FromHandle(m1_hFig);   
		CRect rect;   
		this->GetClientRect(&rect); 
		pWnd->MoveWindow(&rect,true);   
		//pWnd->ModifyStyle(WS_CAPTION|WS_BORDER|WS_THICKFRAME,0); 
		pWnd->ShowWindow(SW_HIDE);
	}
UpdateData(FALSE);



你可能感兴趣的:(C/Cplusplus)