Related
To change the static's control color and width, I did process the WM_NCPAINT message, but it's not working properly:
the text isn't properly displayed. Should I draw it in this message? When I call SetWindowText(), the new text is properly set, but I still have the issue #2.
after a call to SetWindowText(), the text is set, but the border differs, it's smaller than the one I've draw in the WM_NCPAINT message.
Here's how I'm handling WM_NCPAINT:
case WM_NCPAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
RECT rt = {0};
GetClientRect(hwnd, &rt);
HPEN pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN holdPen = SelectObject(dc, pen);
DrawBorder(dc, &rt);
SelectObject(dc, holdPen);
EndPaint(hwnd, &ps);
DeleteObject(pen);
pen = NULL;
return 0;
}
When the application starts, the static control border looks like the one I've draw at WM_NCPAINT:
But once I call SetWindowText(), for example, from a button click, it looks like this:
What am I missing?
Here's full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void EnableVisualStyles2(void);
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void SetDefaultFont(HWND hwnd);
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2);
void DrawBorder(HDC hdc, RECT *rect);
HFONT getSystemDefaultFont(void);
WNDPROC oldButtonProc;
HINSTANCE ghInstance;
HFONT hDefaultFont;
HWND btn, btn2;
enum
{
BTN_ID = 10,
BTN2_ID,
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow)
{
MSG msg = {0};
HWND hwnd;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
EnableVisualStyles2();
if(!RegisterClass(&wc)) {
return -1;
}
int width = 540;
int height = 460;
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int cx = (screenWidth - width) / 2;
int cy = (screenHeight - height) / 2;
hwnd = CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
cx, cy, width, height, NULL, NULL,
hInstance, NULL);
ghInstance = hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DeleteObject(hDefaultFont);
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
btn =
CreateWindow(L"static", L"+",
WS_VISIBLE | WS_CHILD | WS_TABSTOP |
SS_NOTIFY | SS_CENTER | SS_CENTERIMAGE,
15, 25, 50, 50,
hwnd, (HMENU) BTN_ID, NULL, NULL);
SetDefaultFont(btn);
oldButtonProc = (WNDPROC) SetWindowLongPtr(btn,
GWLP_WNDPROC,
(LONG_PTR) ButtonProc);
btn2 =
CreateWindow(L"Button", L"Click me!",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
15, 100, 70, 25,
hwnd, (HMENU) BTN2_ID,
NULL, NULL);
SetDefaultFont(btn2);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case BTN_ID:
{
//InvalidateRect(btn, NULL, TRUE);
if(IsWindowVisible(btn2))
{
SetWindowText(btn, L"+");
ShowWindow(btn2, SW_HIDE);
}
else
{
SetWindowText(btn, L"-");
ShowWindow(btn2, SW_SHOW);
}
}
break;
case BTN2_ID:
{
InvalidateRect(btn, NULL, TRUE);
//SetWindowText(btn, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0");
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCPAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
RECT rt = {0};
GetClientRect(hwnd, &rt);
HPEN pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN holdPen = SelectObject(dc, pen);
DrawBorder(dc, &rt);
SelectObject(dc, holdPen);
EndPaint(hwnd, &ps);
DeleteObject(pen);
pen = NULL;
return 0;
}
}
return CallWindowProc(oldButtonProc, hwnd, msg, wParam, lParam);
}
void EnableVisualStyles2(void)
{
TCHAR dir[MAX_PATH] = {0};
GetSystemDirectory(dir, sizeof(dir) / sizeof(*dir));
ACTCTX actCtx = {0};
actCtx.cbSize = sizeof(ACTCTX);
actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID |
ACTCTX_FLAG_SET_PROCESS_DEFAULT |
ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
actCtx.lpSource = L"shell32.dll";
actCtx.lpAssemblyDirectory = dir;
actCtx.lpResourceName = (LPCTSTR) 124;
ULONG_PTR cookie = FALSE;
HANDLE h = CreateActCtx(&actCtx);
assert(h != INVALID_HANDLE_VALUE);
assert(ActivateActCtx(h, &cookie));
}
HFONT getSystemDefaultFont(void)
{
if(!hDefaultFont)
{
// get system default font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
hDefaultFont = CreateFontIndirect(&ncm.lfMessageFont);
}
return hDefaultFont;
}
void SetDefaultFont(HWND hwnd)
{
SendMessage(hwnd, WM_SETFONT, (WPARAM)getSystemDefaultFont(), FALSE);
}
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2)
{
MoveToEx(hdc, x1, y1, NULL);
LineTo(hdc, x2, y2);
}
void DrawBorder(HDC hdc, RECT *rect)
{
DrawLine(hdc, rect->left, rect->top, rect->left, rect->bottom);
DrawLine(hdc, rect->left, rect->top, rect->right, rect->top);
DrawLine(hdc, rect->right, rect->top, rect->right, rect->bottom);
DrawLine(hdc, rect->left, rect->bottom, rect->right, rect->bottom);
}
Your static control does not have a transparent background, so when you call the SetWindowText function, the static control partially covers the external lines you draw.
You can add the following code in WndProc:
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetBkMode(hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
But this code tells the static control to draw the text without a background color and not to repaint the background. So the new text is drawn on top of the old text instead of on a fresh background.You can refer to this thread to try to solve it.
Of course, you can also extend the boundary of the straight line when drawing a straight line (you do not need to process the WM_CTLCOLORSTATIC message), as shown in the following code:
void DrawBorder(HDC hdc, RECT* rect)
{
DrawLine(hdc, rect->left - 3, rect->top - 3, rect->left - 3, rect->bottom + 3) ;
DrawLine(hdc, rect->left - 3, rect->top - 3, rect->right + 3, rect->top - 3);
DrawLine(hdc, rect->right + 3, rect->top - 3, rect->right + 3, rect->bottom + 3);
DrawLine(hdc, rect->left - 3, rect->bottom + 3, rect->right + 3, rect->bottom + 3);
}
This is the modified effect:
I tried to color customize menu items (pure WinAPI). But there is a line in the menu bar which does not draw with MenuInfo.hbrBack color. If the mouse cursor hover above items a part of this line is redrawn. But if I resize the window the line will return. And in the area of menu bar where no items the line drawn constantly. How can I draw over this annoying line?
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
struct
{
COLORREF text = RGB(200, 200, 250);
COLORREF clientBorder = RGB(120, 0, 0);
COLORREF clientBackground = RGB(100, 100, 100);
COLORREF itemBorder = RGB(0, 0, 255);
COLORREF itemBackground = RGB(0, 120, 0);
COLORREF pink = RGB(255, 0, 255);
} colorTheme;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MainWindow";
wc.cbWndExtra = NULL;
wc.cbClsExtra = NULL;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(colorTheme.clientBackground);
wc.hInstance = hInst;
RegisterClassEx(&wc);
HWND hMainWnd = CreateWindow(
"MainWindow",
"MainWindow",
WS_OVERLAPPEDWINDOW,
100, 100, 450, 120,
(HWND)NULL, NULL, HINSTANCE(hInst), NULL);
HMENU hMenu = CreateMenu();
HMENU hMenuSub1 = CreatePopupMenu();
HMENU hMenuSub2 = CreatePopupMenu();
HMENU hMenuSub3 = CreatePopupMenu();
AppendMenu(hMenu, MF_OWNERDRAW | MF_POPUP, (UINT)hMenuSub1, "SubMenu1");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item01");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item02");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item03");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item04");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item05");
AppendMenu(hMenu, MF_OWNERDRAW | MF_POPUP, (UINT)hMenuSub2, "SubMenu2");
AppendMenu(hMenu, MF_OWNERDRAW | MF_POPUP, (UINT)hMenuSub3, "SubMenu3");
MENUINFO menuInfo;
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIM_BACKGROUND;
menuInfo.hbrBack = CreateSolidBrush(colorTheme.pink);
SetMenuInfo(hMenu, &menuInfo);
SetMenu(hMainWnd, hMenu);
ShowWindow(hMainWnd, nCmdShow);
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
HFONT hApplicationFont;
LOGFONT applicationFont;
applicationFont.lfHeight = 16;
applicationFont.lfWidth = 6;
applicationFont.lfEscapement = 0;
applicationFont.lfOrientation = 0;
applicationFont.lfWeight = FW_NORMAL;
applicationFont.lfItalic = FALSE;
applicationFont.lfUnderline = FALSE;
applicationFont.lfStrikeOut = FALSE;
applicationFont.lfCharSet = DEFAULT_CHARSET;
applicationFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
applicationFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
applicationFont.lfQuality = ANTIALIASED_QUALITY;
applicationFont.lfPitchAndFamily = DEFAULT_PITCH;
strcpy_s(applicationFont.lfFaceName, "Arial");
hApplicationFont = CreateFontIndirectA(&applicationFont);
SelectObject(hDC, hApplicationFont);
SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, colorTheme.clientBorder);
SelectObject(hDC, GetStockObject(DC_BRUSH));
SetDCBrushColor(hDC, colorTheme.clientBackground);
RECT clientRect;
GetClientRect(hWnd, &clientRect);
Rectangle(hDC, 0, 0, clientRect.right, clientRect.bottom);
EndPaint(hWnd, &ps);
break;
}
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT itemStruct = (LPMEASUREITEMSTRUCT)lParam;
const char* str = (const char*)(itemStruct->itemData);
SIZE strSize;
HDC hDC = GetDC(hWnd);
GetTextExtentPoint32(hDC, str, lstrlen(str), &strSize);
itemStruct->itemWidth = strSize.cx;
itemStruct->itemHeight = 30;
ReleaseDC(hWnd, hDC);
return TRUE;
break;
}
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT itemStruct = (LPDRAWITEMSTRUCT)lParam;
HDC hDC = itemStruct->hDC;
SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, colorTheme.itemBorder);
SelectObject(hDC, GetStockObject(DC_BRUSH));
SetDCBrushColor(hDC, colorTheme.itemBackground);
SetTextColor(hDC, colorTheme.text);
SetBkMode(hDC, TRANSPARENT);
Rectangle(hDC, itemStruct->rcItem.left,
itemStruct->rcItem.top,
itemStruct->rcItem.right,
itemStruct->rcItem.bottom + 1);
DrawText(hDC, (const char*)(itemStruct->itemData), -1, &(itemStruct->rcItem), DT_SINGLELINE | DT_CENTER | DT_VCENTER);
break;
}
case WM_DESTROY:
{
PostQuitMessage(NULL);
break;
}
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return NULL;
}
It seems to be part of the non-client area of the window. If that's the case then to paint there you need to handle WM_NCPAINT.
It is a single pixel line above the window's client area, so for example if I add the following code to your program I can paint it in red.
// ... in the WNDPROC
case WM_NCPAINT:
{
auto result = DefWindowProc(hWnd, WM_NCPAINT, wParam, lParam);
HDC hdc = GetWindowDC(hWnd);
RECT r = GetNonclientMenuBorderRect(hWnd);
HBRUSH red = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &r, red);
DeleteObject(red);
ReleaseDC(hWnd, hdc);
return result;
}
// ... elsewhere
RECT MapRectFromClientToWndCoords(HWND hwnd, const RECT& r)
{
RECT wnd_coords = r;
// map to screen
MapWindowPoints(hwnd, NULL, reinterpret_cast<POINT*>(&wnd_coords), 2);
RECT scr_coords;
GetWindowRect(hwnd, &scr_coords);
// map to window coords by substracting the window coord origin in
// screen coords.
OffsetRect(&wnd_coords, -scr_coords.left, -scr_coords.top);
return wnd_coords;
}
RECT GetNonclientMenuBorderRect(HWND hwnd)
{
RECT r;
GetClientRect(hwnd, &r);
r = MapRectFromClientToWndCoords(hwnd, r);
int y = r.top - 1;
return {
r.left,
y,
r.right,
y+1
};
}
Now an issue with the above code is that it is over-painting the rectangle after the default non-client painting is done. In theory this could flicker; in practice I don't notice a flicker. If it did flicker, however, a safer way to do this would be to modify the WPARAM you pass to DefWindowProc(hWnd, WM_NCPAINT, ... ) such that it is the handle to a region that is the region passed to WM_NCPAINT minus the rectangle you want to paint. This doesnt seem necessary to me, for whatever reason.
If you are using themes / visual styles, which pretty much everything is nowadays, you can't override a lot of the menu styling without using a workaround like https://github.com/adzm/win32-custom-menubar-aero-theme which also uses the same approach to get rid of the white line. Note that you will need to handle this in WM_NCPAINT and WM_NCACTIVATE.
The last three versions of Windows have all had translucent highlight and hover effects in Windows Explorer listview:
Using a theme explorer I see that the ListItem has no state that matches what i see in Windows:
Is there a:
class
part
state
that represents the ListView in Windows?
For compatibility reasons ListView still has the old style look by default. DrawThemeBackground(htheme, hdc, LVP_LISTITEM, ...) will simply draw a solid rectangle with border, for all item states, as shown in above image. GetSysColor should be used to get the right colors for this listview.
A call to SetWindowTheme(hwnd, L"Explorer", NULL) will load the new theme data and draw the list items similar to Explorer. Example:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
SetWindowTheme(hwnd, L"Explorer", NULL);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
auto hdc = BeginPaint(hwnd, &ps);
HTHEME ht = OpenThemeData(hwnd, L"LISTVIEW");
if(ht)
{
RECT rc = { 10, 10, 100, 50 };
DrawThemeBackground(ht, hdc, LVP_LISTITEM, LISS_SELECTED, &rc, NULL); OffsetRect(&rc, 0, 55);
DrawThemeBackground(ht, hdc, LVP_LISTITEM, LISS_DISABLED, &rc, NULL); OffsetRect(&rc, 0, 55);
DrawThemeBackground(ht, hdc, LVP_LISTITEM, LISS_SELECTED, &rc, NULL); OffsetRect(&rc, 0, 55);
DrawThemeBackground(ht, hdc, LVP_LISTITEM, LISS_HOT, &rc, NULL); OffsetRect(&rc, 0, 55);
DrawThemeBackground(ht, hdc, LVP_LISTITEM, LISS_HOTSELECTED, &rc, NULL); OffsetRect(&rc, 0, 55);
DrawThemeBackground(ht, hdc, LVP_LISTITEM, LISS_SELECTEDNOTFOCUS, &rc, NULL);
CloseThemeData(ht);
}
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Output:
I want to make dark semitransparent GUI using WinAPI. I made a custom button, but I cant make my own groupbox. In WM_DRAWITEM case of message handler, the callback drawing my groupbox is not even called. This callback contains MessageBox call that is not even once appeared.
How to draw groupbox with colored frame and colored text? Also I want to make my groupboxes lying under the all other controls. How to do that?
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// Main logic goes here...
ShowMainWindow();
}
void RegisterWndClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = Proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(RGB(0x14, 0x14, 0x14));
wc.lpszMenuName = NULL;
wc.lpszClassName = szName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("Cannot register class"), TEXT("Error"), MB_OK);
}
}
// Draw custom button
void DrawButton(DRAWITEMSTRUCT *Item, HWND hwnd)
{
SelectObject(Item->hDC, CreateFont(16, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial Black"));
FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(RGB(0x14, 0x14, 0x14)));
SelectObject(Item->hDC, CreateSolidBrush(0));
if (Item->itemState & ODS_SELECTED)
{
SetTextColor(Item->hDC, 0);
SelectObject(Item->hDC, CreateSolidBrush(0xFF00));
SelectObject(Item->hDC, CreatePen(PS_SOLID, 2, 0xFF00));
}
else
{
SetTextColor(Item->hDC, 0x00FF00);
SelectObject(Item->hDC, CreatePen(PS_SOLID, 2, 0x00FF00));
}
SetBkMode(Item->hDC, TRANSPARENT);
RoundRect(Item->hDC, Item->rcItem.left, Item->rcItem.top, Item->rcItem.right, Item->rcItem.bottom, 20, 20);
int len = GetWindowTextLength(Item->hwndItem);
LPSTR lpBuff[255];
GetWindowTextA(Item->hwndItem, lpBuff, len + 1);
DrawTextA(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER);
}
// Trying to draw customgroupbox
void DrawKeyGroup(DRAWITEMSTRUCT *Item, HWND hwnd)
{
SelectObject(Item->hDC, CreateSolidBrush(RGB(0, 255, 0)));
SelectObject(Item->hDC, CreateSolidBrush(0));
SetTextColor(Item->hDC, 0x00FF00);
SelectObject(Item->hDC, CreatePen(PS_SOLID, 2, 0x00FF00));
MessageBox(NULL, "", "", MB_OK);
//SetBkMode(Item->hDC, TRANSPARENT);
RoundRect(Item->hDC, Item->rcItem.left, Item->rcItem.top, Item->rcItem.right, Item->rcItem.bottom, 200, 200);
}
//Main windows proc
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;
switch (uMsg)
{
case WM_CREATE: // Init interface
// Text field
CreateWindow(TEXT("EDIT"),
NULL,
WS_VISIBLE | WS_CHILD | ES_LEFT | ES_AUTOHSCROLL,
10, 280, 350, 20,
hWnd,
(HMENU)ID_KEY_FIELD,
NULL,
NULL);
// Button to enter the text
CreateWindowEx(0, TEXT("BUTTON"),
TEXT("Unlock"),
WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
370, 280, 150, 20,
hWnd,
(HMENU)ID_KEY_ENTER,
GetModuleHandle(NULL),
NULL);
// Groupbox
CreateWindowEx(0, TEXT("BUTTON"),
TEXT("Key"),
WS_VISIBLE | WS_CHILD | BS_GROUPBOX | BS_OWNERDRAW,
5, 262, 523, 47,
hWnd,
(HMENU)ID_KEY_GROUP,
GetModuleHandle(NULL),
NULL);
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
EndPaint(hWnd, &ps);
break;
// Color text field
case WM_CTLCOLOREDIT:
{
HDC hdc = (HDC)wParam;
HWND hwnd = (HWND)lParam;
if (GetDlgCtrlID(hwnd) == ID_KEY_FIELD)
{
SetTextColor(hdc, 0xFF00);
SetBkColor(hdc, RGB(0x29, 0x29, 0x29));
return (LRESULT)CreateSolidBrush(RGB(0x29, 0x29, 0x29));
}
break;
}
// Color statie elements (group box caption)
/*case WM_CTLCOLORSTATIC:
SetTextColor((HDC)wParam, RGB(0x00, 0x8C, 0xBA));
SetBkMode((HDC)wParam, TRANSPARENT);
SetBkColor((HDC)wParam, RGB(0x14, 0x14, 0x14));
return (LRESULT)CreateSolidBrush(GetBkColor((HDC)wParam));*/
// Draw custom controls
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)lParam;
switch (dis->CtlID)
{
case ID_KEY_ENTER:
DrawButton(dis, GetDlgItem(hWnd, dis->CtlID));
break;
case ID_KEY_GROUP:
DrawKeyGroup(dis, GetDlgItem(hWnd, dis->CtlID));
break;
}
}
case WM_SIZE:
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
void ShowMainWindow(void)
{
HWND hMainWnd;
MSG msg;
RegisterWndClass(WndProc, TEXT("Info"), COLOR_WINDOW);
hMainWnd = CreateWindowEx(WS_EX_LAYERED, TEXT("Info"), TEXT("Info"),
WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, 0, 550, 360, (HWND)NULL, (HMENU)NULL,
GetModuleHandle(NULL), NULL);
SetWindowLong(hMainWnd, GWL_EXSTYLE, GetWindowLong(hMainWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hMainWnd, 0, (255 * 70) / 100, LWA_ALPHA);
if (!hMainWnd)
{
MessageBox(NULL, TEXT("Can\'t create main window."), TEXT("Error"), MB_OK);
return;
}
ShowWindow(hMainWnd, SW_SHOW);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
I have created a window with createwindow() api using VS2005 in C++ on Windows Vista
My requirement is to draw an image (of any format) on that window. I am not using any MFC in this application.
not exactly sure what is your problem: draw a bitmap on the form, or you would like know how to work with various image formats, or both. Anyways below is an example of how you could load a bitmap and draw it on the form:
HBITMAP hBitmap = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
<...>
case WM_CREATE:
hBitmap = (HBITMAP)LoadImage(hInst, L"c:\\test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
BITMAP bitmap;
HDC hdcMem;
HGDIOBJ oldBitmap;
hdc = BeginPaint(hWnd, &ps);
hdcMem = CreateCompatibleDC(hdc);
oldBitmap = SelectObject(hdcMem, hBitmap);
GetObject(hBitmap, sizeof(bitmap), &bitmap);
BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
DeleteObject(hBitmap);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LoadImage loads an icon, cursor, animated cursor, or bitmap. Details here
For working with various images formats you can use Windows Imaging Component (see IWICBitmapDecoder) or code from here Loading JPEG and GIF pictures or 3rd party tools like FreeImage or LeadTools
hope this helps, regards
void LoadScreen(HWND hWnd) {
RECT rect;
HDC hdc = GetDC(hWnd);
HBRUSH brush = CreatePatternBrush((HBITMAP)LoadImage(NULL, L"file.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
GetWindowRect(hWnd, &rect);
FillRect(hdc, &rect, brush);
DeleteObject(brush);
ReleaseDC(hWnd, hdc);
}
#include <windows.h>
#include <string.h>
HBITMAP hBitmap, hOldBitmap;
HDC hdc, hdcMem;
BITMAP bm;
HINSTANCE hI;
PAINTSTRUCT ps;
RECT rect;
RECT rc;
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
hBitmap = (HBITMAP)LoadImage(hI, "1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
GetObject(hBitmap, sizeof(BITMAP), &bm);
hdc = GetDC(hWnd);
hdcMem = CreateCompatibleDC(hdc);
hOldBitmap = SelectBitmap(hdcMem, hBitmap);
ReleaseDC(hWnd, hdc);
return 0;
case WM_LBUTTONDOWN:
//for dragging not only by the title, but also by any part of the window
ReleaseCapture();
SendMessage(hWnd, 0xA1, 2, 0);
break;
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
//overlay image with stretching to fit the window
GetClientRect(hWnd,&rect);
SetStretchBltMode(hdc, STRETCH_HALFTONE);
StretchBlt(hdc,0,0,rect.right,rect.bottom,
hdcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
EndPaint(hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
DeleteObject(hOldBitmap);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPInst, LPSTR lpCmdLine, int nCmdShow)
{
//copying a pointer to a running application instance (module)
hI=hInstance;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProcedure;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
wc.lpszClassName = "test_class";
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClass(&wc);
HWND hWnd = CreateWindow(wc.lpszClassName, "Image Window",
//window with title (overlapping window)
WS_OVERLAPPEDWINDOW,
//window without title
//WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage (&msg, NULL, 0, 0))
{
DispatchMessage (&msg);
TranslateMessage (&msg);
}
UnregisterClass(wc.lpszClassName, hInstance);
return (int) msg.wParam;
}