|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
零基础用VC6.0做人物走迷宫(上集)
程序运行后,窗口里,是一个简单的迷宫。人物可以随着键盘移动。下面说说如何用VC6.0制作以下迷宫
上集中,我们首先制作一个带有人物的窗口:如下
1、新建工程win32application————空白工程(工程名取为game32)
2、在新工程中,新建C/C++ Heand file (取名为game32) 添加到game32工程中
3、在head file 文件夹中,打开我们新建的game32.h 空白文件(head file文件),加入#include <afxwin.h>
afxwin.h 就是MFC的库类。
4、我们需要去新建资源文件添加到工程中 (虽然本例子没用到资源,但习惯上还是要建个资源文件,资源就是指图片,声音等外部来的资源)
步骤:新建——资源脚本(resourcescript)取名game————添加到工程
5、设置资源文件包含的资源内容
我们新建好资源文件后,会自动弹出资源文件窗口,在窗口中选中文件右击————选则资源包含
在这里,因为我们没有使用到资源文件,所以资源包含弹出的窗口中,我们点确定就行。
6、新建类向导
查看(view)————类向导(class wizard)—————弹出窗口问是否创建,选是————弹出窗口,什么也不用填直接点OK————弹窗再直接点OK
类向导是我们用新建类做准备
7、设置项目
工程(project)————设置(setting)————使用MFC静态链接库————OK
静态链接库可以让程序在其他机子里也正常运行起来(程序包含MFC库),而选则共享DLL ,那么程序在其他机子里可能运行不起来(程序不包含MFC库,其他机子如果没有安装MFC库就可能运行不起来)
8、插入窗口类
插入(insert)————类(new class)——————类的类型MFC Class——自定义取名为gamewnd——————bass class(基类) 选择cframewnd————OK
cframewnd是主窗口的类。
这样,我们就生成了一个类,可以在目录中看到这个类
9、protect改为public
双击gamewnd这个类(或者打开gamewnd.h)——————把gamewnd()构造函数前面默认的protect改为public,因为我们之后要在其他类中调用到这个类。
10、再次创建一个类(普通类)
插入(insert)————类(new class)————类的类型generic class——取名为gameapp————derived from CWinApp————继承类型 共有————确定————弹窗是否————是
11、编译一下。发现有两条错误,修改。
错误一:'stdafx.h': No such file or directory
我们将这个#include"stdafx.h"去掉
错误二:'game.h': No such file or directory
把'game.h'变为game32.h 因为game.h是不存在的,只有game32.h
12、在gameapp.app中定义一个对象
双击gameapp.app 在构造函数前面定义一个这个类的对象。取名为myapp
13、增加gameapp类中一个BOOL函数
双击gameapp.h 在gameapp类public中增加一个BOOL函数。(构造函数前)
BOOL InitInstance() ; //这是入口函数 函数名不可自定义
14、在gameapp.app中定义InitInstance() 函数
双击gameapp.app 在其中定义这个成员函数,用到的格式是类外定义成员的格式
这个函数是窗口的入口,定义具体内容就是初始化窗口,但为什么不在gameapp()这个构造函数中初始化呢?
因为winmain就是去调用InitInstance() 来进行初始化的。
BOOL gameapp::InitInstance()
{
m_pMainWnd = new gamewnd; // gamewnd就是我们从CFrameWnd中派生的自定义类。左边是指针。gameapp这个类是从CWinApp中派生出来的自定义类,CWinApp是从CWinThread中派生出来。总之这个指针就是gameapp继承下来的指针。
}
15、在gameapp.app中添加 #include "gamewnd.h"
因为我们在这个文件中使用了 gamewnd
16、定义gamewnd()构造函数的内容
打开gamewnd.app 找到构造函数,定义
gamewnd::gamewnd()
{
Create(NULL,"创建窗口") ;//创建一个窗口,第一个窗口是窗口类名,如果没有,则表示采用默认窗口类(默认风格),第二个是窗口的标题。这个函数只是建立窗口在内存中,并没有在显示器中显示出来。
}
17、让Create()函数建立的窗口在显示器上显示出来
打开gameapp.app 在BOOL gameapp::InitInstance() 函数中继续定义:
BOOL gameapp::InitInstance()
{
m_pMainWnd = new gamewnd;
m_pMainWnd ->ShowWindow(m_nCmdShow);// 调用gamewnd类中的成员ShowWindow函数,m_nCmdShow是窗口显示的方式,往往第一次传参数时用这个参数。当然这个参数还可以换成其他一些显示的参数。
}
18、增加更新窗口函数
因为我们要做一个人物移动的窗口,所以窗口随着人物移动在不断的改变,因此还需要一个能更新窗口的函数。
BOOL gameapp::InitInstance()
{
m_pMainWnd = new gamewnd;
m_pMainWnd ->ShowWindow(m_nCmdShow);// 调用gamewnd类中的成员ShowWindow函数,m_nCmdShow是窗口显示的方式,往往第一次传参数时用这个参数。当然这个参数还可以换成其他一些显示的参数。
m_pMainWnd ->UpdateWindow();//这个函数不断刷新窗体,如果值为false,则不进行更新
}
19、让BOOL gameapp::InitInstance() 返回一个值
BOOL gameapp::InitInstance()
{
m_pMainWnd = new gamewnd;
m_pMainWnd ->ShowWindow(m_nCmdShow);// 调用gamewnd类中的成员ShowWindow函数,m_nCmdShow是窗口显示的方式,往往第一次传参数时用这个参数。当然这个参数还可以换成其他一些显示的参数。
m_pMainWnd ->UpdateWindow();//这个函数不断刷新窗体,如果值为false,则不进行更新
return TRUE;//BOOL是判断真假,这里如果运行正常就返回TURE
}
运行一下,就弹出了窗口。
20、在gamewnd类定义中,再定义一个新的变量成员
我们可以打开gamewnd.h 然后在public中加入新成员。这里介绍一种新方式:
我们右击gamewnd.h类 选择 add member variable
我们要添加的是一个指向位图类的指针。CBitmap是一个库类。所以在变量类型中填入 CBitmap* 变量名自定义 权限是public
确定后,gamewnd.h中gamewnd类定义public 自动增加了 CBitmap*bitmap;
此时类的目录中,会自动增加一个变量的图标
当然,如果我们手动自己在h文件中增加一个新成员,类目录中也会自动增加一个变量的图标
21、在gamewnd()构造函数中建立位图类的对象,并用指针指向
打开gamewnd.cpp
gamewnd::gamewnd()
{
Create (NULL,"创建窗口") ;
bitmap = new CBitmap; // 建立了一个位图类对象,并用指针指向。但这个对象还是空的,之后我们可以把图片放进去
}
22、用LoadImage()函数给位图类对象加载图片
LoadImage()函数有6个参数
第一个参数这里是 NULL (如果资源是链接式的,就是写NULL,如果是嵌入式的那可能就是句柄,这个例子中是链接式)
第二个参数是访问路径字符串。如果说位图就在工程文件夹中,那么直接写文件名也可以。
第三个参数时加载图片的类型。这里是 IMAGE_BITMAP 当然图片类型不同这里的参数也不同
第四、五个参数:这是放置图片控件的长宽。(注意不是图片大小,是图片放置的控件空间大小,这里我们让他跟图片大小一样,都是 93,100 直接写数字)
第六个参数是:LR_LOADFROMFILE 是指载入的方式,这里就是链接式。还有黑白、缩放载入等
函数返回值:如果加载成功,函数会返回一个句柄,这个句柄是最后一次加载位图成功的句柄。
23、接受位图的句柄
什么是句柄:句柄就是保存数据新内存地址的不变地址(程序重启后当然会变,句柄近似是指向指针的指针)
bitmap->m_hObject 来接受句柄 它可以接受位图、字体、调色板、裁剪区、画笔、画刷等的句柄(m_hObject是CBitmap类的一个成员)
gamewnd::gamewnd()
{
Create (NULL,"创建窗口") ;
bitmap = new CBitmap; // 建立了一个位图类对象,并用指针指向。但这个对象还是空的,之后我们可以把图片放进去
bitmap->m_hObject = LoadImage(NULL, "1.1.bmp", IMAGE_BITMAP ,93,100,LR_LOADFROMFILE);
}
24、把已经加载好的图片在窗口中显示出来
从图片加载到显示出来的步骤需要:
1、LoadImage把本地图片传入内存中,返回句柄(相当于返回资源地址)
2、用CBitmap类接收句柄(这步可以省略,但是之后要传句柄,如果没有接收的话,就需要把整个函数当参数,这个参数会很长)
3、创建客户区dc (dc表示窗口空白的部分,图片自然是放到这个区域)
4、CreateCompatibleDC 创建一个兼容dc (这个函数是CDC成员,这个函数创建了一个与客户区dc兼容的dc,因为图片不能直接读入dc,他需要先读入兼容的dc中)
5、SelectObject 把图片传入兼容dc中 (这个函数是CDC成员,这一步把图片传入了兼容dc中)
6、biblt 把图片传入客户区dc中 (传入后,在showwindow函数中就可显示出来)
gamewnd::gamewnd()
{
Create (NULL,"创建窗口") ;
bitmap = new CBitmap; // 建立了一个位图类对象,并用指针指向。但这个对象还是空的,之后我们要把图片放进去
bitmap->m_hObject = LoadImage(NULL, "1.1.bmp", IMAGE_BITMAP ,93,100,LR_LOADFROMFILE);//这个位图类里面就有了图片
mdc = new CDC; // 这里CDC是一个库类,新建了一个对象,用来创建兼容dc,并存放位图,本来应该写成CDC *mdc = new CDC;但因为这个是写在构造函数里,是构造函数里的局部变量,而构造函数结束后,我们之后还要使用这个变量,所以这里定义成gamewnd的类成员。这里我们还需要在gamewnd.h中声明或者右击类目录添加这个成员。
CClientDC dc (this) ; //创建客户区,this是指这个类,相当于是在这个主窗体中创建了客户区
mdc->CreateCompatibleDC(&dc);// 该函数创建一个与指定设备(这里就是CClientDC dc)兼容的内存设备上下文环境(DC)。通过GetDc()获取的HDC直接与相关设备沟通,而本函数创建的DC,则是与内存中的一个表面相关联。因为图片不可以直接通过dc读入窗口,他要先放入一个与dc兼容的设备上下文中。这是为后面的SelectObject(bitmap);做准备
mdc->SelectObject(bitmap);//把位图传入前面一步所建立的兼容DC中,这一步不能提前,如果提前不会报错,但运行时会出错。
}
到这里,还剩最后一步biblt,只需要把兼容DC的内容读取到真正的dc中就行了,但是这一步需要使用WM_PAINT
系统会在很多的不同的机制下发送WM_PAINT消息,比如调用UpdateWindow函数,第一次创建窗口,改变了窗口的大小,最大化,最小化等等。这些动作的产生都是有系统来控制的,应用程序只是接收消息,并处理消息。
我们先创建了一个空白窗口,然后系统就会发生WM_PAINT消息(在这里,其实就是构造函数执行完后,就执行在这个类中,其自动生成的onpaint函数。这个消息不是立刻执行,而是等待执行)
所以,我们需要在这个类中,添加WM_PAINT消息,相当于是在这个类中增加onpaint函数。
我们把bc.BitBlt 放在一个 gamewnd::OnPaint()函数中 (需要我们自动添加WM_PAINT 它自动生成onpaint)
我们在类目录下对gamewnd类增加message handler
在gamewnd类目录中添加message handle ————WM_PAINT————add and edit
这个时候就会在类成员中增加onpaint函数
我们把dc.BitBlt (0,0,93,100,mdc,0,0,SRCCOPY);放入这个函数里面,运行即可。
前面0,0表示画布的左上起始位置,后面的0,0是指读入的图片,它放在窗口中左上的位置。
93,100是指读入图片的长宽。如果图片放置的位置不在画布上,那也是显示不出来的。
mdc,就是函数通过mdc来找到兼容的dc从中读取图片到真正的dc中。
最后一个SRCCOPY表示按照原样复制过来,不拉伸,不缩放等。
这里的画布就是CPaintDC dc 。但我们之前用的是CClientDC啊,其实CPaintDC跟CClientDC差不多。前面的兼容dc对于这两个都能用。
这里之所以要改为用CPaintDC dc ,这是CPaintDC与CClientDC的一大区别,在onpaint函数中,CClientDC会不断发出WM_PAINT消息,导致不断的重绘。而CPaintDC则不会这样。
把程序运行后:
当我们放大缩小窗口,其图片是不变的。这是因为当我们改变大小,或窗体变无效区时,窗口会自动发送wm_paint消息,从而我们onpaint函数又会被执行。
如果我们在onpaint函数中用CClientDC,可以做一个实验,把onpaint函数里,让画布与画的坐标 +x ,+y 然后让x,y自增。如果是CClientDC,那么窗口运行后,画就一直在移动。而CPlientDC只有在更新窗口时图片才会移动。
|
|