在CodeBolcks+Windows API下的C++编程教程——用向导创建一个Windows GUI项目(aTetris)

0.前言

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

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

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

了解不同方式实现同样效果的差异,请阅读以下文章:

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

  1. 使用向导新建一个Win32 GUI程序(aTetris)
  2. 向导为我生成的项目文件aTetris与xTetris有什么不同
  3. 通过修改aTetris的代码实现与xTetris一致的视觉效果
  4. 结束语

 

1.使用向导新建一个Win32 GUI程序(aTetris)

在开始编写程序之前,先说一个重要的问题:

CodeBlocks追求的是跨平台编程,一次编写代码,可以在多个操作系统下编译成应用程序,而不需要为了适应操作系统而修改。而选择了创建Win32 GUI应用程序,使用了Windows API,这就决定着编写的应用程序只能在Windows操作系统下运行,不可能在其他的操作系统下使用。也就是说完全放弃了跨平台的能力。

在开始下面的内容之前,我假定你已经安装了CodeBlocks程序开发环境,测试使用CodeBlocks创建第一个程序成功编译运行,并且了解了C++语言的基础知识和使用Windows API开发C++程序的知识。

如果你还有哪一方面没有做到,请阅读下面的文章:

在开始下面的内容之前,你还需要阅读我写的以下文章。在以下文章中有创建应用程序xTetris的全部内容,而本篇文章中创建应用程序sTetris的过程、解读、修改等都要与xTetris进行对比,认识二者的异同点。

在CodeBolcks+wxWidgets下的C++编程教程——用向导创建一个wxWidgets项目(xTetris) - lexyao - 博客园

使用向导新建一个Win32 GUI project程序的操作步骤如下:

第一步:打开新建项目向导

创建任何类型的项目在这一步的操作是相同的,后续就有差别了。有两种方法:

①主菜单:File->New->Projects

②点击Start Here页面中的Create New Project

第二步:在向导中选择项目类型Win32 GUI project

第三步:选择窗口类型,点击Next

提供两种窗口类型,在这里我们选择Frame based。

 

第四步:输入项目名称、文件保存位置

输入项目名称。将来你编译生成的exe应用程序将会使用这个名称。保存这个项目的文件夹也会默认使用这个名称,不过你可以在这个页面中修改保存项目文件的文件夹。

  • 在项目名称栏中输入sTetris。将来编译生成的项目文件将会是aTetris.exe
  • 将文件路径中自动添加的aTetris改为Tetris。修改之后保存创建的项目文件的文件夹将会是Tetris,而不是默认的aTetris

 第五步:选择编译器

这一步保持默认就可以了,直接点击Finish就行了。

按向导完成项目创建后,在CodeBlocks左边的栏目中将会看到新创建项目所包含的文件。下图中显示了向导创建的项目中包含的文件的清单。

 与wxWidgets项目不同,Win32 GUI 项目的向导只创了一个文件main.cpp,没有头文件和资源文件。

为了与今后将要创建的项目文件名称有区别,将向导生成的件的文件名由main.cpp改为aTetrisMain.cpp。

修改文件名的操作方法是:

在CodeBlocks左边的栏目中要修改的文件名上点击鼠标右键,从弹出的菜单中选择“Rename file…”,输入新的文件名,点击[OK]按钮确认修改。

完成修改后你会发现CodeBlocks左边的栏目中的文件变成了新的文件名,文件资源管理器中的文件名也同步改变了。

第六步、编译运行创建的项目

Code::Blocks工具栏中的编译运行按钮,就会执行编译过程。Code::Blocks下部的窗口中有两个选项卡,分别是编译日志和编译信息。如果编译出错,会在这里出现红色的错误信息。如果是代码错误,编译结束后,点击错误信息,代码窗口会跳转到出错的代码行。

 只要不出现错误,编译链接完成后就会运行程序,出现你的应用程序运行后的主界面窗口。

以下是向导创建的Win32 GUI 应用程序的主界面,这个例子中窗口类型选择了Frame based。

2.向导为我生成的项目文件aTetris与xTetris有什么不同

以下是向导为我们生成的代码,关于这些代码的详细解释,请点击下面链接查看:

在CodeBolcks+Windows API下的C++编程教程——使用向导新建的Win32 GUI程序代码详解 - lexyao - 博客园

以下是aTetrisMain.cpp文件的全部代码:

#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#include <tchar.h>
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           _T("Code::Blocks Template Windows App"),       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

从以上代码看,找不到一点与基于wxWidgets开发的xTetris项目有任何相同的地方。不单是代码结构不同,编程风格也不相同。唯一相同的是编译运行后出现的主界面的画面框架相同,但缺少了菜单、状态栏,图标跟sTetris的初始图标相同。

3.通过修改aTetris的代码实现与xTetris一致的视觉效果

向导生成的项目aTetris和xTetris视觉效果不同的地方是有四点:标题、图标、菜单栏、状态栏。

要想实现视觉效果一致,需要给sTetris增加实现五方面的效果:

  • 主窗口标题栏显示标题
  • 任务栏中、主窗口左上角显示与xTetris中一样的图标
  • 给主窗口添加菜单
  • 添加点击菜单项引发的操作
  • 添加状态栏,并将状态栏分成两列,还要显示文字

下面分别实现这五方面的效果。

3.1 主窗口标题栏显示标题

在aTetrisMain.cpp代码中查找程序运行后出现在窗口标题栏中的字符串,找到以下代码:

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    ....../* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           ......
           _T("Code::Blocks Template Windows App"),       /* Title Text */
           ......
           );

    ......
}

将代码中的字符串"Code::Blocks Template Windows App"改为"多彩俄罗斯方块aTetris"。

完成修改后编译运行aTetris项目,结果没有像预想的那样,窗口标题栏显示的不是汉字,而是乱码。

为什么会这样呢?在wxWidgets项目中,只要字符串使用了_T()就能正确显示汉字,为什么这里Win32项目就成了乱码了呢?

显示乱码的原因肯定是字符串编码问题。汉字需要使用Unicode或者utf-8编码,Windows不是使用的Unicode编码吗?

其实,这里有一个问题,程序开发环境支持Unicode和已经设置了Unicode是两回事。

看一看aTetrisMain.cpp开头的几行编译指令代码,这些指令就是决定是否使用了Unicode编码的。

 从以上代码看,defined(UNICODE) && !defined(_UNICODE)的值是false。

将以上代码做一个修改,看一看是哪一个表达式返回的false。

 经测试,上面的第一行不管是改成#if defined(UNICODE) 还是#if defined(_UNICODE),上面截图中灰色的代码都是灰色的,这说明UNICODE和都没有定义。

按着代码的逻辑,当第一行为真的时候执行第二行,否则执行第三行的判断;第三行的判断为真,则执行第四行。

而从以上截图看到,第一行为假的时候第三行没有执行的机会,这说明这一组代码存在逻辑错误,或者说CodeBlocks不支持这种路逻辑。可能吗?从语法看不出问题啊。

经过测试,在文件的开头添加代码,以下两种形式都能正常显示。不但#elif正常了,编译运行aTetris项目,窗口标题栏显示也正常了。

 两个同时添加后#elfi又不正常了,这说明CodeBlocks在这个问题的处理上存在缺陷,或者这一组代码存在逻辑错误。

3.2 任务栏中、主窗口左上角显示与xTetris中一样的图标

给Win32项目添加图标,就需要有一个图标文件。

在Windows操作系统中,图标的来源有两种情况:

  • 操作系统提供的图标。这种图标在操作系统的资源文件里,任何应用程序都可以使用它。
  • 用户自己提供的图标。这种图标保存在用户自己的文件里,由用户自己管理。

如果不是使用操作系统提供的图标,那就需要给自己的应用程序添加一个资源文件,在资源文件中添加图标。

本想在这里,我们给aTetris项目添加一个资源文件,但是考虑到资源文件是一个大话题,添加图标也是一个大话题,所以决定单独写一篇文章,讲述如何给自己的应用程序添加资源文件和图标。

下面就是给aTetris项目添加资源文件和图标的文章的链接:

 在CodeBolcks+Windows API下的C++编程教程——给你的项目中添加资源文件和图标 - lexyao - 博客园

 使用上述文章中的方法,我们给aTetris项目添加了一个资源文件aTetris.rc,资源文件的内容如下:

aaaa ICON "D:/CodeBlocks/wxWidgets-3.2.6/include/wx/msw/std.ico"

 

为了将资源文件中的图标添加到aTetris项目主窗口和任务栏,我们修改aTetrisMain.cpp文件中使用图标的代码如下:

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    ....../* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           ......

        /* 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);

           ......
           );

    ......
}

 

3.3 给主窗口添加菜单

在Windows操作系统中,应用程序的菜单有三种情况:

  • 系统菜单。点击应用程序主窗口左上角的图标会弹出一个菜单,这就是系统菜单,所有的应用程序的主窗口都有这个菜单,功能是相同的。程序员编写程序的时候可以在这个菜单中添加额外的功能,但很少有人这么做。
  • 主菜单。显示在应用程序主窗口上边的菜单就是主菜单,是程序员编写程序的时候加上去的。以前的主菜单都是一个菜单条,现在有很多的应用软件为了节省空间把主菜单放入了窗口左上角或者右上角的一个图标里,点击这个图标才能看到主菜单。
  • 弹出菜单。也叫快捷菜单、上下文菜单。这种菜单也是程序员编写程序时加上去的。当用户在特定的区域点击鼠标右键,就会弹出一个与这个区域的操作有关的菜单,使用很方便。

给应用程序添加主菜单跟添加图标的操作很相似,同样包括三部分内容:

  • 添加一个头文件,在这个头文件中定义资源文件中使用的常量
  • 在资源文件中添加菜单资源
  • 在代码中引用菜单资源

下面就是介绍如何给aTetris项目添加头文件、主菜单的文章的链接:

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

添加头文件跟添加资源文件的操作相似,只是头文件扩展名是h或hpp。给aTetris项目添加的头文件aTetrs.h的内容如下:

#ifndef ATETRIS_H_INCLUDED
#define ATETRIS_H_INCLUDED

#define IDM_NEW                         40001
#define IDM_EXIT                        40002
#define IDM_ABOUT                       40003

#endif // ATETRIS_H_INCLUDED

 使用上述文章中的方法,我们给aTetris项目的资源文件aTetris.rc中添加了主菜单,资源文件中添加的主菜单的内容如下:

/////////////////////////////////////////////////////////////////////////////
// Menu

aTetris MENU
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "&New...",                     IDM_NEW
        MENUITEM SEPARATOR
        MENUITEM "E&xit",                       IDM_EXIT
    END
    POPUP "&Help"
    BEGIN
        MENUITEM "&About...",                   IDM_ABOUT
    END
END

aTetrisMain.cpp文件将资源文件中的主菜单添加到aTetris项目主窗口的代码如下:

复制代码
TCHAR szMenuResource[ ] = _T("aTetris");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    ......
    wincl.lpszMenuName = szMenuResource; //wincl.lpszMenuName = NULL;                /* No menu */
    ......
}
复制代码

 下图是给aTetris项目添加主菜单后编译运行的主窗口的样子:

 

3.4 添加点击菜单项引发的操作

把资源文件中的菜单添加到aTetris项目的主窗口后,主窗口能够显示一个主菜单,但这个菜单中看不中用,什么也没有做。

为什么这样呢?因为还没有给它添加响应菜单项点击的代码。

本想在这里,我们给aTetris项目添加主菜单的事件响应代码,但是考虑到消息循环和事件响应,是一个大话题,所以决定单独写一篇文章,讲述消息循环和如何给自己的应用程序添加主菜单操作响应代码。

下面就是给aTetris项目添加主菜单、响应菜单事件以及消息循环的文章的链接:

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

 使用上述文章中的方法,我们给aTetris项目添加了菜单响应的代码。

以下是给aTetris项目添加了菜单响应的代码aTetrisMain.cpp文件中的窗口过程函数WindowProcedure的完整代码:

/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_EXIT:
            SendMessage(hwnd, WM_CLOSE, 0, 0);
            return 0;

        case IDM_ABOUT:
            MessageBox(hwnd, _T("This is my aTetris by Win32 GUI\n")
                       _T("Copyright(c) lexyao,2024"),
                       szClassName,MB_ICONINFORMATION | MB_OK);
            return 0;

        }
        break;

    case WM_DESTROY:
        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        break;
    default:                      /* for messages that we don't deal with */
        return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

以下是给aTetris项目添加了菜单事件响应代码后,编译运行aTetris项目,在aTetris中点击菜单[Help->About...]显示消息的窗口样子: 

 

3.5 添加状态栏,并将状态栏分成两列,还要显示文字

程序员习惯在自己的应用程序的主窗口下边添加一个状态条,这样看起开更像Windows操作系统的窗口,这个状态条可以显示一些动态的信息。

添加工具条涉及到添加窗口组件,这是一个大话题,所以决定单独写一篇文章,讲述如何给自己的应用程序添加状态条。

下面就是给aTetris项目添加状态条的文章的链接:

 在CodeBolcks+Windows API下的C++编程教程——给你的项目中添加状态栏(通用公共控件) - lexyao - 博客园

 使用上述文章中的方法,我们给aTetris项目添加了使用状态栏的代码。

为此,增加了两个文件,这两个文件是下一步使用更多公共控件的基础。

一个是向程序添加状态栏的程序cpp文件aTetrisCommCtrls.cpp,文件的完整内容如下:

#if !defined(UNICODE)
    #define UNICODE
#endif

#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#include <windows.h>
#include <commctrl.h>
#include "aTetrisCommCtrls.h"

// Description:
//   Creates a status bar and divides it into the specified number of parts.
// Parameters:
//   hwndParent - parent window for the status bar.
//   idStatus - child window identifier of the status bar.
//   hinst - handle to the application instance.
//   cParts - number of parts into which to divide the status bar.
// Returns:
//   The handle to the status bar.
//
HWND DoCreateStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinst, int cParts)
{
    HWND hwndStatus;
    RECT rcClient;
    HLOCAL hloc;
    PINT paParts;
    int i, nWidth;

    // Ensure that the common control DLL is loaded.
    InitCommonControls();

    // Create the status bar.
    hwndStatus = CreateWindowEx(
                     0,                       // no extended styles
                     STATUSCLASSNAME,         // name of status bar class
                     (PCTSTR) NULL,           // no text when first created
                     SBARS_SIZEGRIP |         // includes a sizing grip
                     WS_CHILD | WS_VISIBLE,   // creates a visible child window
                     0, 0, 0, 0,              // ignores size and position
                     hwndParent,              // handle to parent window
                     (HMENU) idStatus,       // child window identifier
                     hinst,                   // handle to application instance
                     NULL);                   // no window creation data

    // Get the coordinates of the parent window's client area.
    GetClientRect(hwndParent, &rcClient);

    // Allocate an array for holding the right edge coordinates.
    hloc = LocalAlloc(LHND, sizeof(int) * cParts);
    paParts = (PINT) LocalLock(hloc);

    // Calculate the right edge coordinate for each part, and
    // copy the coordinates to the array.
    nWidth = rcClient.right / cParts;
    int rightEdge = nWidth;
    for (i = 0; i < cParts; i++)
    {
        paParts[i] = rightEdge;
        rightEdge += nWidth;
    }

    // Tell the status bar to create the window parts.
    SendMessage(hwndStatus, SB_SETPARTS, (WPARAM) cParts, (LPARAM)paParts);

    // Free the array, and return.
    LocalUnlock(hloc);
    LocalFree(hloc);
    return hwndStatus;
}

HWND DoCreateStatusBar2(HWND hwndParent, int idStatus, HINSTANCE hinst, int cParts)
{
    HWND hwndStatus;
    RECT rcClient;
    HLOCAL hloc;
    PINT paParts;
    int i, nWidth;

    hwndStatus = CreateStatusBar(hwndParent,idStatus,hinst);

    // Get the coordinates of the parent window's client area.
    GetClientRect(hwndParent, &rcClient);

    // Allocate an array for holding the right edge coordinates.
    hloc = LocalAlloc(LHND, sizeof(int) * cParts);
    paParts = (PINT) LocalLock(hloc);

    // Calculate the right edge coordinate for each part, and
    // copy the coordinates to the array.
    nWidth = rcClient.right / cParts;
    int rightEdge = nWidth;
    for (i = 0; i < cParts-1; i++)
    {
        //paParts[i] = -10;
        paParts[i] = rightEdge;
        rightEdge += nWidth;
    }
    paParts[i] = -1;

    // Tell the status bar to create the window parts.
    SetStatusParts(hwndStatus, cParts, paParts);

    // Free the array, and return.
    LocalUnlock(hloc);
    LocalFree(hloc);

    return hwndStatus;
}

HWND CreateStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinstApp,DWORD dwStyle)
{
    HWND hwndStatus;

    // Ensure that the common control DLL is loaded.
    InitCommonControls();

    // Create the status bar.
    return CreateWindowEx(
               0,                       // no extended styles
               STATUSCLASSNAME,         // name of status bar class
               (PCTSTR) NULL,           // no text when first created
               dwStyle |         // includes a sizing grip
               WS_CHILD | WS_VISIBLE,   // creates a visible child window
               0, 0, 0, 0,              // ignores size and position
               hwndParent,              // handle to parent window
               (HMENU) idStatus,       // child window identifier
               hinstApp,                   // handle to application instance
               NULL);                   // no window creation data
}


HRESULT SetStatusParts(HWND hwndStatus, int iParts, const int*  aPartWidth)
{
    return SendMessage(hwndStatus, SB_SETPARTS, (WPARAM)iParts, (LPARAM)aPartWidth);
}


HRESULT SetStatusTextA(HWND hwndStatus, LPSTR pszStatusText, int iParts)
{
    //SendMessage传递的参数是指针,使用LPSTR和LPWSTR没有什么差别
    //而SetStatusText的参数传递的是字符串,会认为LPSTR和LPWSTR是两种类型的数据
    return SendMessageA(hwndStatus, SB_SETTEXT, iParts, (LPARAM)(LPSTR)(pszStatusText));
    //return SendMessage(hwndStatus, SB_SETTEXT, iParts, (LPARAM)(LPWSTR)(pszStatusText));
}


HRESULT SetStatusTextW(HWND hwndStatus, LPWSTR pszStatusText, int iParts)
{
    return SendMessage(hwndStatus, SB_SETTEXT, iParts, (LPARAM)(LPWSTR)(pszStatusText));
}

HRESULT SetStatusSize(HWND hwndStatus)
{
        return SendMessage(hwndStatus, WM_SIZE, (WPARAM)0, (LPARAM)0);
}

一个是定义aTetrisCommCtrls.cpp文件中的函数的头文件aTetrisCommCtrls.h,文件的完整内容如下:

#ifndef ATETRISCOMMCTRLS_H_INCLUDED
#define ATETRISCOMMCTRLS_H_INCLUDED

#include <tchar.h>
#include <commctrl.h>

HWND DoCreateStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinst, int cParts);
HWND DoCreateStatusBar2(HWND hwndParent, int idStatus, HINSTANCE hinst, int cParts);
HWND CreateStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinstApp,DWORD dwStyle = SBARS_SIZEGRIP);
HRESULT SetStatusParts(HWND hwndStatus, int iParts, const int* aPartWidth);
HRESULT SetStatusTextA(HWND hwndStatus, LPSTR pszStatusText, int iParts);
HRESULT SetStatusTextW(HWND hwndStatus, LPWSTR pszStatusText, int iParts);
#define SetStatusText __MINGW_NAME_AW(SetStatusText)

HRESULT SetStatusSize(HWND hwndStatus);

#endif // ATETRISCOMMCTRLS_H_INCLUDED

以下是给aTetris项目添加了菜单响应的代码aTetrisMain.cpp文件中的窗口过程函数WindowProcedure的相关代码:

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HWND hwndStatus;

    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        hwndStatus=DoCreateStatusBar2(hwnd,NULL,GetModuleHandle(NULL),2);
        SetStatusText(hwndStatus,_T("欢迎使用多彩俄罗斯方块!"),0);//SetStatusText
        SetStatusText(hwndStatus,_T("aTetris"),1);
        break;
    case WM_SIZE:
        SetStatusSize(hwndStatus);
        //SendMessage(hwndStatus, WM_SIZE, 0, 0);

        break;
    ......
    }

    return 0;
}

 

4.结束语

由于这篇文章讲述的内容涉及到Windows API编程的很多基础性的内容,每项内容都是一个大话题,所以都单独写了一篇文章,在这篇文章里引用这些专题文章的最后成果。

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