You know what is custom window,the window that looks different. In this article we will create fixed size window having only minimize & close options.
Download the source code for both Visual Studio & MinGW and also demo.
Here's the article to customize windows forms in C#:
But we are talking about customize window in win32 using C/C++. Before you go to start to customize window,you must have some basics of win32 programming.
Following articles covers the basics of win32 programming.
Now lets move to customize the window.
First step you need to do is that you must set Window Style to WS_POPUP or WS_POPUPWINDOW.
WS_POPUP or WS_POPUPWINDOW styles set your window borderless with no any controls.
Now go to the WndProc() function.
In WM_CREATE message, you need to add Minimize & Close buttons at the top layered of the window at top-right location.
Buttons can be created using CreateWindow() statement by passing default text as "button"
I am using minimize_button & close_button HWND variables.
Syntax:
HWND button = CreateWindow(TEXT("button"), button-text,
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
x, y, width, height, HWND parent, action ID,HISTANCE, NULL);
Description
- CreateWindow() : this function create a button by passing "button" text to it.
- button-text : It is the text display on the button.
- W_CHILD : By setting this property the created button is added to the currently created window.
- WS_SVISIBLE : By setting this property the created button will be visible.
- BS_DEFPUSHBUTTON : This is style of button.there are many styles of buttons like:
BS_PUSHBUTTON
BS_DEFPUSHBUTTON
BS_FLAT
BS_CHECKBOX
BS_AUTOCHECKBOX
BS_RADIOBUTTON
BS_3STATE
BS_AUTO3STATE
BS_GROUPBOX
BS_AUTORADIOBUTTON
BS_OWNERDRAW
- x : Button location X.
- y : Button location Y.
- width & height.
See following complete code.
Download the source code for both Visual Studio & MinGW and also demo.
Creating & Adding buttons to window by setting button style to BS_OWNERDRAW :
- case WM_CREATE :
-
- minimize_button = CreateWindow(TEXT("button"), TEXT(""),
- WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
- 538, 0, 30, 30, hwnd, (HMENU)ID_MINIMIZE,
- hInst, NULL);
-
-
- close_button = CreateWindow(TEXT("button"), TEXT(""),
- WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
- 568, 0, 30, 30, hwnd, (HMENU)ID_CLOSE,
- hInst, NULL);
Next step is to draw borders on the window.this can be done in WM_PAINT message.
Here i drawn a top latered border,window text,icon & left,right,bottom rectangles.
See WM_PAINT code in following complete code.
Ok now you added buttons & also drawn a top layered border on window.
Now it's time to customize buttons.
This can be done by specifying WM_DRAWITEM message.
First declare the LPDRAWITEMSTRUCT structure variable.
LPDRAWITEMSTRUCT : Long Pointer to Draw Item Structure
First define the function that draw on button.
Here's the function that draw a black colored close button.
- void DrawCloseButton(HDC hdc)
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 30;
- rc.bottom = 30;
- HBRUSH br = CreateSolidBrush(RGB(0, 0, 0));
- FillRect(hdc, &rc, br);
-
- SetBkColor(hdc, RGB(0, 0, 0));
- SetTextColor(hdc, RGB(255, 255, 255));
-
- TextOut(hdc, 10, 8, L"X", 1);
- }
Now define statement by declaring the condition that LPDRAWITEMSTRUCT variable pointes to CtlID. And call the above drawn close button function by defining the ID of that button.
I have declared the ID_CLOSE to 0x001 and added this id while creating the close button in WM_CREATE message.
See following complete code for better understanding.
- LPDRAWITEMSTRUCT pdis;
-
- case WM_DRAWITEM:
- pdis = (LPDRAWITEMSTRUCT)lParam;
-
- switch (pdis->CtlID)
- {
- case ID_CLOSE:
-
- DrawCloseButton(pdis->hDC);
- break;
- }
Moving the window :
Window can be moved by mouse by specifying WM_NCHITTEST message in switch statement.
Here i just want move the window when cursor in on top layered border.
This can be done by getting the cursor position & window rect.
Here's the code that move window by mouse.
- LRESULT move = NULL;
-
- case WM_NCHITTEST:
- RECT rc;
- POINT pt;
-
- GetCursorPos(&pt);
-
- GetWindowRect(hwnd, &rc);
- rc.bottom = rc.bottom - 466;
-
-
-
- if (pt.x <= rc.right && pt.x >= rc.left && pt.y <= rc.bottom && pt.y >= rc.top)
- {
- move = DefWindowProc(hwnd, message, wParam, lParam);
- if (move == HTCLIENT)
- {
- move = HTCAPTION;
- }
- }
-
- return move;
-
- break;
Download the source code for both Visual Studio & MinGW and also demo.
Here's the complete code to create black colored window in Visual Studio.
- #include"stdafx.h"
- #include<Windows.h>
-
-
- #define ID_CLOSE 0x001
- #define ID_MINIMIZE 0x002
- #define ID_DEMOBUTTON 0x00F
-
- BOOL isMouseDownOnCloseButton = FALSE;
- BOOL isMouseDownOnMinimizeButton = FALSE;
- BOOL isMouseDownOnDemoButton = FALSE;
-
-
- HINSTANCE hInst;
-
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam);
-
-
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
- {
- TCHAR appname[] = TEXT("Windows Programming");
- WNDCLASS wndclass;
- MSG msg;
- HWND hwnd;
-
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(60, 60, 60)));
- wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
- wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wndclass.hInstance = hInstance;
- wndclass.lpfnWndProc = WndProc;
- wndclass.lpszClassName = appname;
- wndclass.lpszMenuName = NULL;
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
-
-
- if (!RegisterClass(&wndclass))
- {
- MessageBox(NULL, TEXT("Window class is not registered"), TEXT("Error...."), MB_ICONERROR);
- return 0;
- }
-
- hwnd = CreateWindow(appname,
- appname,
- WS_POPUP,
- 100,
- 100,
- 600,
- 500,
- NULL,
- NULL,
- hInstance,
- NULL
- );
-
-
- ShowWindow(hwnd, iCmdShow);
- UpdateWindow(hwnd);
-
-
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- return msg.wParam;
- }
-
-
-
-
- void DrawCloseButton(HDC hdc)
- {
- if (isMouseDownOnCloseButton)
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 30;
- rc.bottom = 30;
- HBRUSH br = CreateSolidBrush(RGB(200, 30, 30));
- FillRect(hdc, &rc, br);
-
- SetBkColor(hdc, RGB(200, 30, 30));
- SetTextColor(hdc, RGB(255, 255, 255));
-
- TextOut(hdc, 10, 8, L"X", 1);
- }
- else
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 30;
- rc.bottom = 30;
- HBRUSH br = CreateSolidBrush(RGB(0, 0, 0));
- FillRect(hdc, &rc, br);
-
- SetBkColor(hdc, RGB(0, 0, 0));
- SetTextColor(hdc, RGB(255, 255, 255));
-
- TextOut(hdc, 10, 8, L"X", 1);
- }
-
- }
-
-
-
- void DrawMinimizeButton(HDC hdc)
- {
- if (isMouseDownOnMinimizeButton)
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 30;
- rc.bottom = 30;
- HBRUSH br = CreateSolidBrush(RGB(60, 60, 100));
- FillRect(hdc, &rc, br);
-
- SetBkColor(hdc, RGB(60, 60, 100));
- SetTextColor(hdc, RGB(255, 255, 255));
- TextOut(hdc, 10, 5, L"_", 1);
- }
- else
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 30;
- rc.bottom = 30;
- HBRUSH br = CreateSolidBrush(RGB(0, 0, 0));
- FillRect(hdc, &rc, br);
-
- SetBkColor(hdc, RGB(0, 0, 0));
- SetTextColor(hdc, RGB(255, 255, 255));
- TextOut(hdc, 10, 5, L"_", 1);
- }
- }
-
-
-
- void DrawDemoButton(HDC hdc)
- {
- if (isMouseDownOnDemoButton)
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 260;
- rc.bottom = 80;
- HPEN hpen;
-
-
- for (int i = 0; i < 80; i++)
- {
- hpen = CreatePen(PS_SOLID, 4, RGB(150 - i, 0, 0));
- SelectObject(hdc, hpen);
- Rectangle(hdc, 0, 0 + i, 262, 1 + i);
- DeleteObject(hpen);
- }
-
- SetBkColor(hdc, RGB(130, 0, 0));
- SetTextColor(hdc, RGB(255, 255, 255));
- TextOut(hdc, 90, 27, L"Hello World", 11);
- }
- else
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = 260;
- rc.bottom = 80;
- HPEN hpen;
-
-
- for (int i = 0; i < 80; i++)
- {
- hpen = CreatePen(PS_SOLID, 4, RGB(0, 0, 150 - i));
- SelectObject(hdc, hpen);
- Rectangle(hdc, 0, 0 + i, 262, 1 + i);
- DeleteObject(hpen);
- }
-
- SetBkColor(hdc, RGB(0, 0, 130));
- SetTextColor(hdc, RGB(255, 255, 255));
- TextOut(hdc, 90, 27, L"Hello World", 11);
- }
-
- }
-
-
-
- void Draw_LeftRightBottom_Rectangles(RECT rect, HDC hdc, HBRUSH brush, int width, int height)
- {
- RECT leftrect, rightrect, bottomrect;
- leftrect.left = 0;
- leftrect.top = rect.bottom - 266;
- leftrect.right = 4;
- leftrect.bottom = height;
-
- FillRect(hdc, &leftrect, brush);
-
- rightrect.left = width - 4;
- rightrect.top = rect.bottom - 266;
- rightrect.right = width;
- rightrect.bottom = height;
-
- FillRect(hdc, &rightrect, brush);
-
- bottomrect.left = 0;
- bottomrect.top = height - 4;
- bottomrect.right = width;
- bottomrect.bottom = height;
-
- FillRect(hdc, &bottomrect, brush);
- }
-
-
-
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
- PAINTSTRUCT ps;
- HWND minimize_button, close_button, demo_button;
- static int X, Y;
- LRESULT move = NULL;
- LPDRAWITEMSTRUCT pdis;
- HICON hIcon;
-
- switch (message)
- {
- case WM_CREATE:
-
-
- minimize_button = CreateWindow(TEXT("button"), TEXT(""),
- WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
- 538, 0, 30, 30, hwnd, (HMENU)ID_MINIMIZE,
- hInst, NULL);
-
-
-
- close_button = CreateWindow(TEXT("button"), TEXT(""),
- WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
- 568, 0, 30, 30, hwnd, (HMENU)ID_CLOSE,
- hInst, NULL);
-
-
-
- demo_button = CreateWindow(TEXT("button"), TEXT(""),
- WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
- 160, 200, 260, 80, hwnd, (HMENU)ID_DEMOBUTTON,
- hInst, NULL);
-
- break;
-
-
- case WM_PAINT:
- hdc = BeginPaint(hwnd, &ps);
-
- RECT rect;
- HBRUSH brush;
-
- GetClientRect(hwnd, &rect);
- rect.bottom = rect.bottom - 466;
- brush = CreateSolidBrush(RGB(0, 0, 0));
-
-
- FillRect(hdc, &rect, brush);
-
-
- Draw_LeftRightBottom_Rectangles(rect, hdc, brush, X, Y);
-
-
- SetBkColor(hdc, RGB(0, 0, 0));
- SetTextColor(hdc, RGB(255, 255, 255));
- TextOut(hdc, 35, 7, TEXT("Custom Window in Win32"), 22);
-
-
- SetBkColor(hdc, RGB(60, 60, 60));
- SetTextColor(hdc, RGB(200, 200, 200));
- TextOut(hdc, 160, 120, TEXT("Custom Black Colored Window in Win32"), 36);
-
-
- hIcon = (HICON)LoadIcon(hInst, IDI_APPLICATION);
-
- DrawIconEx(hdc, 5, 5, hIcon, 20, 20, 0, brush, 0);
-
- EndPaint(hwnd, &ps);
-
- break;
-
-
- case WM_DRAWITEM:
- pdis = (LPDRAWITEMSTRUCT)lParam;
-
- switch (pdis->CtlID)
- {
- case ID_CLOSE:
-
- DrawCloseButton(pdis->hDC);
- break;
-
- case ID_MINIMIZE:
-
- DrawMinimizeButton(pdis->hDC);
- break;
-
- case ID_DEMOBUTTON:
- DrawDemoButton(pdis->hDC);
- break;
- }
-
-
- if (pdis->itemState && ODS_SELECTED)
- {
- isMouseDownOnCloseButton = TRUE;
- isMouseDownOnMinimizeButton = TRUE;
- isMouseDownOnDemoButton = TRUE;
- }
- else
- {
- isMouseDownOnCloseButton = FALSE;
- isMouseDownOnMinimizeButton = FALSE;
- isMouseDownOnDemoButton = FALSE;
- }
-
-
- break;
-
-
- case WM_COMMAND:
-
- switch (wParam)
- {
- case ID_CLOSE:
- PostQuitMessage(EXIT_SUCCESS);
- return 0;
-
- case ID_MINIMIZE:
- SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, lParam);
- break;
-
- case ID_DEMOBUTTON:
- MessageBox(NULL, TEXT("Custom Window in Win32"), TEXT("Hello World"), MB_OK);
- break;
-
- }
-
- break;
-
-
- case WM_SIZE:
- X = LOWORD(lParam);
- Y = HIWORD(lParam);
- break;
-
-
- case WM_NCHITTEST:
- RECT rc;
- POINT pt;
-
- GetCursorPos(&pt);
-
- GetWindowRect(hwnd, &rc);
- rc.bottom = rc.bottom - 466;
-
-
-
- if (pt.x <= rc.right && pt.x >= rc.left && pt.y <= rc.bottom && pt.y >= rc.top)
- {
- move = DefWindowProc(hwnd, message, wParam, lParam);
- if (move == HTCLIENT)
- {
- move = HTCAPTION;
- }
- }
-
- return move;
-
- break;
-
-
- case WM_DESTROY:
- PostQuitMessage(EXIT_SUCCESS);
- return 0;
-
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-
- }