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