我已多次搜索过,但我发现的一切都是MFC。我希望它在C ++ WinAPI中。我知道如何更改按钮控件的样式,但我无法找到如何使按钮成为不同的颜色。那么,如何使用C ++更改WinAPI按钮控件的背景颜色?我不想用资源文件来做这件事。
谢谢!
答案 0 :(得分:9)
我只是使用自定义绘图从我的其他帖子发布副本而不是链接,类似于alwayslearningnewstuff
示例:
第一张图显示当没有选择任何内容时,第二张显示第一个按钮被选中并被按下时,最后一张显示第二个按钮被按下且鼠标悬停在它上面(注意亮度增加 - cutom hilight)。为此,您必须自己捕获NM_CUSTOMDRAW消息和绘制按钮。这就是你如何做到的。还添加了渐变画笔功能和一些注释。
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#include <Windows.h>
#include <Commctrl.h>
#define IDC_EXIT_BUTTON 101
#define IDC_PUSHLIKE_BUTTON 102
HBRUSH CreateGradientBrush(COLORREF top, COLORREF bottom, LPNMCUSTOMDRAW item)
{
HBRUSH Brush = NULL;
HDC hdcmem = CreateCompatibleDC(item->hdc);
HBITMAP hbitmap = CreateCompatibleBitmap(item->hdc, item->rc.right-item->rc.left, item->rc.bottom-item->rc.top);
SelectObject(hdcmem, hbitmap);
int r1 = GetRValue(top), r2 = GetRValue(bottom), g1 = GetGValue(top), g2 = GetGValue(bottom), b1 = GetBValue(top), b2 = GetBValue(bottom);
for(int i = 0; i < item->rc.bottom-item->rc.top; i++)
{
RECT temp;
int r,g,b;
r = int(r1 + double(i * (r2-r1) / item->rc.bottom-item->rc.top));
g = int(g1 + double(i * (g2-g1) / item->rc.bottom-item->rc.top));
b = int(b1 + double(i * (b2-b1) / item->rc.bottom-item->rc.top));
Brush = CreateSolidBrush(RGB(r, g, b));
temp.left = 0;
temp.top = i;
temp.right = item->rc.right-item->rc.left;
temp.bottom = i + 1;
FillRect(hdcmem, &temp, Brush);
DeleteObject(Brush);
}
HBRUSH pattern = CreatePatternBrush(hbitmap);
DeleteDC(hdcmem);
DeleteObject(Brush);
DeleteObject(hbitmap);
return pattern;
}
LRESULT CALLBACK MainWindow(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HBRUSH defaultbrush = NULL;
static HBRUSH hotbrush = NULL;
static HBRUSH selectbrush = NULL;
static HBRUSH push_uncheckedbrush = NULL;
static HBRUSH push_checkedbrush = NULL;
static HBRUSH push_hotbrush1 = NULL;
static HBRUSH push_hotbrush2 = NULL;
switch (msg)
{
case WM_CREATE:
{
HWND Exit_Button = CreateWindowEx(NULL, L"BUTTON", L"EXIT",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
50, 50, 100, 100, hwnd, (HMENU)IDC_EXIT_BUTTON, NULL, NULL);
if(Exit_Button == NULL)
{
MessageBox(NULL, L"Button Creation Failed!", L"Error!", MB_ICONEXCLAMATION);
exit(EXIT_FAILURE);
}
HWND Pushlike_Button = CreateWindowEx(NULL, L"BUTTON", L"PUSH ME!",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX | BS_PUSHLIKE,
200, 50, 100, 100, hwnd, (HMENU)IDC_PUSHLIKE_BUTTON, NULL, NULL);
if(Pushlike_Button == NULL)
{
MessageBox(NULL, L"Button Creation Failed!", L"Error!", MB_ICONEXCLAMATION);
exit(EXIT_FAILURE);
}
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_EXIT_BUTTON:
{
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR some_item = (LPNMHDR)lParam;
if (some_item->idFrom == IDC_EXIT_BUTTON && some_item->code == NM_CUSTOMDRAW)
{
LPNMCUSTOMDRAW item = (LPNMCUSTOMDRAW)some_item;
if (item->uItemState & CDIS_SELECTED)
{
//Select our color when the button is selected
if (selectbrush == NULL)
selectbrush = CreateGradientBrush(RGB(180, 0, 0), RGB(255, 180, 0), item);
//Create pen for button border
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
//Select our brush into hDC
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, selectbrush);
//If you want rounded button, then use this, otherwise use FillRect().
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 5, 5);
//Clean up
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
//Now, I don't want to do anything else myself (draw text) so I use this value for return:
return CDRF_DODEFAULT;
//Let's say I wanted to draw text and stuff, then I would have to do it before return with
//DrawText() or other function and return CDRF_SKIPDEFAULT
}
else
{
if (item->uItemState & CDIS_HOT) //Our mouse is over the button
{
//Select our color when the mouse hovers our button
if (hotbrush == NULL)
hotbrush = CreateGradientBrush(RGB(255, 230, 0), RGB(245, 0, 0), item);
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, hotbrush);
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 5, 5);
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
return CDRF_DODEFAULT;
}
//Select our color when our button is doing nothing
if (defaultbrush == NULL)
defaultbrush = CreateGradientBrush(RGB(255, 180, 0), RGB(180, 0, 0), item);
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, defaultbrush);
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 5, 5);
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
return CDRF_DODEFAULT;
}
}
else if (some_item->idFrom == IDC_PUSHLIKE_BUTTON && some_item->code == NM_CUSTOMDRAW)
{
LPNMCUSTOMDRAW item = (LPNMCUSTOMDRAW)some_item;
if (IsDlgButtonChecked(hwnd, some_item->idFrom))
{
if (item->uItemState & CDIS_HOT)
{
if (push_hotbrush1 == NULL)
push_hotbrush1 = CreateGradientBrush(RGB(0, 0, 245), RGB(0, 230, 255), item);
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, push_hotbrush1);
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
return CDRF_DODEFAULT;
}
if (push_checkedbrush == NULL)
push_checkedbrush = CreateGradientBrush(RGB(0, 0, 180), RGB(0, 222, 200), item);
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, push_checkedbrush);
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
return CDRF_DODEFAULT;
}
else
{
if (item->uItemState & CDIS_HOT)
{
if (push_hotbrush2 == NULL)
push_hotbrush2 = CreateGradientBrush(RGB(255, 230, 0), RGB(245, 0, 0), item);
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, push_hotbrush2);
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
return CDRF_DODEFAULT;
}
if (push_uncheckedbrush == NULL)
push_uncheckedbrush = CreateGradientBrush(RGB(255, 180, 0), RGB(180, 0, 0), item);
HPEN pen = CreatePen(PS_INSIDEFRAME, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(item->hdc, pen);
HGDIOBJ old_brush = SelectObject(item->hdc, defaultbrush);
RoundRect(item->hdc, item->rc.left, item->rc.top, item->rc.right, item->rc.bottom, 10, 10);
SelectObject(item->hdc, old_pen);
SelectObject(item->hdc, old_brush);
DeleteObject(pen);
return CDRF_DODEFAULT;
}
}
return CDRF_DODEFAULT;
}
break;
case WM_CTLCOLORBTN: //In order to make those edges invisble when we use RoundRect(),
{ //we make the color of our button's background match window's background
return (LRESULT)GetSysColorBrush(COLOR_WINDOW+1);
}
break;
case WM_CLOSE:
{
DestroyWindow(hwnd);
return 0;
}
break;
case WM_DESTROY:
{
DeleteObject(defaultbrush);
DeleteObject(selectbrush);
DeleteObject(hotbrush);
DeleteObject(push_checkedbrush);
DeleteObject(push_hotbrush1);
DeleteObject(push_hotbrush2);
DeleteObject(push_uncheckedbrush);
PostQuitMessage(0);
return 0;
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG msg;
const wchar_t ClassName[] = L"Main_Window";
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MainWindow;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = ClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
exit(EXIT_FAILURE);
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, ClassName, L"Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 368, 248, NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
exit(EXIT_FAILURE);
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.message;
}
答案 1 :(得分:5)
我不记得原始代码的链接,但是过去的代码帮助我解决了您目前面临的问题。
请注意,它没有您所请求的资源文件,并且是普通的Win32 API。
仔细研究,一切都由原作者评论。
希望它会帮助你,因为它在过去帮助过我。
如果您有任何疑问,请询问,我会尽力回答。
据我所知,有4种方法可以改变按钮的颜色:
所有者提取(明显的解决方案)。
自定义抽奖(在我看来是最佳解决方案)。
子类化控件(我不喜欢它,但有可能)。
使用位图作为按钮背景。
处理WM_CTLCOLORBTN
:
来自MSDN:
只有所有者绘制的按钮才会响应处理此窗口的父窗口 信息。
重点是我的。如果您打算使用此选项,请仔细阅读Remarks section。
下面的代码演示了案例1,2和4。
#pragma comment(linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' \
publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "comctl32.lib")
#include <windows.h>
#include <commctrl.h>
ATOM RegisterWndClass(HINSTANCE hInst);
BOOL CreateMainWnd(HINSTANCE hInstance, int nCmdShow);
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
HINSTANCE hInst;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hInstPrev, LPWSTR lpszCmdLine,
int nCmdShow)
{
INITCOMMONCONTROLSEX icex = {0};
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_USEREX_CLASSES | ICC_BAR_CLASSES |
ICC_COOL_CLASSES | ICC_TAB_CLASSES | ICC_WIN95_CLASSES |
ICC_PROGRESS_CLASS | ICC_PAGESCROLLER_CLASS;
InitCommonControlsEx(&icex);
MSG msg;
hInst = hInstance;
if (!RegisterWndClass(hInstance))
return NULL;
if (!CreateMainWnd(hInstance, nCmdShow))
return NULL;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
};
ATOM RegisterWndClass(HINSTANCE hInstance)
{
WNDCLASS wndClass = {0};
wndClass.style = CS_DBLCLKS;
wndClass.lpfnWndProc = MainWndProc;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = L"MainClass";
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
return RegisterClass(&wndClass);
}
BOOL CreateMainWnd(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd = CreateWindow(L"MainClass", L"Buttons sample",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
GetSystemMetrics(SM_CXSCREEN) / 2 - 115,
GetSystemMetrics(SM_CYSCREEN) / 2 - 50,
230, 100, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
HBITMAP hBitmap = NULL;
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
// Owner draw button
CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON |
BS_OWNERDRAW, 10, 10, 60, 30, hWnd,
(HMENU)10001, hInst, NULL);
// Custom draw button
CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 80,
10, 60, 30, hWnd, (HMENU)10002, hInst, NULL);
// Bitmap button
HWND hBitmapButton = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE
| BS_PUSHBUTTON | BS_BITMAP,
150, 10, 60, 30, hWnd,
(HMENU)10003, hInst, NULL);
HDC hDC = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
hBitmap = CreateCompatibleBitmap(hDC, 55, 25);
SelectObject(hMemDC, hBitmap);
SetDCBrushColor(hMemDC, RGB(0, 0, 255));
RECT r = {0};
r.left = 0;
r.right = 55;
r.top = 0;
r.bottom = 25;
FillRect(hMemDC, &r, (HBRUSH)GetStockObject(DC_BRUSH));
DeleteDC(hMemDC);
ReleaseDC(hWnd, hDC);
SendMessage(hBitmapButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP,
(LPARAM)hBitmap);
return 0;
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case 10001:
MessageBox(hWnd, L"Owner draw button clicked", L"Message", NULL);
return 0;
case 10002:
MessageBox(hWnd, L"Custom draw button clicked", L"Message", NULL);
return 0;
case 10003:
MessageBox(hWnd, L"Bitmap button clicked", L"Message", NULL);
return 0;
}
break;
// Owner draw button
case WM_DRAWITEM:
if (wParam == 10001)
{
LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
SetDCBrushColor(lpDIS -> hDC, RGB(255, 0, 0));
SelectObject(lpDIS -> hDC, GetStockObject(DC_BRUSH));
RoundRect(lpDIS -> hDC, lpDIS -> rcItem.left, lpDIS -> rcItem.top,
lpDIS -> rcItem.right, lpDIS -> rcItem.bottom, 5, 5);
return TRUE;
}
break;
// Custom draw button
case WM_NOTIFY:
switch (((LPNMHDR)lParam) -> code)
{
case NM_CUSTOMDRAW:
if (((LPNMHDR)lParam) -> idFrom == 10002)
{
LPNMCUSTOMDRAW lpnmCD = (LPNMCUSTOMDRAW)lParam;
switch (lpnmCD -> dwDrawStage)
{
case CDDS_PREPAINT:
SetDCBrushColor(lpnmCD -> hdc, RGB(0, 255, 0));
SetDCPenColor(lpnmCD -> hdc, RGB(0, 255, 0));
SelectObject(lpnmCD -> hdc, GetStockObject(DC_BRUSH));
SelectObject(lpnmCD -> hdc, GetStockObject(DC_PEN));
RoundRect(lpnmCD -> hdc, lpnmCD -> rc.left + 3,
lpnmCD -> rc.top + 3,
lpnmCD -> rc.right - 3,
lpnmCD -> rc.bottom - 3, 5, 5);
return TRUE;
}
}
break;
}
break;
case WM_DESTROY:
if (hBitmap != NULL)
DeleteObject((HBITMAP)hBitmap);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
答案 2 :(得分:3)
您可以在DialogProc(MSDN About WM_DRAWITEM)上的消息WM_DRAWITEM中编辑一个按钮(其标志为BS_OWNERDRAW),这是一个如何绘制简单按钮的简单示例:
LPDRAWITEMSTRUCT Item;
Item = (LPDRAWITEMSTRUCT)lParam;
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(0));
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;
len = GetWindowTextLength(Item->hwndItem);
LPSTR lpBuff;
lpBuff = new char[len+1];
GetWindowTextA(Item->hwndItem, lpBuff, len+1);
DrawTextA(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER);
答案 3 :(得分:1)
你需要一个owner-drawn button。出于某种原因,与其他控件不同,常规按钮不会对WM_CTLCOLORBTN
消息处理程序中的更改做出反应。