Come posso cambiare il colore di sfondo di un pulsante WinAPI C ++

Ho cercato questo molte volte, ma tutto quello che trovo è MFC. Lo voglio in C ++ WinAPI. So come cambiare lo stile di un pulsante di controllo, ma non riesco a scoprire come rendere un pulsante un colore diverso. Quindi, come posso cambiare il colore di sfondo di un controllo pulsante WinAPI usando C ++? Non voglio farlo con un file di risorse.

Grazie!

Invece di un link, alwayslearningnewstuff una copia dal mio altro post utilizzando il disegno personalizzato, simile alwayslearningnewstuff di alwayslearningnewstuff :

Niente è selezionatoIl primo pulsante è selezionato ed è stato premutoIl secondo pulsante è stato premuto e il mouse è sopra di esso (si noti l'aumento di luminosità - cutom hilight)

La prima immagine mostra quando non è selezionato nulla, la seconda mostra quando viene selezionato il primo pulsante ed è stato premuto e l’ultimo mostra quando è stato premuto il secondo pulsante e il mouse è sopra di esso (notare l’aumento di luminosità – immagine notturna). Per fare ciò, devi prendere tu stesso il messaggio NM_CUSTOMDRAW e il pulsante paint. E questo è come lo fai. Aggiunta anche la funzione di sfumatura del pennello e alcuni commenti.

 #pragma comment(linker,"\"/manifestdependency:type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #include  #include  #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; } 

Non ricordo il collegamento per il codice originale, ma il codice muggito mi ha aiutato in passato a risolvere il problema che attualmente si trova ad affrontare.

Si noti che non ha un file di risorse, come richiesto, ed è in semplice API Win32.

Studia attentamente, tutto è commentato dall’autore originale.

Spero che ti possa aiutare, in quanto mi ha aiutato in passato.

Se hai qualche domanda, chiedi, proverò a rispondere loro.

Ci sono 4 modi, per quanto ne so, per cambiare il colore del pulsante:

  1. Estrazione del proprietario (soluzione ovvia).

  2. Disegno personalizzato (a mio parere la soluzione migliore).

  3. Sottoclass il controllo (non mi piace, ma è ansible).

  4. Usa le bitmap come sfondo dei pulsanti.

  5. Gestione di WM_CTLCOLORBTN :

Da MSDN:

solo i pulsanti disegnati dal proprietario rispondono alla finestra padre che elabora questo messaggio.

L’accento è mio. Se si prevede di utilizzare questa opzione, leggere attentamente la sezione Note .

Il codice seguente mostra i casi 1, 2 e 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  #include  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); } 

È ansible modificare un pulsante (che ha la bandiera BS_OWNERDRAW) nel messaggio WM_DRAWITEM sul DialogProc ( MSDN About WM_DRAWITEM ), ecco un semplice esempio di come disegnare un semplice pulsante:

 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); 

Hai bisogno di un pulsante disegnato dal proprietario per quello. Per qualche motivo, a differenza di altri controlli, i pulsanti normali non reagiscono alle modifiche apportate nel gestore di messaggi WM_CTLCOLORBTN .