前言
之前所有示例程序都是属于展示型的,只是作为展示板输出使用,不涉及键盘和鼠标的输入交互,下面我们开始接触具有交互功能的程序。
没有交互功能的程序可以满足一定需求,不过大部分的程序是不能脱离交互功能的。程序依据使用者的操作进行相应反应并进行相关输出从而达到互动,将让程序的魅力提高一个层次。一个典型的应用就是游戏,所以学习完本篇内容后将可以进行一些游戏程序的编写。当前SimpleCG库主要支持的输入操作是鼠标和键盘,下面看看具体如何操作吧。
一、消息处理基础
想要在SimpleCG中处理Windows的交互操作,就是需要定义一个消息处理函数,消息处理函数名字可以随便定义,但形式是固定的。例如鼠标消息固定形式如下所示:
LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
}
名字OnLButtonDown是可以自己定义的,一般也是按消息功能命名。定义完消息函数后,依据想要接收的消息进行注册,所谓注册也就是调用一个设置函数。例如想要接收左键点击消息,按如下方式设置:
SetMouseProcess( enumINMSG_LBUTTONDOWN, OnLButtonDown);
这里要注意的是,设置函数一定要在初始化阶段设置,一般是程序开始处设置。
二、鼠标操作
支持的鼠标消息如下所示:
enumINMSG_MOUSEMOVE //鼠标移动
, enumINMSG_LBUTTONDOWN //左键按下
, enumINMSG_LBUTTONUP //左键抬起
, enumINMSG_LBUTTONDBLCLK //左键双击
, enumINMSG_RBUTTONDOWN //右键按下
, enumINMSG_RBUTTONUP //右键抬起
, enumINMSG_RBUTTONDBLCLK //右键双击
, enumINMSG_MBUTTONDOWN //中键按下
, enumINMSG_MBUTTONUP //中键抬起
, enumINMSG_MBUTTONDBLCLK //中键双击
, enumINMSG_MOUSEWHEEL //滚轮消息
当需要处理相应消息时,只要按上面说到的两个步骤定义相应函数即可。下面用一个绘图功能的程序来演示一下鼠标左键消息的处理。
#include "../import/include/CGBoard.h"
#include "math.h"
#ifdef _DEBUG
#pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
#else
#pragma comment(lib,"../import/lib/SimpleCG_MD.lib")
#endif
int g_nWidth = 500; //画面宽度
int g_nHeight= 400; //画面高度
int g_bIsDrawing = 0;
POINT g_ptLast;
void DrawProcess()
{
}
LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
g_ptLast.x = nX;
g_ptLast.y = nY;
g_bIsDrawing = 1;
return TRUE;
}
LRESULT OnLButtonUp( HWND hWnd, WPARAM wParam, int nX, int nY )
{
if(g_bIsDrawing)
{
line(g_ptLast.x,g_ptLast.y,nX,nY);
g_ptLast.x = nX;
g_ptLast.y = nY;
g_bIsDrawing = 0;
}
return TRUE;
}
LRESULT OnMouseMove( HWND hWnd, WPARAM wParam, int nX, int nY )
{
if(g_bIsDrawing)
{
line(g_ptLast.x,g_ptLast.y,nX,nY);
g_ptLast.x = nX;
g_ptLast.y = nY;
}
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
//设置消息处理函数
SetMouseProcess( enumINMSG_LBUTTONDOWN, OnLButtonDown);
SetMouseProcess( enumINMSG_LBUTTONUP, OnLButtonUp);
SetMouseProcess( enumINMSG_MOUSEMOVE, OnMouseMove);
//初始化
if( !ShowingBoard(g_nWidth,g_nHeight, DrawProcess))
return 1;
//关闭图库
CloseBoard();
return 0;
}
该程序可以用鼠标在窗口点击要绘制的地方,然后移动鼠标绘制出鼠标轨迹,直至左键抬起。
另外函数
LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
}
中各参数意义如下:
hWnd是窗口句柄,暂时不需要了解
wParam附带有消息产生时的按键信息,可通过如下方法判断。
MK_CONTROL 按下了 CTRL 键。
MK_LBUTTON 按下了鼠标左键。
MK_MBUTTON 按下了鼠标中键。
MK_RBUTTON 按下了鼠标右键。
MK_SHIFT 按下了 SHIFT 键。
MK_XBUTTON1 按下了第一个 X 按钮。
MK_XBUTTON2 按下了第二个 X 按钮。
例如通过代码
if(wParam&MKCONTROL)就可以判断CTRL键是否按下。
nX和nY是鼠标在窗口中的坐标
三、键盘消息
键盘支持的消息如下:
enumINMSG_KEYDOWN //按键按下
, enumINMSG_KEYUP //按键放开
按键消息响应函数如下
//按键消息响应函数
LRESULT OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
}
其中wParam代表当前虚拟键,各个虚拟键值可在此网站查找。
lParam是32位数含义如下:
0-15 当前消息的重复计数。 该值是由于用户按住键而自动重复击键的次数。
16-23 扫描代码。 该值取决于 OEM。
24 指示键是扩展键,例如在增强型 101 键或 102 键键盘上显示的右侧 Alt 键和 Ctrl 键。 如果是扩展键,则值为 1;否则为 0。
25-28 保留;请勿使用。
29 上下文代码。 对于 WM_KEYDOWN 消息,该值始终为 0。
30 上一个键状态。 如果键在发送消息之前关闭,则值为 1;如果键已打开,则值为 0。
31 转换状态。 对于 WM_KEYDOWN 消息,该值始终为 0。
下面用一个可以用方向键控制移动的小球来演示按键的交互
#include "../import/include/CGBoard.h"
#include "math.h"
#ifdef _DEBUG
#pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
#else
#pragma comment(lib,"../import/lib/SimpleCG_MD.lib")
#endif
int g_nWidth = 500; //画面宽度
int g_nHeight= 400; //画面高度
int g_nXCircle = 100;
int g_nYCircle = 100;
void DrawProcess()
{
setfillcolor(RGB(0xAA,0xAA,0xFF));
fillcircle(g_nXCircle, g_nYCircle, 10 );
}
//按键消息响应函数
LRESULT OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
int nStepX = 0;
int nStepY = 0;
switch( wParam )
{
case VK_DOWN:
nStepY = 1;
break;
case VK_UP:
nStepY = -1;
break;
case VK_LEFT:
nStepX = -1;
break;
case VK_RIGHT:
nStepX = 1;
break;
}
_clearcircle(g_nXCircle, g_nYCircle, 12 );
g_nXCircle += nStepX;
g_nYCircle += nStepY;
fillcircle(g_nXCircle, g_nYCircle, 10 );
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
//设置消息处理函数
SetKeyboardProcess( enumINMSG_KEYDOWN, OnKeyDown );
//初始化
if( !ShowingBoard(g_nWidth,g_nHeight, DrawProcess))
return 1;
//关闭图库
CloseBoard();
return 0;
}
有兴趣的同学可以试着运行看看效果。
四、接管所有消息处理
当对Windows编程有了更深入了解后,需要处理除了以上消息之外的消息时,可以设置一个所有消息的处理函数。方法如下:
首先定义消息处理函数
LRESULT OnMessage( HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam )
{
//此处输入消息处理过程
return 0;
}
然后使用SetInputProcess进行设置
SetInputProcess( OnMessage );
此处需要注意的是使用了SetInputProcess( OnMessage );函数后,就要自己处理所有交互消息,所以SetMouseProcess和SetKeyboardProcess都将失效。
下面我们运用自定义消息处理函数对窗口关闭操作进行拦截的演示。代码如下:
// DemoMessage.cpp : 定义控制台应用程序的入口点。
//
#include "../import/include/CGBoard.h"
#include "math.h"
#ifdef _DEBUG
#pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
#else
#pragma comment(lib,"../import/lib/SimpleCG_MD.lib")
#endif
int g_nWidth = 500; //画面宽度
int g_nHeight= 400; //画面高度
int g_bIsDrawing = 0;
POINT g_ptLast;
int g_nLineWidth = 1;
int g_nXCircle = 100;
int g_nYCircle = 100;
void DrawProcess()
{
setfillcolor(RGB(0xAA,0xAA,0xFF));
fillcircle(g_nXCircle, g_nYCircle, 10 );
}
LRESULT OnMessage( HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam )
{
if( nMessage == WM_CLOSE )
{
if(MessageBox(NULL,_T("是否退出"),_T("提示"),MB_YESNO) == IDYES )
return 0;
return 1;
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
//设置消息处理函数
SetInputProcess( OnMessage );
//初始化
if( !ShowingBoard(g_nWidth,g_nHeight, DrawProcess))
return 1;
//关闭图库
CloseBoard();
return 0;
}
五、结语
通过掌握以上介绍的内容,就可以编写出大部分可交互程序。不过要完全操控窗口,还需要熟练掌握更多的消息及参数。对于游戏编写,后面会给出一个简单框架。