Custom edit control win32

守給你的承諾、 提交于 2020-03-18 06:47:08

问题


I finally managed to get my syntax highlighting done using richedit and iczelion's tutorials. Now that i find it, it certainly is not fast enough. I am thinking of taking this one step ahead: a custom edit control. But i do not know how to go about it. Could you guys tell me how to go about it? Give me some info to start on? Maybe even some tutorial or suggest some book?

Now I'm not asking for you guys to spell it out for me, just something to start on. I will be using C++/ASM/Win32 API for this. I'm sure many of you have already made custom edit controls befores, so may be you could even share your experience.

Thanks,

Devjeet


回答1:


You are going to want to look into Owner Drawn Controls. MSDN has an example of doing this with a list box. You can adapt this to an Edit control.




回答2:


I spent one day on coding my own custom edit control - it's working well, so I would like to share my experience here, maybe for someone this code might be helpful... Because custom draw an common edit control is impossible (see here), you must write your own edit control. The general steps are:

// 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);

How to display keyboard input is described here. My window procedure looks as follows

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);
}

Delete current selected text (from select to cursor).

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;
    }
}

Draw window on window DC

void InputWndRedraw(HWND hWnd)
{
    HDC hdc;

    HideCaret(hWnd); 

    hdc = GetDC(hWnd); 
    InputWndDraw(hWnd, hdc);
    ReleaseDC(hWnd, hdc); 

    ShowCaret(hWnd); 

}

Draw input buffer (buf*) on device context. Syntax highlighting and other formatting features goes here...

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); 
    }
}


来源:https://stackoverflow.com/questions/8074047/custom-edit-control-win32

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!