IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 使用C/C++制作简单的俄罗斯方块 一 -> 正文阅读

[C++知识库]使用C/C++制作简单的俄罗斯方块 一

ZERO 、

>本章是主要任务是不使用外置图形库,做一个自己的窗口

一、使用环境

	使用VS2022,需要包含windows桌面应用程序扩展,
	因为我们不使用图形库graphics.h。

二、说明以及预览图

    说明:demo做得可能有点粗糙,因为使用的只有C/C++的内置函数,但是基本功能还是实现了。
    本来还想加入一些道具元素,但能力有限最后还是鸽了。
    写这篇文章的目的其实还是复习一下,然后也是希望在写文章的过程中找到错误,也希望读者能够给我一些建议。
    下面是预览图

在这里插入图片描述

三、制作教程

1、打开VS,新建项目,找到windows应用程序模板,如下图所示。

进入之后点击调试,你就会看到一个窗口,当然是白色的,什么也没有。

在这里插入图片描述
在这里插入图片描述

2、修改模板

1)、CreateWindowW函数

这里我会给大家简单说明一下模板代码中一些比较重要的部分,包括以及要修改的部分。

首先是模板自定义的InitInstance(HINSTANCE, int)函数,你会发现这个函数里面包含着CreateWindowW()函数,下面简单介绍一下,搞清这个函数再来下一个注册函数。

_In和_opt顾名思义,一个输入,一个输出;
LPCTSTRlpClassNameLPCTSTRlpWindowName是窗口类名称和标题,文件开头就有定义,赋值的时候使用的是MyRegisterClass函数,我们下面再讲;
然后是句柄的含义,详情你们可以去官方API上面寻找,我个人的理解其实就是一个特定的标识符,浅一点来说就是跟人们的身份证雷同。

HWND WINAPI CreateWindow(
  _In_opt_  LPCTSTRlpClassName,   // 窗口类名称
  _In_opt_  LPCTSTRlpWindowName,  // 窗口标题
  _In_      DWORD dwStyle,        // 窗口风格,或称窗口格式
  _In_      int x,                // 初始 x 坐标
  _In_      int y,                // 初始 y 坐标
  _In_      int nWidth,           // 初始 x 方向尺寸
  _In_      int nHeight,          // 初始 y 方向尺寸
  _In_opt_  HWNDhWndParent,       // 父窗口句柄
  _In_opt_  HMENUhMenu,           // 窗口菜单句柄
  _In_opt_  HINSTANCEhInstance,   // 程序实例句柄
  _In_opt_  LPVOIDlpParam         // 创建参数

);

前面几个参数很简单,没必要讲;
1.父窗口句柄我们没有,设置为NULL;
2.窗口菜单句柄我们也没有,为NULL;
3.程序实例句柄,可有可无,但我们一般设置为主函数的第一个参数,也就是hInstance
4.最后一个没什么用,设置为NULL。
5.最后我们使用的窗口函数就是这样:
6.HWND hwnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIND_WIDTH, WIND_HEIGHT, nullptr, nullptr, hInstance, nullptr);
其中WIND_WIDTH, WIND_HEIGHT是你自己定义的参数,表示窗口的大小,其他就是windows自带的类型,具体可以使用CTRL+鼠标左键看源码。

之所以要使用这个函数,除了创造窗口之外,我们还需要函数返回的句柄hwnd,这个相当于唯一标识窗口,以后修改窗口时就需要它传参,因此我们把直接把函数InitInstance(HINSTANCE, int)去掉,然后把内容复制到主函数即可,贴代码。

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此处放置代码。

    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_MODSDEMO, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    hInst = hInstance; // 将实例句柄存储在全局变量中

    HWND hwnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, WIND_WIDTH, WIND_HEIGHT, nullptr, nullptr, hInstance, nullptr);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    if (!hwnd)
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MODSDEMO));
    MSG msg = { 0 };

    // 主消息循环:
    while (msg.message != WM_QUIT) {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}

2)、模板创建的MyRegisterClass的函数

开始我们就看到一个名为wcex的变量,这里的wcex并不标识唯一的窗口,标识符还是得靠我们上面提到的hwnd。
下面来介绍一些各个参数

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MODSDEMO));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_MODSDEMO);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

1.cbSize:表示窗口大小,使用sizeof即可;
2.style:窗口类型,自行查阅;
3.lpfnWndProc窗口过程函数,非常重要,举个小栗子,接受到的消息经过翻译是要传到这个函数来的,使用这个函数接受到消息才会引发相应的操作,比如我们的键盘和鼠标输入依靠的就是此函数,模板中应该也写出了,看不懂没关系,有一些我也看不懂,跟着我来
4.cbClsExtracbWndExtra额外参数,没什么用,设置为0;
5.hInstance:句柄,填主函数第一个参数即可;
6.hIcon:应用程序图标,你们的左上角的东西,你也可以使用如下代码使用自己喜欢的.ico图标

(HICON)LoadImage(NULL,L"Nitro.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);

7.hCursor:鼠标的形式,可以有很多取值;
8.hbrBackground:背景颜色,此处设置的为白色,所以我们窗口一片白,我们还可以使用如下函数让窗口灰或白

(HBRUSH)GetStockObject(GRAY_BRUSH);

9.lpszMenuNamelpszClassName上面以及解释,这里正好给他俩所在的参数赋值
10.hIconSm:与hIcon不同的是,它是加载窗口图像。
然后是返回的RegisterClassExW的窗口注册函数,这一步必不可少。

3)、GetMessage消息接受函数

这个也是重点,上面我们提到了窗口过程函数,根据接受的消息做出相应的操作,那么我们也还就需要特定的函数用来接受和翻译消息。
GetMessage函数的特点是,接受消息的时候才会动,同时接受消息,没有消息的时候他是不会动的,但是作为游戏来说,时时刻刻都在运行着,并且每时每刻都要准备接受消息,因此本函数不适合使用在游戏中。
我们使用另外一个消息接受函数PeekMessage,此函数每时每刻都在接受消息,没有消息就返回false;

BOOL PeekMessage(
	LPMSG IpMsg,		//接受消息的结构体
	HWND hWnd,			//检查消息的句柄,设置为0即使用已创建的句柄,你也可以使用上面的hwnd
	UINT wMSGfilterMin,
	UINT wMsgFilterMax,//min和max设置为0表示传来的消息照单全收
	UINT wRemoveMsg		//接受消息的形式,最好是处理消息后然后扔掉
);

因此我们这么使用它

    // 主消息循环:
    while (msg.message != WM_QUIT) {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

如果直接用while里面加PeekMessage,那么如果没收到消息返回false,这时候就会退出while循环导致主函数直接返回,窗口闪一下就会结束,因此我们只能while里面检测是否是WM_QUIT退出消息,然后使用if判断,这样就能一直把PeekMessage锁在循环里了。
其他代码就不需要动了

#include "framework.h"
#include "ModsDemo.h"
#define  WIND_WIDTH 800
#define  WIND_HEIGHT 680
#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
LRESULT CALLBACK	WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此处放置代码。

    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_MODSDEMO, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    hInst = hInstance; // 将实例句柄存储在全局变量中

    HWND hwnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, WIND_WIDTH, WIND_HEIGHT, nullptr, nullptr, hInstance, nullptr);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    if (!hwnd)
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MODSDEMO));
    MSG msg = { 0 };

    // 主消息循环:
    while (msg.message != WM_QUIT) {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc 	= WndProc;
    wcex.cbClsExtra 	= 0;
    wcex.cbWndExtra 	= 0;
    wcex.hInstance 		= hInstance;
    wcex.hIcon 			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MODSDEMO));
    wcex.hCursor 		= LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground 	= (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName 	= MAKEINTRESOURCEW(IDC_MODSDEMO);
    wcex.lpszClassName 	= szWindowClass;
    wcex.hIconSm 		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 分析菜单选择:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

在这里插入图片描述

四、End…

一个简单的窗口就做好了,不复杂,但是东西多,记住下面这几点

我文件名字是ModDemo,其中MAKEINTRESOURCE中的参数与你的文件名字有关,所以不要直接copy代码,比如我的函数就是MAKEINTRESOURCE(IDC_MODSDEMO)参数正是IDC_{大写的文件名}

用浅墨的规划来说:
窗口创建四部曲:

  1. 窗口设计 MyRegisterClass
  2. 窗口注册 MyRegisterClass中的RegisterClassExW
  3. 窗口正式创建 CreateWindowW
  4. 窗口显示和更新 ShowWindowUpdateWindow

如果有可能第二章就一起实现Game_InitGame_Paint

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 00:51:42  更:2022-09-04 00:52:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/14 0:15:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码