0.前言
我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。
了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”:
这是一篇专题文章,这篇文章是用来讲解下面这篇文章用到的知识的,我在这篇文章中讲解程序使用的例子就是在下面这篇文章中创建的oTetris项目:
在CodeBolcks+Windows API下的C++面向对象的编程教程——用面向对象的方法改写用向导创建一个Windows GUI项目(oTetris) - lexyao - 博客园
在这篇文章里,我主要讲述以下几个方面的内容:
- 给项目添加资源文件文件
- aTetris项目中添加图标的代码分析
- oTetris项目中添加图标的方法
- oTetris和aTetris项目添加图标的代码对比
- 创建窗口后给项目添加图标
- 结束语
1.给项目添加资源文件文件
在Win32 GUI项目中,要给应用程序添加图标,需要做以下几个方面的工作:
- 先创建一个资源文件,在资源文件中添加菜单资源
- 在cpp文件中修改代码,将图标添加到应用程序中
以上工作在aTetris项目中已经做过了,在oTetris项目中直接使用aTetris的资源文件就行了。创建资源文件的过程请看下面的文章:
在CodeBolcks+Windows API下的C++编程教程——给你的项目中添加资源文件和图标 - lexyao - 博客园
在这里直接使用aTetris的文件,不用修改。具体操作包括以下步骤:
- 将资源文件添加到oTetris项目
- 在cpp文件中添加使用图标资源的代码
首先是添加资源文件,操作如下:
在CodeBlocks的项目列表中鼠标右击oTetris项目->在菜单中选择“Add files...”->选择aTetris项目的aTetris.rc添加到oTetris项目中。
剩下的就是添加使用菜单的代码了。
2.aTetris项目中添加图标的代码分析
aTetris项目使用菜单的代码是在入口函数WinMain中定义主窗口类数据的时候添加的。aTetrisMain.cpp中的代码如下:
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { ...... WNDCLASSEX wincl; /* Data structure for the windowclass */ ....../* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (hThisInstance, _T("aaaa"));//wincl.hIcon = LoadIcon (NULL, ); wincl.hIconSm = LoadIcon (hThisInstance, _T("aaaa"));//wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); ....../* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; ...... }
在程序入口函数WinMain中使用下面语句将资源文件中图标资源的名称“aaaa”赋值给窗口结构的wincl的hIcon和hIconSm。
wincl.hIcon = LoadIcon (hThisInstance, _T("aaaa")); wincl.hIconSm = LoadIcon (hThisInstance, _T("aaaa"));
没有添加资源图标的时候这个语句的赋值是IDI_APPLICATION,使用的是操作系统资源中的图标:
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
3.oTetris项目中添加图标的方法
在oTetris项目中要实现同样的方法只需要添加下面代码中的红色语句:
void MainWindow::WindowClassEx(PWNDCLASSEX wc) { wc->hIcon = LoadIcon (wc->hInstance, _T("aaaa")); wc->hIconSm = LoadIcon (wc->hInstance, _T("aaaa")); ...... }
其中的WindowClassEx是我们在基类BaseWindow中添加了纯虚函数后在MainWindow中添加的实现。
以下是使用WindowClassEx的代码:
template <class DERIVED_TYPE> BOOL BaseWindow<DERIVED_TYPE>::Create( PCWSTR lpWindowName, DWORD dwStyle, DWORD dwExStyle, int x , int y, int nWidth , int nHeight, HWND hWndParent, HMENU hMenu ) { WNDCLASSEX wc = {0}; ...... WindowClassEx(&wc); if (!RegisterClassEx(&wc)) return 0; ...... }
从代码看,aTetris和oTetris项目中设置菜单的代码执行的位置是一样的,只是代码的表现形式不一样罢了。
4.oTetris和aTetris项目添加菜单的代码对比
在前面的内容中已经对aTetris和oTetris项目中设置菜单的代码进行了对比,采用的方法、使用的位置是一样的。
不同点在于:
- aTetris在程序的入口函数中直接加入,代码简单、明了,比较容易看懂
- oTetris在子类中重载基类的纯虚函数的代码中,看起来不那么直观,但了解了程序执行的流程后就明白了
从这个简单的代码来看,看不出面向对象的优势,甚至还会觉得面向对象的编程方法把简单的事情搞得复杂了。真的是这样吗?
或许使用的多了才会感觉到:面向对象的的编程方法把简单的事情搞得复杂了,把复杂的事情搞得简单了。
5.创建窗口后给项目添加图标
前面说的添加图标的方法是在创建程序的主窗口之前定义项目主窗口类的结构数据的时候添加的。还有一种方法是在创建主窗口后的任何时候头可以使用的添加方法。
首先我来了解一下用到的知识。
添加图标的方法是使用SendMessage向主窗口的手柄发送WM_SETICON消息实现的。以下是Microsoft资料库中对SendMessage函数和WM_SETICON消息的说明:
WM_SETICON消息 (Winuser.h) - Win32 apps | Microsoft Learn
sendMessage 函数 (winuser.h) - Win32 apps | Microsoft Learn
函数及参数的格式如下:
LRESULT SendMessage( [in] HWND hWnd, [in] UINT Msg, [in] WPARAM wParam, [in] LPARAM lParam );
发送消息时,
wParam要设置的图标的类型。 此参数的取值可为下列值之一,下面的常数是在winuser.h中定义的:
#define ICON_SMALL 0 #define ICON_BIG 1 #define ICON_SMALL2 2
lParam新的大图标或小图标的句柄。 如果此参数为 NULL,则删除 wParam 指示的图标。
图标的句柄由LoadIcon函数获得。从资源获得图标句柄有两种情况:
- 资源文件中图标的ID是数字6666时:HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(666));
- 资源文件中图标的ID是字符串aaaa时:HICON hIcon = LoadIcon(hInstance, _T("aaaa"));
LoadIcon函数的定义:
HICON WINAPI LoadIcon ( HINSTANCE hInstance, LPCTSTR lpIconName );
hInstance:图标资源所在模块的实例句柄。如果是标准图标,此参数必须为NULL。
lpIconName:如果 hInstance 为非 NULL, 则 lpIconName 按名称或序号指定图标资源。 必须使用 MAKEINTRESOURCE 宏打包此序号。
在面向对象的方法中,通常是吧底层的东西封装起来。我们添加两个函数,这样使用的时候就不用直接去写Windows API的代码了:
在MainWindow添加函数定义:
LRESULT SetIcon(HINSTANCE hInstance,WPARAM wParam, LPCTSTR lpIconName);
添加函数实现:
LRESULT MainWindow::SetIcon(HINSTANCE hInstance,WPARAM wParam, LPCTSTR lpIconName) { HICON hIcon = LoadIcon(g_hInstance, lpIconName); return SendMessage(hwndDlg, WM_SETICON, wParam, (LPARAM)hIcon); }
使用时调用SetIcon就可以设置窗口图标了。
6.结束语
从添加菜单的代码来看,没有看出面向对象的编程有什么优势,甚至比面向过程的方法更复杂。或许真的是这样。不过,面向对象的编程技术是用来解决复杂问题的,目的是代码的重复利用。使用的越多的代码在面向对象的方法中表现的越有优势。
面向过程将数据和代码都摆在同一个层面上,都是看得见的。
面向对象的方法将数据和代码打包封装在类里,你只需要知道类的接口就可以使用,而不需要类的内部做了什么。
在将来当你的程序越来越大的时候,你会体验到面向对象编程的魅力。
标签:CodeBolcks,LoadIcon,Windows,代码,oTetris,C++,添加,aTetris,图标 From: https://www.cnblogs.com/lexyao/p/18612314