在CodeBolcks+Windows API下的C++面向对象的编程教程——给你的项目中添加头文件和菜单

0.前言

我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。

了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”和“2.已经编写完成的文章(目录)”:

学习编程从游戏开始——编程计划(目录) - lexyao - 博客园

这是一篇专题文章,这篇文章是用来讲解下面这篇文章用到的知识的,我在这篇文章中讲解程序使用的例子就是在下面这篇文章中创建的oTetris项目:

在CodeBolcks+Windows API下的C++面向对象的编程教程——用面向对象的方法改写用向导创建一个Windows GUI项目(oTetris) - lexyao - 博客园

在这篇文章里,我主要讲述以下几个方面的内容:

  1. 给项目添加资源文件和头文件
  2. aTetris项目中添加菜单的代码分析
  3. oTetris项目中添加菜单的方法
  4. oTetris和aTetris项目添加菜单的代码对比
  5. 结束语

 

1.给项目添加资源文件和头文件

在Win32 GUI项目中,要给应用程序添加菜单,需要做以下几个方面的工作:

  1. 先创建一个头文件(.h),在头文件中定义菜单项的命令ID(数字常数)
  2. 再创建一个资源文件,在资源文件中添加菜单资源
  3. 再cpp文件中修改代码,将菜单添加到应用程序中

以上工作在aTetris项目中已经做过了,在oTetris项目中直接使用aTetris的头文件和资源文件就行了。创建头文件、资源文件的过程请看下面的文章:

在CodeBolcks+Windows API下的C++编程教程——给你的项目中添加头文件和菜单 - lexyao - 博客园

在这里直接使用aTetris的文件,不用修改。具体操作包括以下步骤:

  1. 将头文件和资源文件添加到oTetris项目
  2. 在cpp文件中包含头文件
  3. 在cpp文件中添加使用菜单资源的代码

首先是添加头文件和资源文件,操作如下:
在CodeBlocks的项目列表中鼠标右击oTetris项目->在菜单中选择“Add files...”->选择aTetris项目的aTetris.h和aTetris.rc添加到oTetris项目中。

在oTetrisMain.cpp文件的头部添加以下代码包含头文件:

#include "aTetris.h"

剩下的就是添加使用菜单的代码了。

2.aTetris项目中添加菜单的代码分析

aTetris项目使用菜单的代码是在入口函数WinMain中定义主窗口类数据的时候添加的。aTetrisMain.cpp中的代码如下:

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    ......
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    ......
    wincl.lpszMenuName = _T("aTetris"); //wincl.lpszMenuName = NULL;                /* No menu */
    ....../* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    ......
}

在程序入口函数WinMain中使用下面语句将资源文件中菜单资源的名称“aTetris”赋值给窗口结构的wincl.lpszMenuName。

wincl.lpszMenuName = _T("aTetris");

没有添加菜单的时候这个语句的赋值是NULL:

wincl.lpszMenuName = NULL;                /* No menu */

 

3.oTetris项目中添加菜单的方法

在oTetris项目中要实现同样的方法只需要添加下面代码中的红色语句:

void MainWindow::WindowClassEx(PWNDCLASSEX wc)
{
    wc->lpszMenuName = _T("aTetris");
    wc->hbrBackground = (HBRUSH) COLOR_BACKGROUND;
}

其中的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.结束语

从添加菜单的代码来看,没有看出面向对象的编程有什么优势,甚至比面向过程的方法更复杂。或许真的是这样。不过,面向对象的编程技术是用来解决复杂问题的,目的是代码的重复利用。使用的越多的代码在面向对象的方法中表现的越有优势。
面向过程将数据和代码都摆在同一个层面上,都是看得见的。
面向对象的方法将数据和代码打包封装在类里,你只需要知道类的接口就可以使用,而不需要类的内部做了什么。
在将来当你的程序越来越大的时候,你会体验到面向对象编程的魅力。

 

posted @ 2024-12-17 12:12  lexyao  阅读(12)  评论(0编辑  收藏  举报