自定义编辑控件win32

Custom edit control win32

本文关键字:win32 控件 编辑 自定义      更新时间:2023-10-16

我终于使用richhead和iczelion的教程完成了语法高亮显示。现在我找到了,它肯定还不够快。我正在考虑采取这一步:自定义编辑控件。但我不知道该怎么做。你们能告诉我怎么做吗?给我点信息开始吧?甚至是一些教程或推荐一些书?

现在我不是要求你们为我解释清楚,只是一些开始。我将使用c++/ASM/Win32 API。我相信你们中的许多人之前已经做过自定义编辑控件,所以也许你甚至可以分享你的经验。

谢谢,

Devjeet

我花了一天的时间来编写我自己的自定义编辑控件-它工作得很好,所以我想在这里分享我的经验,也许对某些人来说这段代码可能会有所帮助…因为自定义绘制一个通用的编辑控件是不可能的(见这里),您必须编写自己的编辑控件。一般步骤如下:

// global vars
int select; // current selection position
int cursor; // current cursor position
HWND parent; // parent window
wchar_t buf[MAXINPUTBUF]; // edit buffer
WNDPROC oldproc; // old window procedure
// create custom control window
hWnd = CreateWindowW(L"static", NULL, WS_CHILD | WS_TABSTOP | SS_LEFT | SS_NOTIFY, 0, 0, 0, 0, parent, NULL, (HINSTANCE)GetWindowLongPtr(parent, GWL_HINSTANCE), NULL);
// todo: use SetProp() to store all global vars
oldproc = (WNDPROC)SetWindowLongPtrW(hWnd, GWL_WNDPROC, (LONG_PTR)InputWndProc);
SetWindowPos(hWnd, HWND_TOP, x, y, cx, cy, 0);

如何显示键盘输入在这里描述。我的窗口程序如下所示

LRESULT CALLBACK InputWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_LBUTTONDOWN:
        //SetFocus(hWnd);
        PostMessageW(GetParent(hWnd), WM_NEXTDLGCTL, (WPARAM)hWnd, TRUE);
        break;
    case WM_KILLFOCUS: 
        HideCaret(hWnd);
        DestroyCaret();
        break; 
    case WM_SETFOCUS:
        {
            RECT r;
            GetClientRect(hWnd, &r);
            // Create a solid black caret. 
            CreateCaret(hWnd, (HBITMAP) NULL, 2, r.bottom-r.top);
            ShowCaret(hWnd);
            InputWndRedraw(hWnd);
        }
        return FALSE;
    case WM_GETDLGCODE:
        return DLGC_WANTALLKEYS | DLGC_WANTARROWS;
    case WM_KEYDOWN:
    {
        switch (wParam)
        {
        case 'V':
            if (0x8000 & GetKeyState(VK_CONTROL))
            {
                HANDLE h;
                wchar_t *cb;
                int len,slen;
                InputWndDelete(hWnd);
                OpenClipboard(NULL);
                h = GetClipboardData(CF_UNICODETEXT);
                cb = (wchar_t*)GlobalLock(h);
                if (cb)
                {
                    memcpy(buf+(cursor+len)*sizeof(wchar_t), buf+cursor*sizeof(wchar_t), (slen-cursor)*sizeof(wchar_t));
                    memcpy(buf+cursor*sizeof(wchar_t), cb, len*sizeof(wchar_t));
                }
                GlobalUnlock(h);
                CloseClipboard();
                InputWndRedraw(hWnd);
            }
            break;
        case VK_RIGHT:
                if (cursor-1 >= MAXINPUTBUF || cursor >= (int)wcslen(buf))
                    break;
                cursor++;
                if (!(GetKeyState(VK_SHIFT) & 0x8000))
                    select = cursor;
                InputWndRedraw(hWnd);
                break;
            case VK_TAB:
                PostMessageW(GetParent(hWnd), WM_NEXTDLGCTL, GetKeyState(VK_SHIFT) & 0x8000, FALSE);
                break;
            case VK_LEFT:
                if (cursor <= 0)
                    break;
                cursor--;
                if (!(GetKeyState(VK_SHIFT) & 0x8000))
                    select = cursor;
                InputWndRedraw(hWnd);
                break;
            case VK_HOME:
                cursor = 0;
                if (!(GetKeyState(VK_SHIFT) & 0x8000))
                    select = cursor;
                InputWndRedraw(hWnd);
                break;
            case VK_END:
                cursor = wcslen(buf);
                if (!(GetKeyState(VK_SHIFT) & 0x8000))
                    select = cursor;
                InputWndRedraw(hWnd);
                break;
            case VK_DELETE:
                if (cursor >= (int)wcslen(buf))
                {
                    InputWndDelete(hWnd);
                    InputWndRedraw(hWnd);
                    break;
                }
                if (select == cursor)
                    select ++;
                InputWndDelete(hWnd);
                InputWndRedraw(hWnd);
            break;
            case VK_BACK:
                if (cursor <= 0)
                {
                    InputWndDelete(hWnd);
                    InputWndRedraw(hWnd);
                    break;
                }

                if (select == cursor)
                    cursor --;

                InputWndDelete(hWnd);
                InputWndRedraw(hWnd);
            }
        }
        break;
    case WM_CHAR: 
        if (wParam < VK_SPACE)
        break;

        InputWndDelete(hWnd);
        if (wcslen(buf)+1 < MAXINPUTBUF)
        {
            wmemmove(buf+(cursor+1)*sizeof(wchar_t), buf+cursor*sizeof(wchar_t), wcslen(s->buf)-cursor);
            buf[cursor] = wParam;
            cursor++;
            select = cursor;
        }
        InputWndRedraw(hWnd);
        break;
    case WM_ERASEBKGND:
        // no flickering
        return TRUE;
    case WM_PAINT:
        {
            HDC dc;
            PAINTSTRUCT paint;
            dc = BeginPaint(hWnd, &paint);
            InputWndDraw(hWnd, dc);
            EndPaint(hWnd, &paint);
        }
        return TRUE;
    }
    return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam);
}

删除当前选定的文本(从选择光标)。

void InputWndDelete(HWND hWnd)
{
    int len;
    len = wcslen(buf);
    if (select > cursor)
    {
        memcpy(buf+cursor*sizeof(wchar_t), buf+select*sizeof(wchar_t), (len - select)*sizeof(wchar_t));
        ZeroMemory(buf+(len-select+cursor)*sizeof(wchar_t), (MAXINPUTBUF-len+select-cursor)*sizeof(wchar_t));
        select = cursor;
    }
    else if (select < cursor)
    {
        memcpy(buf+select*sizeof(wchar_t), buf+cursor*sizeof(wchar_t), (len - cursor)*sizeof(wchar_t));
        ZeroMemory(buf+(len-cursor+select)*sizeof(wchar_t), (MAXINPUTBUF-len+cursor-select)*sizeof(wchar_t));
        cursor = select;
    }
    else
    {
        select = cursor;
    }
}

在窗口DC上绘制窗口

void InputWndRedraw(HWND hWnd)
{
    HDC hdc;
    HideCaret(hWnd); 
    hdc = GetDC(hWnd); 
    InputWndDraw(hWnd, hdc);
    ReleaseDC(hWnd, hdc); 
    ShowCaret(hWnd); 
}

在设备上下文中绘制输入缓冲区(buf*)。语法高亮显示和其他格式化功能在这里…

void InputWndDraw(HWND hWnd, HDC hdc)
{
    RECT r,cr;
    GetClientRect(hWnd, &cr);
    // draw selected rectangle FillRect()...
    CopyRect(&r,&cr);
    DrawTextW(hdc, buf, -1, &r, DT_LEFT | DT_TOP);

    if (cursor)
        DrawTextW(hdc, buf, cursor, &r, DT_LEFT | DT_TOP | DT_CALCRECT);
    else
        r.right = cr.left;
    if (GetFocus() == hWnd)
    {
        if (r.right > cr.right)
            SetCaretPos(cr.right, cr.top); 
        else
            SetCaretPos(r.right, cr.top); 
    }
}