第122讲 DirectX11Frame(2)

上一讲我们说关于这个框架用到的必要的基础信息,那么这一讲我们开始构造这个框架的基类,通常来说一个通用的基类一般只会提供接口信息,但是这里我们并不打算这么做,为什么呢?真正的接口我们将他放进后面的MDx11Window这个类,MDx11Window类是用于处理DirectX11窗口的信息的基类,而MDx11Window类派生于MObject类,那么既然我们使用的是MDx11犀利那么为什么又要从MObject类说起来呢?嗯,事情是这样的,在以前写这个Frame的时候并没有将MDx11考虑进去,当时只是将Windows的窗口进行按需封装,所以在这个Frame里面还有一系列的类,而这系列的类就是MWindow系列,使用MWindow系列一样能够简单的构架应用程序,而且MWindow一样支持DirectX11进行渲染,不过他的渲染方式和MDx11Window的渲染方式有所不同,MWindow的每一个控件都是有自己的HWND的,而MDX11Window的空间都是DirectX11绘制出来的,简单点说,MWindow是先有控件然后在控件上面进行绘制,而MDx11Window是直接在一块画布上绘制出控件以及所要的信息,MWindow不需要Lua脚本语言就能够绘制出界面,而MDx11Window需要Lua脚本语言的支持再能生成漂亮的界面,因为MDx11Window的界面信息全都是放在Lua脚本处理的。不过MDx11Window可以绘制出任何想要的界面类型,而MWindow就显得中规中矩,因为MWindow只是简单的封装Windows控件,即使使用DirectX11对控件进行渲染,也只能修改窗口控件背景而已,所以相对来说,MDx11Window就显得要炫酷得多。

好吧,扯了这些大家也算是对为什么我们要在这里写一个基类有所理解了,如我们一开始所说,这个基类几乎不干什么有用的事,他只是提供了一个方便性而已,让MDx11Window和MWindow拥有一套相同的事件处理方式而已。


//==============================================================================

#pragma once

#include "

MReflection.h"


//———————————————-

// 框架基础类

//———————————————-

class MObject

{

 

 

DECLARE_CLASS(MObject) // 如果想要动态创建,就需要使用该宏

public:

 

 

MObject();

 

 

virtual ~MObject();

 

 

MObject(const MObject&

) = delete;

 

 

MObject&

operator=(const MObject&

) = delete;

public:

 

 

std::shared_ptr<MClassFactory>GetObjFactory() const;

 

 

std::shared_ptr<MClassFactory>GetObjFactory();

 

 


void Clear();


 

 


 

 

//=================================================

 

 

// 下面的都是虚函数

 

 

// 根据不同情况进行改写

 

 

//=================================================

public:

virtual const MDx11String&

GetContexData() const;

virtual
void SetContexData(const MDx11String&

contex);

virtual MDx11String ToString() const;

 

 

virtual
void Show();

 

 

virtual
void Update();


 

 

//================================================

 

 

// 只有子类才能够访问的信息

 

 

//================================================

protected:

 

 

std::shared_ptr<MClassFactory>mClassFactory;


 

 

//===============================================

 

 

// 友员函数,对流输出的支持

 

 

//===============================================

 

 

friend std::ostream&

operator<<(std::ostream&

os,const MObject&

obj){

 

 

 

 

os<<obj.ToString()<<"

t"

<<&

obj<<std::endl;

 

 

 

 


return os;

 

 

}

MDx11String mContexData;

};


//===========================================================


对于所有的MObject派生的对象,我们是禁止拷贝和复制,mClassFactory这是我们在动态创建对象的时候所以使用的,mContexData我们用来保存空间信息的对象,比如保存一个文本框的所有内容,一个按钮的名字,一个列表控件的信息等等,而MDx11String这是一个字符串类,以前我们曾经介绍过一个MString的字符串类,而这个Frame原本我们使用的就是MString,但是后来发现在我们自己处理输入的情况的时候显得无法满足于是在MString的基础上重新架构了MDx11String,MDx11String不仅对MString兼容还同时对unicode字符的支持,而且修改了一些核心函数的实现方式,使得MDx11String有更好的鲁棒性(测试到现在没有发生任何运行问题)。

//===========================================================

#include "

MObject.h"


IMPLEMENT_CLASS(MObject)


MObject::MObject()

{

 

 

mClassFactory = MClassFactory::Instance();

}


MObject::~MObject()

{

}



void MObject::RegistProperty()

{

}


std::shared_ptr<MClassFactory>MObject::GetObjFactory() const

{

 

 

return mClassFactory;

}


std::shared_ptr<MClassFactory>MObject::GetObjFactory(){

 

 

return mClassFactory;

}


const MDx11String&

MObject::GetContexData() const{


return mContexData;

}


void MObject::SetContexData(const MDx11String&

contex){

mContexData = contex;

}



void MObject::Clear()

{

mContexData.clear();

}


MObject::operator MDx11String() const

{

 

 

return this->ToString();

}


MDx11String MObject::ToString() const

{

 

 

return this->MObjectName;

}


void MObject::Show()

{

}


void MObject::Update()

{

}

//===============================================

关于实现相当的简单,没啥可说,就是在构造函数中将我们的MClassFactory进行实例化即可。和MObject一样通用的是另一个类——事件处理类,在这个Frame中我们的事件管理使用的boost里面的signal,大家还记得吗?如果忘记的话可以回头去看看我们说的boost的信号槽。在这个事件管理类里面我们仅仅对四个参数一下的事件进行管理,当然还是可以扩展的,但是因为没有多少场合会是应用超过4个参数的事件回调函数,而传递的参数我们使用的是boost的any类型,any,顾名思义他可以是任意的类型,但是需要付出的代价是在我们写回调函数的时候需要对参数进行转换,而转换函数便是AnyTypeCast,如果转换成功我们就获取参数的指针,如果不成功就是一个未初始化的opional,这个是不能使用的。


//===============================================

#pragma once

//=========================================================

// 该类用来管理事件的处理状态

// 当然可以直接使用MKeyEvent 和 MMouseEvent进行处理事件

//=========================================================

#include <boost/signals2.hpp>

#include "

MReflection.h"

#include <iostream>

#include <thread>

#include <condition_variable>

#include <mutex>


class MObject;


//———————————————-

// 事件回掉函数

//———————————————-

typedef const boost::any&

AnyType;

// 使用下面的转换函数可以转换到正确的类型


//———————————————————

// 需要对返回结果进行判断是否转换成功

//———————————————————

template<class T>

boost::optional<T>AnyTypeCast(AnyType any){

try{


return boost::optional<T>(boost::any_cast<T>(any));

}

catch (boost::bad_any_cast e){


return boost::optional<T>();

}

}


//—————————————————————

// 定义几种事件驱动类型

//—————————————————————

typedef boost::signals2::signal<void(MObject*)>EventNoArgHandle;

typedef boost::signals2::signal<void(MObject*, AnyType)>Event1ArgHandle;

typedef boost::signals2::signal<void(MObject*, AnyType, AnyType)>Event2ArgHandle;

typedef boost::signals2::signal<void(MObject*, AnyType, AnyType, AnyType)>Event3ArgHandle;

typedef boost::signals2::signal<void(MObject*, AnyType, AnyType, AnyType, AnyType)>Event4ArgHandle;



//—————————————————————–

// 能够被执行回调操作的函数类型

//—————————————————————–

typedef boost::function<void(MObject*)>EventNoArgDelegation;

typedef boost::function<void(MObject*, AnyType)>Event1ArgDelegation;

typedef boost::function<void(MObject*, AnyType, AnyType)>Event2ArgDelegation;

typedef boost::function<void(MObject*, AnyType, AnyType, AnyType)>Event3ArgDelegation;

typedef boost::function<void(MObject*, AnyType, AnyType, AnyType, AnyType)>Event4ArgDelegation;


typedef boost::signals2::connection  

ConnectStatus;

// 管理连接状态

typedef boost::signals2::shared_connection_block SharedConnectedBlock;

// 阻塞连接


class MEventHandle

{

public:

MEventHandle();

virtual ~MEventHandle();


ConnectStatus operator+=(const EventNoArgDelegation&

fun);

ConnectStatus operator+=(const Event1ArgDelegation&

fun);

ConnectStatus operator+=(const Event2ArgDelegation&

fun);

ConnectStatus operator+=(const Event3ArgDelegation&

fun);

ConnectStatus operator+=(const Event4ArgDelegation&

fun);



void EmitEvent(MObject* sender);


void EmitEvent(MObject* sender, AnyType args);


void EmitEvent(MObject* sender, AnyType arg1, AnyType arg2);


void EmitEvent(MObject* sender, AnyType arg1, AnyType arg2, AnyType arg3);


void EmitEvent(MObject* sender, AnyType arg1, AnyType arg2, AnyType arg3, AnyType arg4);


private:

std::shared_ptr<EventNoArgHandle> 

mNoArgHandle;

std::shared_ptr<Event1ArgHandle> 

mOneHandle;

std::shared_ptr<Event2ArgHandle> 

mTwoHandle;

std::shared_ptr<Event3ArgHandle> 

mThreeHandle;

std::shared_ptr<Event4ArgHandle> 

mFourHandle;


std::vector<boost::shared_ptr<EventNoArgDelegation>> mNoArgsFuns;

std::vector<boost::shared_ptr<Event1ArgDelegation>> mOneArgsFuns;

std::vector<boost::shared_ptr<Event2ArgDelegation>> mTwoArgsFuns;

std::vector<boost::shared_ptr<Event3ArgDelegation>> mThreeArgsFuns;

std::vector<boost::shared_ptr<Event4ArgDelegation>> mFourArgsFuns;

};



//====================================================


如果大家还记得我们以前说的boost的信号槽的话,那么实现也是相当简单,简单到完全没啥可说的:


//====================================================#include "

MEventHandle.h"

#include <
future>

#include <HPath_File.h>

MEventHandle::MEventHandle()

{

mNoArgHandle = std::shared_ptr<EventNoArgHandle>(new EventNoArgHandle);

mOneHandle = std::shared_ptr<Event1ArgHandle>(new Event1ArgHandle);

mTwoHandle = std::shared_ptr<Event2ArgHandle>(new Event2ArgHandle);

mThreeHandle = std::shared_ptr<Event3ArgHandle>(new Event3ArgHandle);

mFourHandle = std::shared_ptr<Event4ArgHandle>(new Event4ArgHandle);

}



MEventHandle::~MEventHandle()

{

}


ConnectStatus MEventHandle::operator+=(const EventNoArgDelegation&

fun){

boost::shared_ptr<EventNoArgDelegation>__F(new EventNoArgDelegation(fun));

mNoArgsFuns.push_back(__F);


return mNoArgHandle->connect(EventNoArgHandle::slot_type(*__F).track(__F));

}


ConnectStatus MEventHandle::operator+=(const Event1ArgDelegation&

fun){

boost::shared_ptr<Event1ArgDelegation>__F(new Event1ArgDelegation(fun));

mOneArgsFuns.push_back(__F);


return mOneHandle->connect(Event1ArgHandle::slot_type(*__F).track(__F));

}


ConnectStatus MEventHandle::operator+=(const Event2ArgDelegation&

fun){

boost::shared_ptr<Event2ArgDelegation>__F(new Event2ArgDelegation(fun));

mTwoArgsFuns.push_back(__F);


return mTwoHandle->connect(Event2ArgHandle::slot_type(*__F).track(__F));

}


ConnectStatus MEventHandle::operator+=(const Event3ArgDelegation&

fun){

boost::shared_ptr<Event3ArgDelegation>__F(new Event3ArgDelegation(fun));

mThreeArgsFuns.push_back(__F);


return mThreeHandle->connect(Event3ArgHandle::slot_type(*__F).track(__F));

}


ConnectStatus MEventHandle::operator+=(const Event4ArgDelegation&

fun){

boost::shared_ptr<Event4ArgDelegation>__F(new Event4ArgDelegation(fun));

mFourArgsFuns.push_back(__F);


return mFourHandle->connect(Event4ArgHandle::slot_type(*__F).track(__F));

}



void MEventHandle::EmitEvent(MObject* sender){

std::async(std::launch::async, [=](){(*mNoArgHandle)(sender);

});

}


void MEventHandle::EmitEvent(MObject* sender, AnyType args){

std::async(std::launch::async, [=](){(*mOneHandle)(sender,args);

});

}


void MEventHandle::EmitEvent(MObject* sender, AnyType arg1, AnyType arg2){

std::async(std::launch::async, [=](){(*mTwoHandle)(sender, arg1, arg2);

});

}


void MEventHandle::EmitEvent(MObject* sender, AnyType arg1, AnyType arg2, AnyType arg3){

std::async(std::launch::async, [=](){(*mThreeHandle)(sender, arg1, arg2, arg3);

});

}


void MEventHandle::EmitEvent(MObject* sender, AnyType arg1, AnyType arg2, AnyType arg3, AnyType arg4){

std::async(std::launch::async, [=](){(*mFourHandle)(sender, arg1, arg2, arg3, arg4);

});

}


//=============================================


operator+= 将信号和槽函数连接在一起,EmitEvent是执行回调函数,从我们的实现中所有的回调函数都是异步操作,也就是立即返回的,这样一来不会因为回调函数过大而导致主程序的卡顿了。


这一讲就到这里吧,因为下面我们就开始讲怎么构建一个窗口出来,这个内容会比较多,所以可能还会被分成几讲来说。


//============================================

回复D查看目录,回复数字查看相应章节


原文始发于微信公众号(

C/C++的编程教室

):第122讲 DirectX11Frame(2)

|

发表评论