anand
anand

Reputation: 11309

How to create custom shape control in win32 C++

I would like to create a edit box with rounded edges.I cannt use standard edit box control since it would draw rectangular edit box.

Any suggestions or pointers how to do that?

Upvotes: 0

Views: 2443

Answers (1)

Skizz
Skizz

Reputation: 71070

You have a couple of options:-

  1. Create a parent control and have a child borderless text edit control inside it
  2. Sub-class a text edit control and overload the NC_PAINT to draw the border

UPDATE

After messing around with a sample program, it gradually dawned on me that sub-classing edit controls doesn't really work and checking on-line confirms this (thankyou MS for being so consistent!).

So that just leaves option 1 and option 3 (just thought of it):

  1. Create your own edit control

Here's an example of method 1:

#include <windows.h>

LRESULT __stdcall EditboxProc (HWND window, unsigned message, WPARAM w_param, LPARAM l_param)
{
  bool
    use_default = true;

  LRESULT
    result = 0;

  switch (message)
  {
  case WM_CREATE:
    {
      RECT
        client;

      GetClientRect (window, &client);

      HWND
        edit = CreateWindowEx (0,
                               TEXT ("Edit"),
                               0,
                               WS_VISIBLE | WS_CHILD,
                               10,
                               10,
                               client.right - 20,
                               client.bottom - 20,
                               window,
                               0,
                               GetModuleHandle (0),
                               0);

      SetWindowLongPtr (window, GWLP_USERDATA, static_cast <LONG> (reinterpret_cast <LONG_PTR> (edit)));
    }
    break;

  case WM_SIZE:
    {
      RECT
        client;

      GetClientRect (window, &client);
      SetWindowPos (reinterpret_cast <HWND> (static_cast <LONG_PTR> (GetWindowLongPtr (window, GWLP_USERDATA))), 0, 10, 10, client.right - 20, client.bottom - 20, SWP_NOZORDER | SWP_NOOWNERZORDER);

      use_default = false;
    }
    break;
  }

  return use_default ? DefWindowProc (window, message, w_param, l_param) : result;
}

LRESULT __stdcall WindowProc (HWND window, unsigned message, WPARAM w_param, LPARAM l_param)
{
  bool
    use_default = true;

  LRESULT
    result = 0;

  switch (message)
  {
  case WM_CREATE:
    {
      RECT
        client;

      GetClientRect (window, &client);

      CreateWindowEx (0,
                      TEXT ("EditboxClass"),
                      0,
                      WS_VISIBLE | WS_CHILD,
                      client.right / 4,
                      client.bottom / 2 - 20,
                      client.right / 2,
                      40,
                      window,
                      0,
                      GetModuleHandle (0),
                      0);
    }
    break;
  }

  return use_default ? DefWindowProc (window, message, w_param, l_param) : result;
}

int __stdcall WinMain (HINSTANCE instance, HINSTANCE prev_instance, LPSTR command_line, int show)
{
  WNDCLASSEX
    window_class = 
    {
      sizeof window_class,
      0,
      WindowProc,
      0,
      0,
      instance,
      0,
      0,
      reinterpret_cast <HBRUSH> (static_cast <int> (COLOR_WINDOW) + 1),
      0,
      TEXT ("WindowClass"),
      0
    },
    editbox_class = 
    {
      sizeof editbox_class,
      0,
      EditboxProc,
      0,
      0,
      instance,
      0,
      0,
      reinterpret_cast <HBRUSH> (static_cast <int> (COLOR_BTNFACE) + 1),
      0,
      TEXT ("EditboxClass"),
      0
    }; 

  if (RegisterClassEx (&window_class) && RegisterClassEx (&editbox_class))
  {
    HWND
      window = CreateWindowEx (0,
                               TEXT ("WindowClass"),
                               TEXT ("Demo"),
                               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                               CW_USEDEFAULT,
                               CW_USEDEFAULT,
                               CW_USEDEFAULT,
                               CW_USEDEFAULT,
                               0,
                               0,
                               instance,
                               0);

    if (window)
    {
      MSG
        message;

      bool
        quit = false;

      while (!quit)
      {
        switch (GetMessage (&message, window, 0, 0))
        {
        case -1:
        case 0:
          quit = true;
          break;

        default:
          TranslateMessage (&message);
          DispatchMessage (&message);
          break;
        }
      }
    }
  }

  return 0;
}

It's a bit bare-bones but should give you some idea about how to do what you want. It won't work with dialogs defined using resource scripts (I think, it's been a while since I hand coded a resource) as it uses a custom control for the parent of the edit box (the thing that renders the frame). You will probably want to add handlers to EditboxProc to handle pass message to and from the edit control (like WM_NOTIFY, WM_COMMAND, WM_GETTEXT, etc) and to render the rounded corners (WM_PAINT, WM_ERASEBKGND).

Upvotes: 3

Related Questions