Windows API

本文为了从C语言的面向过程说明窗口创建、操作的过程。
1.窗口创建过程
每种窗口是一种类,例如form类型的窗口类、文本窗口类等等,不同的类包含的变量和消息处理方法不一样。要创建一个窗口,首先需要把类名和消息处理函数注册到WINDOWS操作系统中,然后使用已经注册的类名来创建窗口。
第一步,注册窗口类,实际上就是对结构体WNDCLASSEX初始化,然后用该结构体作为ATOM RegisterClassEx(&WNDCLASSEX)的参数注册窗口类,是将窗口类的数据放在User32.dll维护的一个原子表中,自定义注册窗口函数:

// 注册应用程序窗口类
ATOM _RegisterClass()
{
    int i = 0;
    WNDCLASSEX wc;
    ::ZeroMemory(&wc, sizeof(wc));                 // 作为一步清空,是为了让未赋值的字段的默认值为(或NULL)

    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW;  // 指定当窗口横向和纵向的尺寸发生变化时都会重绘窗口
    wc.hInstance = _HInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);  // 指定主窗口背景为“工作区域”系统颜色
    wc.lpszClassName = _WindowClass;          // 此为要注册的类名,创建窗口时要以此类名为标识符
    wc.lpfnWndProc = _TextBoxWndProc;                      // 此为处理窗口消息的函数

    return ::RegisterClassEx(&wc);                 // 调用API函数注册窗口类
}

第二部,创建窗口对象,用CreateWindow创建窗口对象。函数原型为:
HWND WINAPI CreateWindow(

In_opt LPCTSTR lpClassName, // 窗口类名称

In_opt LPCTSTR lpWindowName, // 窗口标题

In DWORD dwStyle, // 窗口风格,或称窗口格式

In int x, // 初始 x 坐标

In int y, // 初始 y 坐标

In int nWidth, // 初始 x 方向尺寸

In int nHeight, // 初始 y 方向尺寸

In_opt HWND hWndParent, // 父窗口句柄

In_opt HMENU hMenu, // 窗口菜单句柄

In_opt HINSTANCE hInstance, // 程序实例句柄

In_opt LPVOID lpParam // 创建参数

);
CreateWindow详细参数说明可以参考:
http://www.tuicool.com/articles/6RvqIrv
然后用系统的API函数显示窗口和更新窗口:
::ShowWindow;
::UpdateWindow;

HWND _CreateWindow(int nCmdShow)
{
    HWND hWnd = ::CreateWindow(_WindowClass, _Title, WS_POPUP,
        500, 500, 200, 20, NULL, NULL, _HInstance, NULL);

    if (hWnd == NULL)
        return NULL;

    ::ShowWindow(hWnd, nCmdShow);
    ::UpdateWindow(hWnd);

    return hWnd;
}

2.窗口操作过程
WINDOWS操作系统通过消息与应用程序进行交互,每个窗口都有自己的消息处理函数,该函数在窗口注册时就和窗口绑定了,既窗口对一系列的事件,如鼠标事件、键盘事件等等,然后调用绑定的消息处理函数处理自己的用户操作,然后进行界面重绘。

// 创建文本框
HWND _CreateTextBoxWindow(HWND hParentWnd)
{
    // 之下代码是为了让文本框显示在父窗口中央,而计算位置
    RECT parentWndRect;
    ::GetClientRect(hParentWnd, &parentWndRect);  // 获取父窗口客户区的位置
    int left = (parentWndRect.right - TEXTBOX_WIDTH) / 2, top = (parentWndRect.bottom - TEXTBOX_HEIGHT) / 2;

    // 创建文本框
    HWND hWnd = ::CreateWindow(_TextBoxClass, NULL, WS_CHILDWINDOW | WS_VISIBLE,
        left, top, TEXTBOX_WIDTH, TEXTBOX_HEIGHT,
        hParentWnd, NULL, _HInstance, NULL);

    return hWnd;
}

// 文本框消息的处理过程
LRESULT CALLBACK _TextBoxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT: {  // 绘制这里之所以加一对大括号,是为了让之下定义的变量局部化

                       static PAINTSTRUCT ps;
                       static RECT rect;
                       HDC hDC = ::BeginPaint(hWnd, &ps);  // 开始绘制操作

                       ::GetClientRect(hWnd, &rect);        // 获取客户区的尺寸
                       ::DrawEdge(hDC, &rect, EDGE_SUNKEN, BF_RECT);  // 绘制边框,EDGE_SUNKEN表示绘制样式为内嵌样式,BF_RECT表示绘制矩形边框
                       _DrawText(hDC);                      // 绘制文本
                       ::EndPaint(hWnd, &ps);               // 结束绘制操作

    } break;

    case WM_SETFOCUS: {    // 获得焦点
                          ::CreateCaret(hWnd, (HBITMAP)NULL, 1, TEXTBOX_HEIGHT - 5);     // 创建光标
                          _SetCaretPos(hWnd);                            // 设置光标位置
                          ::ShowCaret(hWnd);                   // 显示光标
    } break;

    case WM_KILLFOCUS: // 失去焦点
        ::HideCaret(hWnd);                   // 隐藏光标
        ::DestroyCaret();                    // 销毁光标
        break;

    case WM_SETCURSOR: {  // 设置光标形状
                           static HCURSOR hCursor = ::LoadCursor(NULL, IDC_IBEAM);
                           ::SetCursor(hCursor);
    } break;

    case WM_CHAR: {    // 字符消息
                      TCHAR code = (TCHAR)wParam;
                      int len = ::_tcslen(_String);
                      if (code < (TCHAR)' ' || len >= TEXTBOX_MAXLENGTH)
                          return 0;

                      ::MoveMemory(_String + _StringPosition + 1, _String + _StringPosition, (len - _StringPosition + 1) * sizeof(TCHAR));
                      _String[_StringPosition++] = code;

                      _UpdateWindow(hWnd);
                      _SetCaretPos(hWnd);

    } break;

    case WM_KEYDOWN: {  // 键按下消息
                         TCHAR code = (TCHAR)wParam;

                         switch (code)
                         {
                         case VK_LEFT: // 左光标键
                             if (_StringPosition > 0)
                                 _StringPosition--;
                             break;

                         case VK_RIGHT:     // 右光标键
                             if (_StringPosition < (int)::_tcslen(_String))
                                 _StringPosition++;
                             break;

                         case VK_HOME: // HOME 键
                             _StringPosition = 0;
                             break;

                         case VK_END:  // END 键
                             _StringPosition = ::_tcslen(_String);
                             break;

                         case VK_BACK: // 退格键
                             if (_StringPosition > 0)
                             {
                                 ::MoveMemory(_String + _StringPosition - 1, _String + _StringPosition, (::_tcslen(_String) - _StringPosition + 1) * sizeof(TCHAR));
                                 _StringPosition--;
                                 _UpdateWindow(hWnd);
                             }
                             break;

                         case VK_DELETE: {  // 删除键
                                             int len = ::_tcslen(_String);
                                             if (_StringPosition < len)
                                             {
                                                 ::MoveMemory(_String + _StringPosition, _String + _StringPosition + 1, (::_tcslen(_String) - _StringPosition + 1) * sizeof(TCHAR));
                                                 _UpdateWindow(hWnd);
                                             }

                         } break;

                         }

                         _SetCaretPos(hWnd);

    } break;

    case WM_LBUTTONDOWN: {  // 鼠标单击,设置光标位置
                             int x = LOWORD(lParam);
                             HDC hDc = ::GetDC(hWnd);

                             int strLen = ::_tcslen(_String), strPos = 0;
                             SIZE size;

                             for (strPos = 0; strPos<strLen; strPos++)
                             {
                                 ::GetTextExtentPoint(hDc, _String, strPos, &size);

                                 if (size.cx + 4 >= x)
                                     break;
                             }

                             _StringPosition = strPos;
                             ::GetTextExtentPoint(hDc, _String, strPos, &size);
                             ::SetCaretPos(size.cx + 4, 3);

                             ::ReleaseDC(hWnd, hDc);

    } break;

    default:
        return ::DefWindowProc(hWnd, message, wParam, lParam);
    }

    return (LRESULT)0;
}

然后再定义更新窗口、绘制文本、设置光标位置的函数:

// 更新窗口
void _UpdateWindow(HWND hWnd)
{
    RECT rect;
    ::GetClientRect(hWnd, &rect);
    ::InvalidateRect(hWnd, &rect, TRUE);
    ::UpdateWindow(hWnd);
}

// 绘制文本
void _DrawText(HDC hDC)
{
    int len = ::_tcslen(_String);
    ::TextOut(hDC, 4, 2, _String, len);
}

// 设置光标位置
void _SetCaretPos(HWND hWnd)
{
    HDC hDC = ::GetDC(hWnd);

    SIZE size;
    ::GetTextExtentPoint(hDC, _String, _StringPosition, &size);
    ::SetCaretPos(4 + size.cx, 3);

    ::ReleaseDC(hWnd, hDC);

}

这样就可以生成一个浮现在桌面的文本框,直接输入字符串了。
浮在桌面的文本框

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值