为什么Windows会绘制自己的“最小最大关闭”按钮,即使WM_NCPAINT已正确(?)重新实现?
我们可以从我拍摄的这个截图中看到: 出于某种奇怪的原因,Windows在标题栏中绘制了自己的(非样式的)最小化/最大化/关闭按钮 在我的皮肤标题栏(黄色矩形)顶部,红色箭头指向。 它还在这些按钮的底部画了一条恼人的1像素大小的线,你可以从屏幕上看到 您可以注意到我正在为窗口蒙皮:我正在绘制自己的标题栏(黄色矩形),然后 调整边框大小(青色、洋红、红色矩形)。 现在它们只是矩形,但我不明白为什么Windows只在WM_NCPAINT发生时绘制,就在我在非客户区绘制的黄色矩形之上绘制。 除了这个奇怪的东西,一切都很好 这种情况并不总是发生,它会在使用蒙皮窗口、调整其大小并将其最大化/最小化2-3次后发生。特别是当我在小程序执行的某个点上,在tilebar上单击鼠标时,会发生这种情况。事实上,我认为问题可能是WM_NCHITTEST信息中的某些错误,但似乎并非如此。有问题,可能是某个窗口样式或窗口扩展样式标志出错 我无法解释这一点,我正在正确地重新实现WM_NCPAINT消息(我猜),那么Windows难道不应该理解我正在绘制自己的标题栏吗?为什么它会覆盖我的图纸?!这是Windows XP的一个bug吗? 这似乎不会发生在Windows7中,但我不太确定 也许我只是错过了重新实现一个WM_*消息。 有人能帮我吗?这让我发疯了 注意:我不能使用WinForms、Qt或其他有助于对窗口进行蒙皮的库,这是一个旧项目,所有这些都必须直接在winapi中完成,处理正确的WM_*消息。无法链接任何库 注2:在WM_NCACTIVATE消息中同时使用SetWindowPos或RedrawWindow会产生相同的结果 代码如下:为什么Windows会绘制自己的“最小最大关闭”按钮,即使WM_NCPAINT已正确(?)重新实现?,windows,winapi,user-interface,skins,Windows,Winapi,User Interface,Skins,我们可以从我拍摄的这个截图中看到: 出于某种奇怪的原因,Windows在标题栏中绘制了自己的(非样式的)最小化/最大化/关闭按钮 在我的皮肤标题栏(黄色矩形)顶部,红色箭头指向。 它还在这些按钮的底部画了一条恼人的1像素大小的线,你可以从屏幕上看到 您可以注意到我正在为窗口蒙皮:我正在绘制自己的标题栏(黄色矩形),然后 调整边框大小(青色、洋红、红色矩形)。 现在它们只是矩形,但我不明白为什么Windows只在WM_NCPAINT发生时绘制,就在我在非客户区绘制的黄色矩形之上绘制。 除了这个奇
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "SkinTest";
int left_off;
int right_off;
int top_off;
int bottom_off;
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl))
return 0;
DWORD style = WS_OVERLAPPEDWINDOW;
hwnd = CreateWindowEx (
WS_EX_CLIENTEDGE,
szClassName,
"Code::Blocks Template Windows App",
style,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
HWND_DESKTOP,
NULL,
hThisInstance,
NULL
);
//
// This prevent the round-rect shape of the overlapped window.
//
HRGN rgn = CreateRectRgn(0,0,500,500);
SetWindowRgn(hwnd, rgn, TRUE);
left_off = 4;
right_off = 4;
top_off = 23;
bottom_off = 4;
ShowWindow (hwnd, nCmdShow);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
#define COLOR_TITLEBAR 0
#define COLOR_LEFT_BORDER 2
#define COLOR_RIGHT_BORDER 4
#define COLOR_BOTTOM_BORDER 6
int win_x, win_y, win_width, win_height;
int win_is_not_active = 0;
COLORREF borders_colors[] =
{
RGB(255,255,0), RGB(180,180,0), // Active titlebar - Not active titlebar
RGB(0,255,255), RGB(0,180,180), // Active left border - Not active left border
RGB(255,0,255), RGB(180,0,180), // Active right border - Not Active right border
RGB(255,0,0), RGB(180,0,0) // Active bottom border - Not active bottom border
};
void draw_titlebar(HDC hdc)
{
HBRUSH tmp, br = CreateSolidBrush(borders_colors[COLOR_TITLEBAR + win_is_not_active]);
tmp = (HBRUSH)SelectObject(hdc, br);
Rectangle(hdc, 0, 0, win_width, top_off);
SelectObject(hdc, tmp);
DeleteObject(br);
}
void draw_left_border(HDC hdc)
{
HBRUSH tmp, br = CreateSolidBrush(borders_colors[COLOR_LEFT_BORDER + win_is_not_active]);
tmp = (HBRUSH)SelectObject(hdc, br);
Rectangle(hdc, 0, top_off, left_off, win_height - bottom_off);
SelectObject(hdc, tmp);
DeleteObject(br);
}
void draw_right_border(HDC hdc)
{
HBRUSH tmp, br = CreateSolidBrush(borders_colors[COLOR_RIGHT_BORDER + win_is_not_active]);
tmp = (HBRUSH)SelectObject(hdc, br);
Rectangle(hdc, win_width - right_off, top_off, win_width, win_height - bottom_off);
SelectObject(hdc, tmp);
DeleteObject(br);
}
void draw_bottom_border(HDC hdc)
{
HBRUSH tmp, br = CreateSolidBrush(borders_colors[COLOR_BOTTOM_BORDER + win_is_not_active]);
tmp = (HBRUSH)SelectObject(hdc, br);
Rectangle(hdc, 0, win_height - bottom_off, win_width, win_height);
SelectObject(hdc, tmp);
DeleteObject(br);
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_SIZE:
{
RECT rect;
HRGN rgn;
GetWindowRect(hwnd, &rect);
win_x = rect.left;
win_y = rect.top;
win_width = rect.right - rect.left;
win_height = rect.bottom - rect.top;
//
// I use this to set a rectangular region for the window, and not a round-rect one.
//
rgn = CreateRectRgn(0,0, rect.right, rect.bottom);
SetWindowRgn(hwnd, rgn, TRUE);
DeleteObject(rgn);
}
break;
case WM_PAINT:
{
printf("WM_PAINT\n");
PAINTSTRUCT ps;
HDC hdc;
HBRUSH hb;
RECT rect;
hdc = BeginPaint(hwnd, &ps);
hb = CreateSolidBrush(RGB(rand()%255,rand()%255,rand()%255));
GetClientRect(hwnd, &rect);
FillRect(hdc, &rect, hb);
DeleteObject(hb);
EndPaint(hwnd, &ps);
break;
}
case WM_NCPAINT:
{
printf("WM_NCPAINT\n");
HDC hdc;
HBRUSH br;
RECT rect;
HRGN rgn = (HRGN)wparam;
if ((wparam == 0) || (wparam == 1))
hdc = GetWindowDC(hwnd);
else
hdc = GetDCEx(hwnd, (HRGN)wparam, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE|DCX_INTERSECTRGN);
draw_titlebar(hdc);
draw_left_border(hdc);
draw_right_border(hdc);
draw_bottom_border(hdc);
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_NCACTIVATE:
if (wparam)
win_is_not_active = 0;
else
win_is_not_active = 1;
// Force paint our non-client area otherwise Windows will paint its own.
SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED);
//RedrawWindow(hwnd, 0, 0, RDW_FRAME | RDW_UPDATENOW | RDW_NOCHILDREN);
return 0;
case WM_NCCALCSIZE:
{
if (wparam)
{
NCCALCSIZE_PARAMS * ncparams = (NCCALCSIZE_PARAMS *)lparam;
printf("WM_NCCALCSIZE wparam:True\n");
ncparams->rgrc[0].left += left_off;
ncparams->rgrc[0].top += top_off;
ncparams->rgrc[0].right -= right_off;
ncparams->rgrc[0].bottom -= bottom_off;
return 0;
} else {
RECT * rect = (RECT *)lparam;
return 0;
}
}
case WM_NCHITTEST:
{
LRESULT result = DefWindowProc(hwnd, message, wparam, lparam);
switch (result)
{
//
// I have to set this, because i need to draw my own min/max/close buttons
// in different coordinates where the system draws them, so let's consider
// all the titlebar just a tilebar for now, ignoring those buttons.
//
case HTCLOSE:
case HTMAXBUTTON:
case HTMINBUTTON:
case HTSYSMENU:
case HTNOWHERE:
case HTHELP:
case HTERROR:
return HTCAPTION;
default:
return result;
};
}
case WM_ERASEBKGND:
return 1;
default:
return DefWindowProc (hwnd, message, wparam, lparam);
}
return 0;
}
#包括
#包括
LRESULT回调窗口过程(HWND、UINT、WPARAM、LPARAM);
char szClassName[]=“皮肤测试”;
int左/右;
int右键关闭;
int top_off;
int-bottom_-off;
int WINAPI WinMain(HINSTANCE hThisInstance、HINSTANCE HPPreInstance、LPSTR lpszArgument、int nCmdShow)
{
这是我们窗口的手柄*/
MSG messages;/*此处保存应用程序的消息*/
windowclass的WNDCLASSEX wincl;/*数据结构*/
wincl.hInstance=hthis实例;
wincl.lpszClassName=szClassName;
wincl.lpfnWndProc=窗口程序;
wincl.style=CS_DBLCLKS;
wincl.cbSize=sizeof(WNDCLASSEX);
wincl.hIcon=加载图标(空,IDI_应用程序);
wincl.hIconSm=加载图标(空,IDI_应用程序);
wincl.hCursor=LoadCursor(空,IDC_箭头);
wincl.lpszMenuName=NULL;
wincl.cbClsExtra=0;
wincl.cbWndExtra=0;
wincl.hbrBackground=(HBRUSH)颜色背景;
if(!RegisterClass(&wincl))
返回0;
DWORD样式=WS_重叠窗口;
hwnd=CreateWindowEx(
前客户,
szClassName,
“代码::阻止模板Windows应用程序”,
风格
CW_使用默认值,
CW_使用默认值,
500,
500,
HWND_桌面,
无效的
例如,,
无效的
);
//
//这样可以防止重叠窗口的圆形矩形。
//
HRGN rgn=CreateRectRgn(0,0500500);
SetWindowRgn(hwnd、rgn、TRUE);
左=4;
右_off=4;
top_off=23;
底部关闭=4;
显示窗口(hwnd、nCmdShow);
while(GetMessage(&messages,NULL,0,0))
{
翻译消息(和消息);
DispatchMessage(&messages);
}
返回messages.wParam;
}
#定义颜色标题栏0
#定义颜色\u左\u边框2
#定义颜色\u右\u边框4
#定义颜色\u底部\u边框6
int win_x,win_y,win_宽度,win_高度;
int win_未激活=0;
COLORREF边框颜色[]=
{
RGB(255255,0),RGB(180180,0),//活动标题栏-非活动标题栏
RGB(0255255),RGB(0180180),//活动左边框-非活动左边框
RGB(255,0255),RGB(180,0180),//活动右边框-非活动右边框
RGB(255,0,0),RGB(180,0,0)//活动底边框-非活动底边框
};
无效绘制标题栏(HDC HDC)
{
HBRUSH tmp,br=CreateSolidBrush(边框颜色[颜色标题栏+赢]处于非活动状态];
tmp=(HBRUSH)选择对象(hdc,br);
矩形(hdc,0,0,赢得宽度,顶部关闭);
选择对象(hdc、tmp);
删除对象(br);
}
无效绘制左边框(HDC HDC)
{
HBRUSH tmp,br=CreateSolidBrush(边框颜色[颜色左边框+赢边框处于非活动状态]);
tmp=(HBRUSH)选择对象(hdc,br);
矩形(hdc,0,顶部关闭,左侧关闭,赢得高度-底部关闭);
选择对象(hdc、tmp);
删除对象(br);
}
无效绘制右边框(HDC HDC)
{
HBRUSH tmp,br=CreateSolidBrush(边框颜色[颜色右边框+赢边框处于非活动状态]);
tmp=(HBRUSH)选择对象(hdc,br);
矩形(hdc,宽度-右关闭,顶部关闭,宽度,高度-底部关闭);
选择对象(hdc、tmp);
删除对象(br);
}
无效绘制底部边框(HDC HDC)
{
HBRUSH tmp,br=CreateSolidBrush(边框颜色[颜色底部边框+赢色处于非活动状态]);
tmp=(HBRUSH)选择对象(hdc,br);
矩形(hdc,0,赢得高度-底部关闭,赢得宽度,赢得高度);
选择对象(hdc、tmp);
删除对象(br);
}
LRESULT回调窗口过程(HWND HWND,UINT消息,WPARAM WPARAM,LPARAM LPARAM)
{
开关(信息)
{
案例WM_销毁:
PostQuitMessage(0);
打破
案例WM_大小:
{
RECT-RECT;
HRGN-rgn;
GetWindowRect(hwnd和&rect);
win_x=矩形左;
win_y=rec