C++ 使用子窗口(控件)创建分层窗口的策略
我想创建一个形状不规则/蒙皮不规则的窗口(目前仅使用圆角、alpha混合角)。创建顶级窗口后,我将处理WM_CREATE消息,并执行以下操作:C++ 使用子窗口(控件)创建分层窗口的策略,c++,winapi,alpha,layered,C++,Winapi,Alpha,Layered,我想创建一个形状不规则/蒙皮不规则的窗口(目前仅使用圆角、alpha混合角)。创建顶级窗口后,我将处理WM_CREATE消息,并执行以下操作: 创建一个兼容的内存DC 创建与窗口DC兼容的DIB节 在内存DC中选择DIB 画我的背景 应用alpha通道和预乘RGB值 调用UpdateLayeredWindow() 稍后,我计划通过设置alpha通道并对相关位进行预乘来实现边缘的圆角 现在,如果我在我的窗口中创建一个按钮,它将不会自己渲染。我知道为什么,我正试图想出一个优雅的解决方案来制作我的自定
static BOOL CALLBACK MyPaintCallback(HWND hChild,LPARAM lParam) {
SendMessage(hChild,WM_PRINT,(WPARAM)lParam,(LPARAM)(PRF_CHECKVISIBLE|PRF_CHILDREN|PRF_CLIENT));
return TRUE;
}
void MyPaintMethod(HWND hWnd) {
//steps 1-5
EnumChildWindows(hWnd,MyPaintCallback,MyMemoryDC);
//step 6
}
CPaintDC dc(this);
OnDraw(&dc);
引述:
WM_PAINT消息由系统生成,不应由应用程序发送。要强制窗口绘制到特定的设备上下文中,请使用WM_PRINT或WM_PRINTCLIENT消息。请注意,这需要目标窗口支持WM_PRINTCLIENT消息。大多数常用控件支持WM_PRINTCLIENT消息
因此,看起来您可以在步骤5和步骤6之间使用内存DC遍历所有子窗口并发送它们
它看起来像这样:
static BOOL CALLBACK MyPaintCallback(HWND hChild,LPARAM lParam) {
SendMessage(hChild,WM_PRINT,(WPARAM)lParam,(LPARAM)(PRF_CHECKVISIBLE|PRF_CHILDREN|PRF_CLIENT));
return TRUE;
}
void MyPaintMethod(HWND hWnd) {
//steps 1-5
EnumChildWindows(hWnd,MyPaintCallback,MyMemoryDC);
//step 6
}
CPaintDC dc(this);
OnDraw(&dc);
我想我会选择这个解决方案: 顶层窗口 顶层窗口维护两个位图。一个是显示的窗口,另一个没有呈现任何子控件。后者只需要在窗口大小改变时重新绘制。窗口将有一个消息处理程序,用于在显示的位图上呈现子控件。消息处理程序将期望一个指向包含子控件的DIB或实际位(目前不确定哪一位最好)的指针作为WPARAM,以及一个指向包含子控件应作为LPRAM绘制的矩形的结构的指针。在AlphaBlend()调用将子控件位图渲染到显示的位图表面之前,将调用BitBlt()清除底层表面(这是其他位图的位置) 每当调整父窗口的大小或出于某种原因需要重新绘制其子窗口时,父窗口将调用EnumChildWindows。当然,这里可能会强制执行某种无效机制,以减少子控件的不必要渲染。不过,我不确定提速是否值得 子窗口 创建子控件实例时,将创建与顶级窗口的位图兼容的内部位图。子对象将自己呈现到该内部位图中,每当需要重画时,它都会通过SendMessage()函数通知其父窗口,并将指向其位图的指针作为WPARAM传递,将RECT作为定义其位置和尺寸的LPRAM传递。如果父窗口需要重画,它会向其所有子窗口发出一条消息,请求它们的位图。当孩子们决定需要重新画自己的时候,他们会用他们通常会发出的同样的信息来回应
Eirik我想我会选择这个解决方案: 顶层窗口 顶层窗口维护两个位图。一个是显示的窗口,另一个没有呈现任何子控件。后者只需要在窗口大小改变时重新绘制。窗口将有一个消息处理程序,用于在显示的位图上呈现子控件。消息处理程序将期望一个指向包含子控件的DIB或实际位(目前不确定哪一位最好)的指针作为WPARAM,以及一个指向包含子控件应作为LPRAM绘制的矩形的结构的指针。在调用AlphaBlend()渲染子控件位图之前,将调用BitBlt()清除底层表面(这是其他位图的位置)
BEGIN_MESSAGE_MAP(MyButton, CButton)
...other messages
ON_MESSAGE(WM_PRINT, OnPrint)
END_MESSAGE_MAP()
LRESULT MyButton::OnPrint(WPARAM wParam, LPARAM lParam) {
CDC* dc = CDC::FromHandle((HDC)wParam);
OnDraw(dc);
return 0;
}
LRESULT MyCWnd::OnPrint(WPARAM wParam, LPARAM lParam) {
CDC* dc = CDC::FromHandle((HDC)wParam);
// Do my own drawing using custom drawing
OnDraw(dc);
// And get the default handler to draw children
return Default();
}
// This method is not very efficient but the CBitmap class doens't
// give me a choice I have to copy all the pixel data out, process it and set it back again.
// For performance I recommend using another bitmap class
//
// This method makes every pixel have an opacity of 255 (fully opaque).
void Vg2pImageHeaderRibbon::ClearBackgroundAndPrepForPerPixelTransparency(
CDC& dc, const BITMAP& raw_bitmap, int bytes, char* bits, CBitmap& dc_buffer
) {
CRect rect;
GetClientRect(&rect);
dc.FillSolidRect(0, 0, rect.Width(), rect.Height(), RGB(0,0,0));
dc_buffer.GetBitmapBits(bytes, bits);
UINT* pixels = reinterpret_cast<UINT*>(bits);
for (int c = 0; c < raw_bitmap.bmWidth * raw_bitmap.bmHeight; c++ ){
pixels[c] |= 0xff000000;
}
dc_buffer.SetBitmapBits(bytes, bits);
}
// This method is not very efficient but the CBitmap class doens't
// give me a choice I have to copy all the pixel data out, process it and set it back again.
// For performance I recommend using another bitmap class
//
// This method modifies the opacity value because we know GDI drawing always sets
// the opacity to 0 we find all pixels that have been drawn on since we called
// For performance I recommend using another bitmap class such as the IcfMfcRasterImage
// ClearBackgroundAndPrepForPerPixelTransparency. Anything that has been drawn on will get an
// opacity of 255 and all untouched pixels will get an opacity of 100.
void Vg2pImageHeaderRibbon::CorrectPerPixelAlpha(
CDC& dc, const BITMAP& raw_bitmap, int bytes, char* bits, CBitmap& dc_buffer
) {
const unsigned char AlphaForBackground = 100; // (0 - 255)
const int AlphaForBackgroundWord = AlphaForBackground << 24;
dc_buffer.GetBitmapBits(bytes, bits);
UINT* pixels = reinterpret_cast<UINT*>(bits);
for (int c = 0; c < raw_bitmap.bmWidth * raw_bitmap.bmHeight; c++ ){
if ((pixels[c] & 0xff000000) == 0) {
pixels[c] |= 0xff000000;
} else {
pixels[c] = (pixels[c] & 0x00ffffff) | AlphaForBackgroundWord;
}
}
dc_buffer.SetBitmapBits(bytes, bits);
}