Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom edit control win32

Tags:

c++

edit

winapi

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

like image 860
devjeetroy Avatar asked Nov 10 '11 01:11

devjeetroy


People also ask

How do I get text from edit control in win32?

To retrieve all text from an edit control, first use the GetWindowTextLength function or the WM_GETTEXTLENGTH message to determine the size of buffer needed to contain the text. Next, retrieve the text by using the GetWindowText function, the GetDlgItemText function, or the WM_GETTEXT message.

How do I change text in edit control?

You can set the text of an Edit control (wrapped by the CEdit class in MFC) by calling the SetWindowText method, which it inherits from the CWnd base class. So then all you need to do is respond to a click event on your button control.

Is a single line edit control?

There are two line styles for edit controls. The default is a single-line edit control. An application can also create a multiline edit control by using the ES_MULTILINE style.


1 Answers

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); 
    }
}
like image 89
vadim_hr Avatar answered Sep 22 '22 23:09

vadim_hr