第九十六讲 MFrame3D框架(2)

上一讲我们把鼠标键盘和数据给抽象出来,但是并没有给出实现,其实实现相当简单的了,不过我还是给出来吧,因为可能有些同学会想要自己进行调试(相关代码以后我会将他放在网上,本来打算自己弄个网站出来和大家交流的,但是后来发现我忘了路由器的密码,也懒得折腾,算了,等把这个框架给大家说完,我把代码直接扔在网盘上,大家下载就好了)。

下面我们先来看看键盘的实现:

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

//MkeyEvent.cpp

#include "

MKeyEvent.h"

namespace Mengjin{

MKeyEvent::MKeyEvent(void)

{

for(int i=0;

i<256;

++i){

b_IsKey[i] = false;

}

b_IsActive = false;

}

MKeyEvent::~MKeyEvent(void)

{

}


void MKeyEvent::processEvent(unsigned char index,bool status){

m_index = index;

b_IsKey[index] = status;

run();

}

}

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

这个实现相当简单,构造函数初始化每个键的状态,如前所说,false表示未按下,processEvent是一个保护的函数,他由框架调用,index表示键盘的ascii码,当然就是一个uchar了,有些东西说起来太多,等到我们说到底层框架后就明白他是多简单了,这里面调用一个run,这个函数在这里是个虚函数,他由我们重写,由框架调用,是不是很简单………

同样,鼠标也很简单:

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

//MMouseEvent.cpp

#include "

MMouseEvent.h"

namespace Mengjin{

MMouseEvent::MMouseEvent(void)

{

m_button = NoButton;

m_status = Hover;

}


MMouseEvent::~MMouseEvent(void)

{

}



void MMouseEvent::processEvent(MouseButton button,MouseAction status,float x,float y){

m_button = button;

m_status = status;

m_point.x = x;

m_point.y = y;

run();

}

}

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

鼠标键盘都一样,为了好用,所以接口一样,如果你看明白了上面键盘的实现,那么这个就不用我解释了。

关于数据,也没什么好说的,我直接贴代码:

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

//MDataBase.cpp

#include "

MDataBase.h"


namespace Mengjin{


MDataBase::~MDataBase(void)

{

}

}

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

我承认,我真不是来搞笑的,但是他确实没什么可说,之所以他存在,是为了一个框架的完整,同时为了更好的管理(这就是典型的观察者模式)。

ok,进入今天的主题,我们今天先来说说窗口,这相当于一个容器,因为我们的3D窗口都是在里面显示的,所以这是一个最底层的class,他不但可以作为3D窗口的容器,还可以作为我们以后编写windows程序的一个框架来用,当然前提是如果大家把他更加完善的话(因为我这里只是给大家模拟出一个框架出来,如果大家想要知道C++在实际中是怎么用的话,这是一个机会,我们将以前的理论都用在实际构架中)。


这就是我们的MWindowBase类:

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

//MWindowBase.h

#pragma once

#include "

MFrameH.h"

#include "

MMouseEvent.h"

#include "

MKeyEvent.h"


namespace Mengjin{

class MWindowBase{

public:

MWindowBase(HINSTANCE hInstance,HINSTANCE hPreInstance,PSTR szCmdLine,

int iCmdShow,const std::wstring&

title,const std::wstring&

wndname);

MWindowBase();

virtual ~MWindowBase();

private:

MWindowBase(const WindowBase&

);

MWindowBase&

operator=(const WindowBase&

);

public:


void setTitle(const std::wstring&

title);


void setWndclassName(const std::wstring&

classname);


void sethInstance(HINSTANCE hInstance);


void setPrehInstance(HINSTANCE PrehInstance);


void setShowCmd(int showcmd);


void setCmdLine(char* cmdline);


void setWindowWidth(int w);


void setWindowHeight(int h);


void setExStyle(DWORD dwExStyle);


void setStyle(DWORD dwStyle);


void setIsFullScreen(bool fullscreen);


void closeWindow(bool isclose);


void AddMouseEvent(MMouseEvent* mouse);


void AddKeyEvent(MKeyEvent* key);

bool isFullScreen(){

return b_IsFullscreen;

}

bool isActive(){
return b_IsActive;

}

static LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

//窗口回调函数


void RegisterFunInitGL(RECALL_INIT initGLfun);

//注册OpenGL初始化函数,没多大用,暂时保留


void RegisterDrawScreen(RECALL_DRAW drawFun);

//注册显示函数,很重要,没他,就显示不出3D画面


void RegisterReShape(RECALL_RESHAPE reshapeFun);

//窗口变化时会被调用


void RegisterWndProc(RECALL_WNDPROC WndProc);

//注册事件回调函数,该函数将会处理相应窗口消息,他的强大之处只是将静态处理变成成员处理,这样扩展性就得到质的提升


void RegisterOnIdleFun(RECALL_IDLE idlefun);


void SetHdc(HDC hdc);

protected:

virtual bool
init();

virtual bool
GenWindow();

//创建窗口

virtual bool
RegisterWndClass();

//注册窗口类

virtual void
showwindow();

// 显示窗口

virtual int
msgloop();

//消息循环

virtual LRESULT MemWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

//窗口消息处理函数

protected:

HWND

m_hwnd;

//windows句柄

HINSTANCE
m_hInstance;

// 实例句柄

HINSTANCE
m_hPreInstance;


PSTR

m_CmdLine;

// 命令符,保留用

int

m_iCmdShow;

//显示窗口

WNDCLASS
m_wndclass;

//窗口类

MSG

m_msg;

//窗口消息

bool

b_IsFullscreen;

//是否全屏


std::wstring m_Title;

// 窗口标题

std::wstring m_wndclassname;

//窗口类名


int

m_height;

int

m_width;

DWORD

m_dwExStyle;

DWORD

m_dwStyle;


MMouseEvent*

m_mouse;

//鼠标

MKeyEvent*

m_key;

// 键盘

RECALL_WNDPROC

m_add_wndproc;

//辅助消息处理 ,如果不想重写消息处理函数时,可以选择附加一个消息处理函数

unsigned long

m_TimeId;

//定时器ID

bool

b_IsActive;

//窗口是否处于活动状态

bool

b_done;

RECALL_INIT
m_InitGL;

RECALL_DRAW
m_DrawScreen;

RECALL_RESHAPE m_Reshape;

HDC

m_hdc;

RECALL_IDLE
m_idle_fun;

// 空闲处理函数

static RECALL_WNDPROC m_WndProc;

//消息回调函数

};

}

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

这个底层的接口虽多,但是基本很多东西我们都不用调用的,因为我们基本会用不到这些接口,但是用不上不等于就没有用,所以就加上这些接口,这些接口顾名思义就好,没什么不好理解的,所以我就不说什么了,接下来我们来看看实现代码:

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

//MWindowBase.cpp

#include "

MWindowBase.h"

namespace Mengjin{

RECALL_WNDPROC MWindowBase::m_WndProc = nullptr;

MWindowBase::MWindowBase(HINSTANCE hInstance,HINSTANCE hPreInstance,PSTR szCmdLine,

int iCmdShow,const std::wstring&

title,const std::wstring&

wndname)

{

m_hInstance = hInstance;

m_hPreInstance = hPreInstance;

m_CmdLine = szCmdLine;

m_iCmdShow = iCmdShow;

m_Title = title;

m_wndclassname = wndname;

if(!init())

throw L"

Init Windows fail!!!"

;

}


MWindowBase::MWindowBase()

{

m_hInstance = nullptr;

m_hPreInstance = nullptr;

m_CmdLine = "

"

;

m_iCmdShow = -1;

m_Title = L"

"

;

m_wndclassname = L"

"

;

}


MWindowBase::~MWindowBase()

{

}


bool MWindowBase::init(){


m_dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;

m_dwStyle = WS_OVERLAPPEDWINDOW;

m_height = 450;

m_width = 750;

b_IsActive = false;

b_done = false;

m_DrawScreen = nullptr;

m_InitGL = nullptr;

m_Reshape = nullptr;

m_hdc = nullptr;

m_key = nullptr;

m_mouse = nullptr;


m_WndProc = std::bind(&

MWindowBase::MemWndProc,this,std::placeholders::_1,std::placeholders::_2,

std::placeholders::_3,std::placeholders::_4);


m_wndclass.style = CS_HREDRAW | CS_VREDRAW;

m_wndclass.lpfnWndProc =WndProc;

m_wndclass.cbClsExtra = 0;

m_wndclass.cbWndExtra = 0;

m_wndclass.hInstance = m_hInstance;

m_wndclass.hCursor = LoadCursor(nullptr,IDC_ARROW);

m_wndclass.hIcon = LoadIcon(nullptr,IDI_APPLICATION);

m_wndclass.lpszClassName = m_wndclassname.c_str();

m_wndclass.lpszMenuName = nullptr;

m_wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

if(!RegisterWndClass()){

throw L"

Register Windows class fail!!!"

;


return false;

}


return true;

}



void MWindowBase::showwindow(){

if(m_hwnd){

ShowWindow(m_hwnd,m_iCmdShow);

UpdateWindow(m_hwnd);

}

}



void MWindowBase::setTitle(const std::wstring&

title){

m_Title = title;

}



void MWindowBase::setWndclassName(const std::wstring&

classname){

m_wndclassname = classname;

}



void MWindowBase::setCmdLine(char* cmdline){

m_CmdLine = cmdline;

}



void MWindowBase::sethInstance(HINSTANCE hinstance){

m_hInstance = hinstance;

}



void MWindowBase::setPrehInstance(HINSTANCE hPreinstance){

m_hPreInstance = hPreinstance;

}



void MWindowBase::setShowCmd(int iShowCmd){

m_iCmdShow = iShowCmd;

showwindow();

}



void MWindowBase::setWindowHeight(int h){

m_height = h;

}



void MWindowBase::setWindowWidth(int w){

m_width = w;

}



void MWindowBase::setExStyle(DWORD dwExStyle){

m_dwExStyle = dwExStyle;

}



void MWindowBase::setStyle(DWORD dwStyle){

m_dwStyle = dwStyle;

}



void MWindowBase::setIsFullScreen(bool fullscreen){

b_IsFullscreen = fullscreen;

}



void MWindowBase::RegisterDrawScreen(RECALL_DRAW drawFun){

m_DrawScreen = drawFun;

}



void MWindowBase::RegisterFunInitGL(RECALL_INIT initGLfun){

m_InitGL = initGLfun;

}



void MWindowBase::RegisterReShape(RECALL_RESHAPE reshapeFun){

m_Reshape = reshapeFun;

}



void MWindowBase::RegisterWndProc(RECALL_WNDPROC WndProc){

m_WndProc = WndProc;

}



void MWindowBase::RegisterOnIdleFun(RECALL_IDLE idlefun){

m_idle_fun = idlefun;

}



void MWindowBase::SetHdc(HDC hdc){

m_hdc = hdc;

}



void MWindowBase::setKeysStatus(bool* keystatus){

b_IsKeys = keystatus;

}



void MWindowBase::setWindowActive(bool Active){

b_IsActive = Active;

}



void MWindowBase::closeWindow(bool isclose){

b_done = isclose;

}


//消息循环

int MWindowBase::msgloop(){

while(!b_done){

if(PeekMessage(&

m_msg,nullptr,0,0,PM_REMOVE)){

TranslateMessage(&

m_msg);

DispatchMessage(&

m_msg);

}

else{

/* if(m_DrawScreen!=nullptr &

&

m_hdc!= nullptr){

if (m_idle_fun)

m_idle_fun();

m_DrawScreen();

SwapBuffers(m_hdc);

}

*/ }

}


return m_msg.wParam;

}


//注册窗口类

bool MWindowBase::RegisterWndClass(){

if(!RegisterClass(&

m_wndclass)){


return false;

}


return true;

}


//生成窗口

bool MWindowBase::GenWindow(){

m_hwnd = CreateWindowEx(

m_dwExStyle,m_wndclassname.c_str(),

m_Title.c_str(),m_dwStyle,

0,0,m_width,m_height,

nullptr,nullptr,m_hInstance,nullptr

);

if(m_hwnd == nullptr){

throw L"

Creat windows fail!!!"

;


return false;

}


return true;

}


//添加鼠标响应事件


void MWindowBase::AddMouseEvent(MMouseEvent* mouse){

m_mouse = mouse;

}

//添加键盘响应事件


void MWindowBase::AddKeyEvent(MKeyEvent* key){

m_key = key;

}


//窗口回调函数,该函数由框架调用,这个函数可以重写,也可以不重写

//因为这里已经基本实现了不少东西,如果不是有什么特殊要求的话,这里已经可以完美实现

LRESULT MWindowBase::MemWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){

switch (msg)

{

case WM_CREATE:

SetTimer(hwnd, m_TimeId, 100, nullptr);

break;


case WM_TIMER:

if (m_idle_fun)

m_idle_fun();

InvalidateRect(m_hwnd, nullptr, false);

break;

case WM_ACTIVATE:

if (!HIWORD(wParam)){

b_IsActive = true;

}

else{

b_IsActive = false;

}

break;


case WM_SYSCOMMAND:

switch (wParam)

{

case SC_SCREENSAVE:

case SC_MONITORPOWER:


return 0;

}

break;


case WM_KEYDOWN:

if(m_key)

m_key->processEvent(wParam,true);

break;


case WM_KEYUP:

if(m_key)

m_key->processEvent(wParam,false);

break;


case WM_LBUTTONDOWN:

if(m_mouse)

m_mouse->processEvent(LButton,Down,LOWORD(lParam),HIWORD(lParam));

break;

case WM_LBUTTONUP:

if (m_mouse)

m_mouse->processEvent(LButton,Up,LOWORD(lParam),HIWORD(lParam));

break;

case WM_LBUTTONDBLCLK:

if(m_mouse)

m_mouse->processEvent(LButton,DoubleClick,LOWORD(lParam),HIWORD(lParam));

break;

case WM_RBUTTONDOWN:

if(m_mouse)

m_mouse->processEvent(RButton,Down,LOWORD(lParam),HIWORD(lParam));

break;


case WM_RBUTTONUP:

if(m_mouse)

m_mouse->processEvent(RButton,Up,LOWORD(lParam),HIWORD(lParam));

break;

case WM_RBUTTONDBLCLK:

if(m_mouse)

m_mouse->processEvent(RButton,DoubleClick,LOWORD(lParam),HIWORD(lParam));

break;

case WM_MBUTTONDOWN:

if (m_mouse)

m_mouse->processEvent(MButton,Down,LOWORD(lParam),HIWORD(lParam));

break;

case WM_MBUTTONUP:

if(m_mouse)

m_mouse->processEvent(MButton,Up,LOWORD(lParam),HIWORD(lParam));

break;


case WM_MOUSEMOVE:

if(m_mouse){

if(wParam&

MK_RBUTTON)

m_mouse->processEvent(RButton,Move,LOWORD(lParam),HIWORD(lParam));

else if(wParam&

MK_LBUTTON)

m_mouse->processEvent(LButton,Move,LOWORD(lParam),HIWORD(lParam));

}

break;


case WM_SIZE:

if (m_Reshape != nullptr)

m_Reshape(LOWORD(lParam), HIWORD(lParam));

break;


case WM_PAINT:

if(m_DrawScreen)

m_DrawScreen();

SwapBuffers(m_hdc);

break;


case WM_CLOSE:

b_done = true;

;

PostQuitMessage(0);

break;

}

if (m_add_wndproc)

m_add_wndproc(hwnd, msg, wParam, lParam);


return DefWindowProc(hwnd, msg, wParam, lParam);

}


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

//窗口回调函数

LRESULT CALLBACK MWindowBase::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){

if (m_WndProc){


return m_WndProc(hwnd, msg, wParam, lParam);

}

else{


return DefWindowProc(hwnd, msg, wParam, lParam);

}

}

}

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

我们所有的窗口就是从这里产生的,所有的消息都是从这里路由出去的,msgloop实现消息循环,WndProc实现消息处理,当然我们没在这里处理,我们都将消息派发给鼠标键盘来处理,最后的结果都交由我们在鼠标键盘中的run中处理,等我们把这框架介绍完后会给出使用实例。


============================

回复D&

d直接查看目录

原文始发于微信公众号(

C/C++的编程教室

):第九十六讲 MFrame3D框架(2)

|

发表评论