我想使用RoundRect
在WM_DRAWITEM
中为所有者绘制控件绘制一个填充的圆角矩形。一切正常,但由于某种原因,将圆角之外的区域设置为白色(就像先清除正方形然后画出圆角矩形一样)。我希望它不要触及该区域,而是将其视为透明的。怎么做?
TIA !!
答案 0 :(得分:2)
Windows默认为矩形。绘制它们时,必须绘制整个矩形。也就是说,所有者至少可以通过三种方式将按钮绘制为圆形矩形:
简单方法:将圆形矩形按钮外部的区域涂成与其父级背景颜色相同的颜色
老派的方法:使用SetWindowRgn(...)使所有者绘制的按钮具有一个圆形的矩形裁剪区域。下面包含执行此操作的代码。这项技术的问题在于您无法对圆形矩形的边界进行抗锯齿处理。
新方法:由于可以使用WS_EX_LAYERED扩展样式创建Windows 8子窗口。这应该使您只需将窗口绘制为圆形矩形即可。但是,由于(我认为)您需要包括一个清单,该清单将您的可执行文件的受支持操作系统设置为Windows 8或更高版本,否则情况就变得复杂了,否则对CreateWindowEx(WS_EX_LAYERED,...)的调用只会失败(至少对我有帮助)。不幸的是,我无法显示如何将清单包含在我的头顶上。
然而,下面是非常基本的代码,展示了窗口区域的方式。您可以通过使用GDI +进行绘制并设置抗锯齿的图形来解决此问题,也可以使用位图填充而不是使用GDI / GDI +调用进行绘制。
// RoundRectButton.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "RoundRectButton.h"
#define BTN_ID 101
HINSTANCE g_instance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
g_instance = hInstance;
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
wc.lpszClassName = L"owner_draw_btn";
if (!RegisterClass(&wc))
return -1;
if (!CreateWindow(wc.lpszClassName, L"foobar", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL))
return -1;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT HandleDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam, int corner_wd, int corner_hgt,
COLORREF unclicked_color, COLORREF clicked_color)
{
auto* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
if (dis->CtlType != ODT_BUTTON)
return 0;
COLORREF fill_color = (dis->itemState & ODS_SELECTED) ? clicked_color : unclicked_color;
auto rect = &dis->rcItem;
//DrawFrameControl(dis->hDC, rect, DFC_BUTTON, style);
HPEN pen = CreatePen(PS_SOLID, 6, RGB(0, 0, 0));
HPEN old_pen = (HPEN) SelectObject(dis->hDC, pen);
HBRUSH brush = CreateSolidBrush(fill_color);
HBRUSH old_brush = (HBRUSH) SelectObject(dis->hDC, brush);
RoundRect(dis->hDC, rect->left, rect->top, rect->right, rect->bottom, corner_wd, corner_hgt);
SelectObject(dis->hDC, old_pen);
SelectObject(dis->hDC, old_brush);
DeleteObject(pen);
DeleteObject(brush);
TCHAR text[512];
auto n = GetWindowText(dis->hwndItem, text, 512);
SetBkMode(dis->hDC, TRANSPARENT);
DrawText(dis->hDC, text, n, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return 0;
}
HWND CreateRoundRectButton(HWND parent, int x, int y, int wd, int hgt, int corner_wd, int corner_hgt, int id)
{
HWND button = CreateWindow(
L"button", L"foobar",
BS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
x, y, wd, hgt, parent,
(HMENU) id,
g_instance,
0
);
SetWindowRgn(button, CreateRoundRectRgn(0, 0, wd, hgt, corner_wd, corner_hgt), TRUE);
return button;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND button = NULL;
DWORD err;
switch (message)
{
case WM_CREATE:
button = CreateRoundRectButton(hWnd, 15, 15, 150, 35, 15, 15, BTN_ID);
return 0;
case WM_DRAWITEM:
return HandleDrawItem(hWnd, wParam, lParam, 15, 15, RGB(230,230,230), RGB(255,255,255));
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
答案 1 :(得分:0)
由于这是一个按钮控件,因此似乎可以正常工作(我试图添加注释,但无法设置其格式)。
case WM_CTLCOLORBTN:
{
if ((HWND)lparam==GetDlgItem(hwnd, IDC_BUTTON)) {
return (LRESULT) ::GetStockObject(NULL_BRUSH);
}
break;
}