版本:VS2015 语言:C++
本来想昨天写个消息窗口的内容,讲一些好玩的东西,不过没有时间了,就放到一起了。
今天正好把书的第二章看完了,感觉良好,Windows的编程确实难度要高,一下子会有一大堆的参数概念,但随着书本深入了解每个参数的含义,Windows编程大致的一些思路基本就出来了。
题外话,这本书绝对神书,游戏编程者都应该去看看,仅仅两个章节我就对整个游戏的循环有个大致的了解了,还有各类事件是如何进行处理的,从两个章节来看我第一次用Java编的贪吃蛇简直是渣渣,什么都没有,勉勉强强能够运行罢了。
首先来介绍一下一个最简单的窗口,打开VS2015,新建工程,把多余的代码删除,只留下一个返回的操作,然后在wWinMain函数中写下这样一行代码:
int i = MessageBox(NULL, TEXT("HELLO"), TEXT("TITLE"), MB_OKCANCEL | MB_ICONERROR);
运行效果:
红叉、HELLO、确定取消,该有的都有了。
1.第一参数hwnd:是父窗口的句柄,因为没有父窗口代表桌面,所以设置为NULL
2.第二参数lptext:正如所见是文本的内容
3.第三参数lpcaption:标题文本
4.第四参数utype:消息窗口的类型,就是有哪些按钮,我这边就设定了确定和取消两个按钮,并且如果点击确定和取消,外部的变量i还会获取到对应的值,有兴趣可以断个点看看
很简短对吧。关于类型能取一些什么值,我就不详细罗列了。
在正式玩基本窗口之前还有个好玩的东西就是MessageBeep,上面的是创建一个消息窗口,而这个是提示一个声音:
MessageBeep(MB_OK); //win10中警告声音都一样了。。。
嗯,试一下就有声音了。注释的意思是不管你设置成什么参数,都是那个声音。怎么形容呢,反正起到了提示玩家的作用。
OK,用Ctrl+K,松开K再按一下C注释一下代码,我们开始正式学习Windows基本窗口的程序了。让我学一下红孩儿,直接发代码,在代码上注释:
// Win32Project1.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "Win32Project1.h"
static int windowNum = 0; //当前窗口的计数
// 消息处理函数,相当于cocos中的callback
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM IParam)
{
switch (msg)
{
case WM_CREATE: //创建消息
{
//初始化需要的资源
}
break;
case WM_DESTROY: //WM_DESTROY是一个窗口销毁的消息,而WM_QUIT是退出应用程序的消息,也就是说一个应用程序可以包含0、1个或多个窗口
{
//窗口数量为0的时候发送结束应用程序的消息
if(0 == --windowNum)
PostQuitMessage(0);
}
break;
default:
DefWindowProc(hwnd, msg, wParam, IParam); //自动处理其他的消息
}
return (1);
}
// 主函数,程序入口
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// 来个消息框
//int i = MessageBox(NULL, TEXT("HELLO"), TEXT("TITLE"), MB_OKCANCEL | MB_ICONERROR);
// 来个声音
//MessageBeep(MB_OK); //win10中警告声音都一样了。。。
//MessageBeep(0xFFFFFFFF);
//MessageBeep(MB_ICONASTERISK);
//MessageBeep(MB_ICONHAND);
//MessageBeep(MB_ICONQUESTION);
// 开始创建一个基本的窗口
// 创建窗口类
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = NULL;// CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; //窗口的样式:改变宽度刷新、改变高度刷新、分配设备描述表、双击信息
wndclass.lpfnWndProc = WindowProc; //回调函数
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //光标
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //窗口背景
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TEXT("MyFirstWindow"); //窗口的名字
wndclass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); //小应用图标
if (!RegisterClassEx(&wndclass))
return 0;
// 创建窗口,上面的窗口类是一个模版,可以根据上面的模版创建多个窗口,但请注意第二个参数
HWND hwnd = CreateWindowEx(NULL,//WS_EX_TOPMOST, //窗口特性,注释里设置为永远在最上方显示
TEXT("MyFirstWindow"), //窗口名称,一定要和窗口类的lpszClassName对应
TEXT("TITLE"), //标题
WS_OVERLAPPEDWINDOW | WS_VISIBLE, //窗口的样式
0, 0, //左上角坐标
800, 600, //宽高
NULL, //父窗口句柄,如果是桌面则为NULL
NULL, //菜单窗口句柄
hInstance, //应用程序实例
NULL //高级特性
);
if (!hwnd) //创建失败返回
return 0;
++windowNum; //窗口数量加1
ShowWindow(hwnd, nCmdShow); //显示窗口
UpdateWindow(hwnd); //刷新窗口
MSG msg; //消息缓存
// 进入主循环
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //有消息事件,注意最后一个参数,如果设置为PM_NOREMOVE的话不会销毁消息队列中的消息
{
/* 这边详细说一下GetMessage和PeekMessage的区别:
* 1.首先说明,使用GetMessage是实现不了像游戏循环一样的效果的
* 2.GetMessage像是事件触发一下,有了消息马上运行;而PeekMessage会反复的检查消息队列
* 3.GetMessage,返回true代表消息不为WM_QUIT(退出应用程序的消息),返回false代表消息是WM_QUIT
* 4.PeekMessage,返回true代表有消息,false没有消息,像游戏这样每帧需要刷新的使用这个是最好的
*
*/
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg); //转译消息
DispatchMessage(&msg); //将消息发送给WindowProc函数处理
}
else //没有消息
{
//GameMain() //进入游戏的主循环
}
}
return msg.wParam;
}
最终结果:
嗯,看到这里想必大家对游戏需要怎样一个窗口循环都有所了解了吧。最好是把上面代码给打一遍,好记性不如烂键盘嘛。
在这一章的结束,书的作者说你已经成为Windows专家了,我当时内心只浮现了四个字——神TMD。不同同样想把这句话送给学完上述程序的玩家们,恭喜你已经完成了Windows的教程了!
至于作者的问题,创建两个窗口,只有在关闭两个窗口后才会退出应用程序。很简单,在我的程序中有个静态变量来表示当前窗口的数量,在关闭窗口后判断一下是否为0,再决定是否要关闭应用程序。
有想了解相关编程的玩家们,希望能跟我一起学习,能有个关注是最好的了,哈哈。我会隔几天发一下自己的学习总结,直到这本书学完。
总结(创建Windows窗口的步骤):
1.WNDCLASSEX创建模版的窗口类
2.CreateWindowEx创建窗口,需要注册别忘了
3.编写主循环
4.写回调函数
书上有一个写的很好,消息是这样往下传的:
PeekMessage -> TranslateMessage -> DispatchMessage -> 你的回调函数
更多推荐
Windows编程 从消息窗口到基本窗口 游戏循环窗口框架的简单实现
发布评论