laishiba 发表于 2015-5-17 09:39:04

windows程序设计第六章Typer部分自己注释 和各位交流下

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        static DWORD   dwCharSet = DEFAULT_CHARSET;
        static int   cxChar, cyChar, cxClient, cyClient, cxBuffer, cyBuffer,
                xCaret, yCaret;
        static TCHAR * pBuffer = NULL;
        HDC            hdc;
        int            x, y, i;
        PAINTSTRUCT    ps;
        TEXTMETRIC   tm;

        // 从WM_INPUTLANGCHANGE消息开始一直往下直到WM_SIZE消息结束,都没有break或者return语句。
        // 这意味着即使程序收到的是WM_INPUTLANGCHANGE消息,它也会一直执行到WM_SIZE消息。
        switch (message)
        {
        case WM_INPUTLANGCHANGE:   // 当改变键盘布局的时候就会收到这个消息
                dwCharSet = wParam;    // dwCharSet里存储的是字符集ID --> DEFAULT_CHARSET。
                                       // 给该变量重新付值的唯一可能的原因就是键盘布局变了。而且我们可以看出该消息的wParam字段里有新的字符集ID。
                // fall through
       
        case WM_CREATE:
                hdc = GetDC(hwnd);
                SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL)); // 默认字符集 固定字宽

                GetTextMetrics(hdc, &tm);
                cxChar = tm.tmAveCharWidth;
                cyChar = tm.tmHeight;

                DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));// 系统默认的是宋体
                ReleaseDC(hwnd, hdc);
                // fall through               
        case WM_SIZE:
                // obtain window size in pixels

                if (message == WM_SIZE)
                {
                        cxClient = LOWORD(lParam);
                        cyClient = HIWORD(lParam);
                }
                // calculate window size in characters

                cxBuffer = max(1, cxClient / cxChar);   // cxBuffer 保存客户区中可显示字符的行数
                cyBuffer = max(1, cyClient / cyChar);   // cyBuffer 保存客户区中可显示字符的列数

                // allocate memory for buffer and clear it

                if (pBuffer != NULL)
                        free(pBuffer);

                pBuffer = (TCHAR *)malloc(cxBuffer * cyBuffer * sizeof(TCHAR)); //根据行数和列数创建 cxBuffer * cyBuffer 个动态字符数组
                                                // 当客户区尺寸改变或者改变了键盘布局的时候程序会释放该动态数组,然后重新分配数组
                for (y = 0; y < cyBuffer; y++)    // 客户区用空格填满。我们可以把空格改成其它的什么,比如: BUFFER(x, y) = 'A';                       
                        for (x = 0; x < cxBuffer; x++)
                                BUFFER(x, y) = ' ';

                // set caret to upper left corner

                xCaret = 0;   // xCaret yCaret是光标的位置
                yCaret = 0;

                if (hwnd == GetFocus())   // 函数GetFocus返回拥有输入焦点的窗口句柄
                        SetCaretPos(xCaret * cxChar, yCaret * cyChar); // 光标移到客户区左上角

                InvalidateRect(hwnd, NULL, TRUE);// 刷新整个客户区
                return 0;   
                // 当我们改变了键盘布局(WM_INPUTLANGCHANGE),或是创建窗口(WM_CREATE),或是改变窗口尺寸(WM_SIZE)的时候
                // 我们对窗口客户区所做的改动都会消失。窗口会变成刚开始时候的样子,也就是一大片空格。

        case WM_SETFOCUS:
                // create and show the caret

                CreateCaret(hwnd, NULL, cxChar, cyChar);       // 创建插入字符的高度和宽度
                SetCaretPos(xCaret * cxChar, yCaret * cyChar); // 设置插入字符的位置
                ShowCaret(hwnd);                               // 使插入字符可见
                return 0;

        case WM_KILLFOCUS:
                // hide and destroy the caret

                HideCaret(hwnd);
                DestroyCaret();
                return 0;

        case WM_KEYDOWN:
                switch (wParam)
                {
                case VK_HOME:
                        xCaret = 0;
                        break;

                case VK_END:
                        xCaret = cxBuffer - 1;
                        break;                       

                case VK_PRIOR:
                        yCaret = 0;
                        break;

                case VK_NEXT:
                        yCaret = cyBuffer - 1;
                        break;

                case VK_LEFT:
                        xCaret = max(xCaret - 1, 0);
                        break;

                case VK_RIGHT:
                        xCaret = min(xCaret + 1, cxBuffer - 1);
                        break;

                case VK_UP:
                        yCaret = max(yCaret - 1, 0);
                        break;

                case VK_DOWN:
                        yCaret = min(yCaret + 1, cyBuffer - 1);
                        break;

                case VK_DELETE:// 删除掉当前位置的字符,然后后继列左移一个单位,来填补空出来的位置。最后一列补一空格
                        for (x = xCaret; x < cxBuffer - 1; x++)
                                BUFFER(x, yCaret) = BUFFER(x + 1, yCaret);

                        BUFFER(cxBuffer - 1, yCaret) = ' ';

                        HideCaret(hwnd);
                        hdc = GetDC(hwnd);

                        SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));

                        TextOut(hdc, xCaret * cxChar, yCaret * cyChar, &BUFFER(xCaret, yCaret), cxBuffer - xCaret);

                        DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
                        ReleaseDC(hwnd, hdc);
                        ShowCaret(hwnd);
                        break;
                }
                SetCaretPos(xCaret * cxChar, yCaret * cyChar);   // 改变当前光标所在位置
                return 0;

        case WM_CHAR:
                for (i = 0; i < (int)LOWORD(lParam); i++)   // LOWORD (lParam)是按键的重复次数
                {
                        switch (wParam)
                        {
                        case '\b':                  // backspace
                                if (xCaret > 0)         // 先把插入符左移一个单位,然后就是 WM_KEYDOWS 的 VK_DELETE部分了
                                {
                                        xCaret--;
                                        SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1);
                                }
                                break;

                        case '\t':                  // tab 按下 tab 键后插入符可能的位置是:(i*8,0)
                                do
                                {
                                        SendMessage(hwnd, WM_CHAR, ' ', 1);// 执行WM_CHAR的default部分
                                } while (xCaret % 8 != 0);               // SendMessage()传递的是一个空格,
                                break;                     // 所以 yCaret 行 xCaret 列的内容变成了空格。然后用TextOut()把变化后的内容显示出来

                        case '\n':                  // line feed意思就是将光标位置往下挪一行,对应++yCaret
                                if (++yCaret == cyBuffer) // 但如果已经挪到最下面一行的话yCaret == cyBuffer,就挪到最上面一行
                                        yCaret = 0;
                                break;

                        case '\r':                  // carriage return               
                                xCaret = 0;               // 将光标挪到最左边

                                if (++yCaret == cyBuffer) // 同'\n'功能相同
                                        yCaret = 0;
                                break;

                        case '\x1B':                  // escape对应键盘Esc键,功能是将光标挪到最左上角,并将以前输入的字符全部擦除
                                for (y = 0; y < cyBuffer; y++)
                                        for (x = 0; x < cxBuffer; x++)
                                                BUFFER(x, y) = ' ';

                                xCaret = 0;
                                yCaret = 0;

                                InvalidateRect(hwnd, NULL, FALSE);
                                break;

                        default:                      // character codes
                                BUFFER(xCaret, yCaret) = (TCHAR)wParam;

                                HideCaret(hwnd);
                                hdc = GetDC(hwnd);

                                SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));

                                TextOut(hdc, xCaret * cxChar, yCaret * cyChar, &BUFFER(xCaret, yCaret), 1);

                                DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
                                ReleaseDC(hwnd, hdc);
                                ShowCaret(hwnd);

                                if (++xCaret == cxBuffer)      // 每改变一个字符位,插入符前进一位 如果移动到行的末尾(客户区的最右边)
                                {
                                        xCaret = 0;                // 将光标挪到行首

                                        if (++yCaret == cyBuffer)// 如果已经挪到最下面一行的话yCaret == cyBuffer,就挪到最上面一行(0,0)位置
                                                yCaret = 0;
                                }
                                break;
                        }
                }

                SetCaretPos(xCaret * cxChar, yCaret * cyChar);
                return 0;

        case WM_PAINT:
                hdc = BeginPaint(hwnd, &ps);

                SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));

                for (y = 0; y < cyBuffer; y++)
                        TextOut(hdc, 0, y * cyChar, &BUFFER(0, y), cxBuffer);

                DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
                EndPaint(hwnd, &ps);
                return 0;

        case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
}

laishiba 发表于 2015-5-17 10:42:34

BUFFER(xCaret, yCaret) = (TCHAR)wParam; 这句不大明白 哪位给解答下

小人 发表于 2015-5-17 11:54:37

BUFFER(xCaret, yCaret) = (TCHAR)wParam   
就是把 后面的wParam类型转换成TCHAR 类型赋值给前面 BUFFER,
至于BUFFER(xCaret, yCaret)   是什么 我没看懂{:9_240:}

零度C 发表于 2015-5-17 14:25:40

#define BUFFER(x,y) *(pBuffer + y * cxBuffer + x)

当你看到程序里有这么一句就明白是什么意思了。

laishiba 发表于 2015-5-17 14:50:13

零度C 发表于 2015-5-17 14:25
#define BUFFER(x,y) *(pBuffer + y * cxBuffer + x)

当你看到程序里有这么一句就明白是什么意思了。


灰常感谢

laishiba 发表于 2015-5-17 14:52:53

小人 发表于 2015-5-17 11:54
BUFFER(xCaret, yCaret) = (TCHAR)wParam   
就是把 后面的wParam类型转换成TCHAR 类型赋值给前面 BUF ...

谢谢大神

citian3094 发表于 2015-5-22 16:29:00

谢谢分享!

a306079758 发表于 2015-6-25 23:09:46

很長!!漫漫看

tiandiweicheng0 发表于 2015-7-6 16:17:17

谢谢分享,学习中

tiandiweicheng1 发表于 2015-7-7 17:11:31

楼主费心了。。。。学习

864195847@aa.co 发表于 2015-7-25 20:31:43

我来看看
页: [1]
查看完整版本: windows程序设计第六章Typer部分自己注释 和各位交流下