尝试用 c++ 写一个神经网络(1)

176 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

目的

为什么在写神经网络前我们要创建一个窗口,答案是用 c++ 写神经网络神经网络的可视化实现

创建一个 Windows 桌面应用程序

anet.PNG

创建主程序

创建一个 Main.cpp 文件

引入头文件

#include <Windows.h>

首先我们把入口函数保存过来,入口函数和之前 c++ 语言和 c 语言入口函数有所不同,这里并不是 main 函数,而是 mWinMain 注意在 c++ 中是区分大小写的,这就是入口文件,主函数需要只用这个名称,保证应用程序可以将你应用正确调用

#include <Windows.h>

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    return 1;
}
  • HINSTANCE 类型
  • LPWSTR 类型

我们创建文件在IDE 默认生成文件看多大量没有见过数据类型,其实这些大家不用担心这些都是一些基本类型别名,使用 typedef 对一些基本类型定义别名, 例如 typedef int INT ,这样做好处是使用 deftype 起别名可以用于简化类型,赋予类型的可解释性,这些还都是表面,便于以后系统即使更改某一个类型不会导致你 code 出现 bug

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,//当前,每一个进程代表一个实例
    _In_opt_ HINSTANCE hPrevInstance,//前一个应用程序实例句柄
    _In_ wchar_t*    lpCmdLine,//命令行参数,默认时候没有传入命令行参数
    _In_ int       nCmdShow)
{

    MessageBox(NULL,L"hello world win32",L"anet ",MB_OK);

    return 0;
}

这里创建了 MessageBox 用于,一个系统提供的弹框窗口,不需要注册,因为系统将 MessageBox 注册好了,其他这样窗口类还有 BUTTON 和 EDIT

  • NULL 是父窗口句柄
typedef HINSTANCE HMODULE 

接下来要做的事

  • 注册窗口类
  • 创建窗口
  • 显示窗口
  • 更新窗口
  • 消息循环

注册窗口

什么是窗口类

  • 窗口类包含了窗口的各种参数信息的数据结构
  • 每个窗口都具有窗口类,窗口类可以看做创建窗口的模板
  • 每个窗口类都具有一个名字,在创建和使用窗口类前必须将其注册到系统

窗口类的分类

  • 系统窗口类
  • 应用程序全局窗口类(所有模块化可视)
  • 应用程序局部窗口类(

定义窗口类的过程就是窗口注册过程

定义窗口结构体

typedef struct
{
    HWND    windowHandle; // 窗口句柄
    BOOL      Running;//状态
} typeWindow;

定义创建窗口的方法

long typeWindowCreate(typeWindow* parent, HINSTANCE hInstance, WNDPROC windowProc);
long typeWindowCreate(typeWindow* parent, HINSTANCE hInstance, WNDPROC windowProc)
{
    // EX 表示扩展的意思
    WNDCLASSEXW wcex;

    if (parent == 0)
        return 0;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;//窗口特征,并不是窗口外观特征,水平重画和垂直重绘制
    wcex.lpfnWndProc = windowProc;//设置用哪个 WindowProc 来处处理消息
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;//当前应用实例句柄
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;//菜单 ID
    wcex.lpszClassName = windowClass;//向系统注册的类名
    wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

    //注册
    if (!RegisterClassExW(&wcex))
    {
        return 0;
    }

    HWND hwnd = CreateWindowW(
        windowClass,//类名称,和刚刚注册一致
        windowTitle,//标题名称
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, //窗口外观样式
        CW_USEDEFAULT,//窗口相对于父级的 x 坐标
        CW_USEDEFAULT,//窗口相对于父级的 y 坐标
        CW_USEDEFAULT,//窗口宽度
        CW_USEDEFAULT, //窗口高度
        NULL, //父窗口
        NULL, //菜单
        hInstance, //应用程序实例
        NULL);//附加数据

    if (!hwnd)
    {
        return 0;
    }

    parent->windowHandle = hwnd;
    parent->Running = 1;

    return 1;
}
long typeWindowGetEvent(typeWindow* parent)
{
    //消息内容
    MSG msg;

    if (parent == 0)
        return 0;

    if (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return parent->Running;
}

销毁窗口

long typeWindowDestroy(typeWindow* parent)
{
    if (parent == 0)
        return 0;

    DestroyWindow(parent->windowHandle);

    parent->windowHandle = 0;
    parent->Running = 0;

    return 1;
}

完整代码

#ifndef TYPEWINDOW_H
#define TYPEWINDOW_H
#include <windows.h>



// 定义一个数据结构
typedef struct
{
    HWND    windowHandle; // 窗口句柄
    BOOL      Running;//状态
} typeWindow;

// 创建窗口
long typeWindowCreate(typeWindow* parent, HINSTANCE hInstance, WNDPROC windowProc);
//从消息队列获取消息
long typeWindowGetEvent(typeWindow* parent);
long typeWindowPeekEvent(typeWindow* parent);
//销毁窗口
long typeWindowDestroy(typeWindow* parent);

//
const WCHAR windowClass[] = L"windowClass";
const WCHAR windowTitle[] = L"windowTitle";

// 创建和显示主程序窗口
long typeWindowCreate(typeWindow* parent, HINSTANCE hInstance, WNDPROC windowProc)
{
    // EX 表示扩展的意思
    WNDCLASSEXW wcex;

    if (parent == 0)
        return 0;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;//窗口特征,并不是窗口外观特征,水平重画和垂直重绘制
    wcex.lpfnWndProc = windowProc;//设置用哪个 WindowProc 来处处理消息
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;//当前应用实例句柄
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;//菜单 ID
    wcex.lpszClassName = windowClass;//向系统注册的类名
    wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

    //注册
    if (!RegisterClassExW(&wcex))
    {
        return 0;
    }

    HWND hwnd = CreateWindowW(
        windowClass,//类名称,和刚刚注册一致
        windowTitle,//标题名称
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, //窗口外观样式
        CW_USEDEFAULT,//窗口相对于父级的 x 坐标
        CW_USEDEFAULT,//窗口相对于父级的 y 坐标
        CW_USEDEFAULT,//窗口宽度
        CW_USEDEFAULT, //窗口高度
        NULL, //父窗口
        NULL, //菜单
        hInstance, //应用程序实例
        NULL);//附加数据

    if (!hwnd)
    {
        return 0;
    }

    parent->windowHandle = hwnd;
    parent->Running = 1;

    return 1;
}

/**
消息循环 消息队列
*/
long typeWindowGetEvent(typeWindow* parent)
{
    MSG msg;

    if (parent == 0)
        return 0;
    //获取消息,直到条件不成立,循环跳出
    if (GetMessage(&msg, NULL, 0, 0))
    {
        //用于将转换按键信息
        TranslateMessage(&msg);
        //将消息分发给 WindowProc 来处理
        DispatchMessage(&msg);
    }

    return parent->Running;
}


long typeWindowPeekEvent(typeWindow* parent)
{
    MSG msg;

    if (parent == 0)
        return 0;

    if (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return parent->Running;
}

long typeWindowDestroy(typeWindow* parent)
{
    if (parent == 0)
        return 0;

    DestroyWindow(parent->windowHandle);

    parent->windowHandle = 0;
    parent->Running = 0;

    return 1;
}
#endif // !TYPEWINDOW_H

主函数实现部分

LRESULT CALLBACK windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


// 声明窗口
typeWindow window;
typeBitmap bitmap;




// 应用程序运行入口函数
// APIENTRY 是 _stdcall , 函数调用的协议,_stdcall 调用约定用于 Win32 API 函数,
// wWinMain 是由系统调用的
int APIENTRY wWinMain(
    _In_ HINSTANCE hInstance, // 应用程序实列的句柄
    _In_opt_ HINSTANCE hPrevInstance,//前一个实例
    _In_ LPWSTR    lpCmdLine,//命令行参数 LP 表示指针
    _In_ int       nCmdShow) //主窗口显示方式
{

    //创建窗口
    typeWindowCreate(&window, hInstance, windowProc);
    //创建 bitmap
    typeBitmapCreate(&bitmap, 100, 100);

    while (typeWindowGetEvent(&window)) {
        //
       
    }
    //退出销毁 bitmap
    typeBitmapDestroy(&bitmap);
    //返回值 0 表示应用程序正常退出
    return 1;
}
// wParam 和 lParam 通常消息出参数,其中 
LRESULT CALLBACK windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
     // 绘制 bitmap
    case WM_PAINT:
    {
        // PAINSTRUCT 结构体包括用于在客户端绘制的信息
        PAINTSTRUCT ps;
        // 
        HDC hdc = BeginPaint(hWnd, &ps);

        typeBitmapShow(&bitmap, &window, 10, 10);

        EndPaint(hWnd, &ps);
        return 0;
    }
    case WM_DESTROY:
        typeWindowDestroy(&window);
        return 0;
        
    }
    // 不做任何处理,又把控制权交给操作系统默认处理
    return DefWindowProc(hWnd, message, wParam, lParam);
}