原文
先取出上篇文章的代码并找到CreateLayeredWindow
函数.
//创建分层窗口
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colBGRA)
{//注册分层窗口RegWindow(hInstance, L"LayeredWindow", DefWindowProc, BLACK_BRUSH);//创建分层窗口HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, hWnd, NULL, hInstance, NULL);//将分层窗口设为本窗口的子窗口SetParent(hLayeredWindow, hWnd);//更新分层窗口,//创建分层窗口的`DC`HDC hLayeredWindowDC = GetDC(hLayeredWindow);HDC hCompatibleDC = CreateCompatibleDC(hLayeredWindowDC);//填充`BLENDFUNCTION`结构BLENDFUNCTION blend = { 0 };blend.BlendOp = AC_SRC_OVER;blend.SourceConstantAlpha = 255;blend.AlphaFormat = AC_SRC_ALPHA;//控制显示位置POINT ptDst = { iPosX, iPosY };//控制窗口大小SIZE sizeWnd = { iWidth, iHeight };//为0就行POINT pSrc = { 0, 0 };//创建一副与当前`DC`兼容的位图HBITMAP hCustomBmp = NULL;hCustomBmp = CreateCompatibleBitmap(hLayeredWindowDC, iWidth, iHeight);//指定`hCustomBmp`到`hCompatibleDC`中SelectObject(hCompatibleDC, hCustomBmp);//填充`bmpInfo`BITMAPINFO bmpInfo = { 0 };bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmpInfo.bmiHeader.biWidth = iWidth;bmpInfo.bmiHeader.biHeight = iHeight;bmpInfo.bmiHeader.biPlanes = 1;bmpInfo.bmiHeader.biCompression = BI_RGB;bmpInfo.bmiHeader.biBitCount = 32;//设置位图中的像素SetDIBits(NULL, hCustomBmp, 0, iHeight, colBGRA, &bmpInfo, DIB_RGB_COLORS);//更新分层窗口UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);//释放`DC`DeleteDC(hLayeredWindowDC);return hLayeredWindow;
}
为了方便,需要把colBGRA
中的像素点数据从BGRA
为转换为RGBA
.
因此需要翻转RGB
值的函数,代码如下:
void TurnRGB(COLORREF* srcCols, COLORREF* tagCols, DWORD dwSize, DWORD dwWidth)
{if (!srcCols || !tagCols || dwSize <= dwWidth || dwSize % dwWidth != 0)//若`srcCols`或`tagCols`为`NULL`,意为没有要翻转`源数据`或没有存储翻转后数据的保存地址
//`dwSize<=dwWidth`表明数据宽度大于数据总大小,如何`0w0`,`dwSize%dwWidth! =0`表明像素点数据若以`dwWidth`为一行的个数,则无法拼成一个矩形,无法构成一个完整的窗口.return;DWORD dwHeight = dwSize / dwWidth;//计算高度for (DWORD index = 0; index < dwSize; index++)//遍历每个像素点并翻转操作{//`col`来存储当前像素点的数据COLORREF col = srcCols[index];//翻转`RGB`值tagCols[index] = RGBA((BYTE)(col >> 16), (BYTE)(col >> 8), (BYTE)col, (BYTE)(col >> 24));}
}
1,srcCols
:像素点数据
2,tagCols
:接收像素点翻转后的数据的变量
3,dwSize
:像素大小(总数量)
4,dwWidth
:像素点数据宽度(就是分层窗口的宽)
在CreateLayeredWindow
前放置上面函数
,以方便调用,然后就可小小的改动CreateLayeredWindow
:
//创建分层窗口
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colRGBA)
//将变量名`colBGRA`改为`colRGBA`
{DWORD dwColSize = iWidth * iHeight;COLORREF* colBGRA = new COLORREF[dwColSize];TurnRGB(colRGBA, colBGRA, dwColSize, iWidth);//注册分层窗口RegWindow(hInstance, L"LayeredWindow", DefWindowProc, BLACK_BRUSH);//创建分层窗口HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, hWnd, NULL, hInstance, NULL);//将分层窗口设为本窗口的子窗口SetParent(hLayeredWindow, hWnd);//更新分层窗口//创建分层窗口的`DC`HDC hLayeredWindowDC = GetDC(hLayeredWindow);HDC hCompatibleDC = CreateCompatibleDC(hLayeredWindowDC);//填充`BLENDFUNCTION`结构BLENDFUNCTION blend = { 0 };blend.BlendOp = AC_SRC_OVER;blend.SourceConstantAlpha = 255;blend.AlphaFormat = AC_SRC_ALPHA;//控制显示位置POINT ptDst = { iPosX, iPosY };//控制窗口大小SIZE sizeWnd = { iWidth, iHeight };//为0就行POINT pSrc = { 0, 0 };//创建一个与当前`DC`兼容的位图HBITMAP hCustomBmp = NULL;hCustomBmp = CreateCompatibleBitmap(hLayeredWindowDC, iWidth, iHeight);//在`hCompatibleDC`中指定`hCustomBmp`SelectObject(hCompatibleDC, hCustomBmp);//填充`bmpInfo`BITMAPINFO bmpInfo = { 0 };bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmpInfo.bmiHeader.biWidth = iWidth;bmpInfo.bmiHeader.biHeight = iHeight;bmpInfo.bmiHeader.biPlanes = 1;bmpInfo.bmiHeader.biCompression = BI_RGB;bmpInfo.bmiHeader.biBitCount = 32;//设置位图中的像素SetDIBits(NULL, hCustomBmp, 0, iHeight, colBGRA, &bmpInfo, DIB_RGB_COLORS);//..//更新分层窗口UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);//...//释放`DC`DeleteDC(hLayeredWindowDC);return hLayeredWindow;
}
这样就可直接传入RGBA
值,而不必先翻转RGBA
值为BGRA
值再传入了.
然后找到CreateLayeredWindow
函数里的这一行:
//注册分层窗口
RegWindow(hInstance, L"LayeredWindow", WindowProc, BLACK_BRUSH);
把"WindowProc"
改为"DefWindowProc"
.
//注册分层窗口
RegWindow(hInstance, L"LayeredWindow", DefWindowProc, BLACK_BRUSH);
分层窗口
并不需要自己的窗口过程函数
,用微软提供的就行.
然后找到这一行:
//创建分层窗口
HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, NULL, NULL, hInstance, NULL);
倒数第四个参数改为hWnd
:
//创建分层窗口
HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, hWnd, NULL, hInstance, NULL);
这样调用GetParent
函数时,就不会出错返回无效
了,这里.
接着找到WinMain
函数:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
{//注册窗口RegWindow(hInstance, L"WINDOW", WindowProc, WHITE_BRUSH);//创建窗口HWND hWnd = CreateWindow(L"WINDOW", 0,WS_OVERLAPPEDWINDOW, 100, 100, 800, 500, NULL, NULL, hInstance, NULL);//显示窗口ShowWindow(hWnd, SW_SHOW);//更新窗口UpdateWindow(hWnd);//创建`BGRA`数据COLORREF* colBGRA = new COLORREF[100 * 100];//初化ZeroMemory(colBGRA, 100 * 100 * sizeof(COLORREF));//填充半透明蓝色for (int i = 0; i < 100 * 100; i++){//虽然用的是`RGBA`,但实际上是`BGRA`colBGRA[i] = RGBA(233, 0, 0, 128);// `R G B A`}//创建分层窗口HWND hLW = CreateLayeredWindow(hInstance, hWnd, 100, 100, 0, 0, colBGRA);//..//消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);} return 0;
}
删除或注解掉14~28
行的代码
.
...//更新窗口UpdateWindow(hWnd);MSG msg;
...
现在完整代码
应该如下:
#include <windows.h>#define RGBA(r,g,b,a) (COLORREF)(((BYTE)(r) |((WORD)((BYTE)(g)) << 8)) |(((DWORD)((BYTE)(b)) << 16)) |(((DWORD)((BYTE)(a)) << 24)))//窗口过程函数
LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{switch (Msg){case WM_DESTROY:PostQuitMessage(0);return 0;default:return DefWindowProc(hWnd, Msg, wParam, lParam);}return 0;
}
//注册窗口函数
void RegWindow(HINSTANCE hInstance, LPCWSTR lpClassName, WNDPROC wndProc, DWORD dwColor)
{WNDCLASS wnd;wnd.cbClsExtra = 0;wnd.cbWndExtra = 0;wnd.hbrBackground = (HBRUSH)(GetStockObject(dwColor));wnd.hCursor = LoadCursor(NULL, IDC_ARROW);wnd.hIcon = LoadCursor(NULL, IDI_APPLICATION);wnd.lpfnWndProc = wndProc;wnd.lpszClassName = lpClassName;wnd.lpszMenuName = NULL;wnd.style = CS_HREDRAW;wnd.hInstance = hInstance;RegisterClass(&wnd);
}
void TurnRGB(COLORREF* srcCols, COLORREF* tagCols, DWORD dwSize, DWORD dwWidth)
{if (!srcCols || !tagCols || dwSize <= dwWidth || dwSize % dwWidth != 0)return;//略注释.DWORD dwHeight = dwSize / dwWidth;//计算高度for (DWORD index = 0; index < dwSize; index++)//遍历每个像素点并翻转操作{//`col`来存储当前像素点的数据COLORREF col = srcCols[index];//翻转`RGB`值tagCols[index] = RGBA((BYTE)(col >> 16), (BYTE)(col >> 8), (BYTE)col, (BYTE)(col >> 24));}
}
//创建分层窗口
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colRGBA)
//将变量名`colBGRA`改为`colRGBA`
{DWORD dwColSize = iWidth * iHeight;COLORREF* colBGRA = new COLORREF[dwColSize];TurnRGB(colRGBA, colBGRA, dwColSize, iWidth);//注册分层窗口RegWindow(hInstance, L"LayeredWindow", DefWindowProc, BLACK_BRUSH);//创建分层窗口HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, hWnd, NULL, hInstance, NULL);//将分层窗口设为本窗口的子窗口SetParent(hLayeredWindow, hWnd);//更新分层窗口//创建分层窗口的`DC`HDC hLayeredWindowDC = GetDC(hLayeredWindow);HDC hCompatibleDC = CreateCompatibleDC(hLayeredWindowDC);//填充`BLENDFUNCTION`结构BLENDFUNCTION blend = { 0 };blend.BlendOp = AC_SRC_OVER;blend.SourceConstantAlpha = 255;blend.AlphaFormat = AC_SRC_ALPHA;//控制显示位置POINT ptDst = { iPosX, iPosY };//控制窗口大小SIZE sizeWnd = { iWidth, iHeight };//为0就行POINT pSrc = { 0, 0 };//创建一副与当前`DC`兼容的位图HBITMAP hCustomBmp = NULL;hCustomBmp = CreateCompatibleBitmap(hLayeredWindowDC, iWidth, iHeight);//指定`hCustomBmp`到`hCompatibleDC`中SelectObject(hCompatibleDC, hCustomBmp);//填充`bmpInfo`BITMAPINFO bmpInfo = { 0 };bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmpInfo.bmiHeader.biWidth = iWidth;bmpInfo.bmiHeader.biHeight = iHeight;bmpInfo.bmiHeader.biPlanes = 1;bmpInfo.bmiHeader.biCompression = BI_RGB;bmpInfo.bmiHeader.biBitCount = 32;//设置位图中的像素SetDIBits(NULL, hCustomBmp, 0, iHeight, colBGRA, &bmpInfo, DIB_RGB_COLORS);//更新分层窗口UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);//释放`DC`DeleteDC(hLayeredWindowDC);return hLayeredWindow;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
{//注册窗口RegWindow(hInstance, L"WINDOW", WindowProc, WHITE_BRUSH);//创建窗口HWND hWnd = CreateWindow(L"WINDOW", 0,WS_OVERLAPPEDWINDOW, 100, 100, 800, 500, NULL, NULL, hInstance, NULL);//显示窗口ShowWindow(hWnd, SW_SHOW);//更新窗口UpdateWindow(hWnd);MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);} return 0;
}
悬停效果
取360
做示例
其实就是点击一个按钮
后有一个框
框住了按钮
的效果,该效果用来实现三态按钮
.如果用纯win32
按正常的思路设计会比较麻烦,但用分层窗口
就会比较容易.
因为win32
的按钮要检测鼠标悬停
,无论是原版按钮还是自绘按钮
,都比较麻烦
.
思路
要先创建几个按钮
,然后检测到按下按钮
后就移动分层窗口
到该按钮
上,而移动窗口
需要MoveWindow
函数.这里
BOOL MoveWindow([in] HWND hWnd,[in] int X,[in] int Y,[in] int nWidth,[in] int nHeight,[in] BOOL bRepaint
);
1,hWnd
:要移动的窗口的hWnd
2,x,y
:要移动到哪里(新位置的坐标)
3,nWidth,nHeight
:窗口移动后的大小
4,bRepaint
:是否重画
实践
这里先创建4个按钮
,而要在WM_CREATE
消息里创建创建按钮.
而处理按钮
事件需要接收WM_COMMAND
消息
找到主窗口
的窗口过程函数WindowProc
,添加WM_CREATE
与WM_COMMAND
消息并处理.
LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{switch (Msg){case WM_CREATE:{LPCREATESTRUCT pc = (LPCREATESTRUCT)lParam;break;}case WM_COMMAND:{WORD id = LOWORD(wParam);WORD code = HIWORD(wParam);HWND hwnd = (HWND)lParam;break;}case WM_DESTROY:PostQuitMessage(0);return 0;default:return DefWindowProc(hWnd, Msg, wParam, lParam);}return 0;
}
接着创建4个宽为120
,高为150
的按钮,分别叫choice1,choice2,choice3,choice4
,对应的id
分别为1,2,3,4
.
...
case WM_CREATE:
{LPCREATESTRUCT pc = (LPCREATESTRUCT)lParam;HWND hButton1 = CreateWindow(L"BUTTON", L"choice1", WS_CHILD | WS_VISIBLE, 10, 10, 120, 150, hWnd, (HMENU)1, pc->hInstance, NULL);HWND hButton2 = CreateWindow(L"BUTTON", L"choice2", WS_CHILD | WS_VISIBLE, 140, 10, 120, 150, hWnd, (HMENU)2, pc->hInstance, NULL);HWND hButton3 = CreateWindow(L"BUTTON", L"choice3", WS_CHILD | WS_VISIBLE, 270, 10, 120, 150, hWnd, (HMENU)3, pc->hInstance, NULL);HWND hButton4 = CreateWindow(L"BUTTON", L"choice4", WS_CHILD | WS_VISIBLE, 400, 10, 120, 150, hWnd, (HMENU)4, pc->hInstance, NULL);break;
}
...
接着在WM_COMMAND
消息里处理按下按钮
的消息
...
HWND hwnd = (HWND)lParam;
if (id == 1 && code == BN_CLICKED)
{MessageBox(hWnd, L"choice1", L"CLICK", 0);
}
else if (id == 2 && code == BN_CLICKED)
{MessageBox(hWnd, L"choice2", L"CLICK", 0);
}
else if (id == 3 && code == BN_CLICKED)
{MessageBox(hWnd, L"choice3", L"CLICK", 0);
}
else if (id == 4 && code == BN_CLICKED)
{MessageBox(hWnd, L"choice4", L"CLICK", 0);
}
break;
...
接着要创建一个分层窗口
来实现悬停
.
先声明全局变量
,并提前声明CreateLayeredWindow
函数,还要定义一些分层窗口的方便宏.
...#define RGBA(r,g,b,a) (COLORREF)(((BYTE)(r) |((WORD)((BYTE)(g)) << 8)) |(((DWORD)((BYTE)(b)) << 16)) |(((DWORD)((BYTE)(a)) << 24)))#define LAYERED_WINDOW_WIDTH 120 //分层窗口的宽分层窗口的高
#define LAYERED_WINDOW_HEIGHT 150 //声明全局变量来保存分层窗口的句柄
//
HWND hLayeredWindow = NULL;
//也要提前声明`TurnRGB`函数否则会出错
void TurnRGB(COLORREF* srcCols, COLORREF* tagCols, DWORD dwSize, DWORD dwWidth);
//声明`CreateLayeredWindow`函数方便在`WindowProc`函数里使用
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colRGBA);
//窗口过程函数
LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
...
再在WM_CREATE
消息里创建分层窗口
.
...
HWND hButton4 = CreateWindow(L"BUTTON", L"choice4", WS_CHILD | WS_VISIBLE, 400, 10, 120, 150, hWnd, (HMENU)4, pc->hInstance, NULL);
//创建一个红色半透明的像素矩阵
COLORREF* col = new COLORREF[120 * 150];
for (size_t i = 0; i < 120 * 150; i++)
//遍历填充颜色
{col[i] = RGBA(255, 0, 0, 20);
}
//创建分层窗口,在`(10,10)`位置创建,可使`分层窗口`与按钮重合
hLayeredWindow = CreateLayeredWindow(pc->hInstance, hWnd, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, 10, 10, col);
if (!hLayeredWindow)//创建失败就取消创建直接结束窗口SendMessage(hWnd, WM_DESTROY, 0, 0);
break;
...
现在只要用MoveWindow
函数移动分层窗口
就行了
回到WM_COMMAND
消息里,删除或注释掉MessageBox
函数,并使用MoveWindow
函数移动分层窗口
到当前按钮的位置
,代码如下:
...
HWND hwnd = (HWND)lParam;
if (id == 1 && code == BN_CLICKED)
{//`MessageBox(hWnd,L"choice1",L"CLICK",0);`移动分层窗口到当前按钮位置,保持宽高不变,重画窗口,下同MoveWindow(hLayeredWindow, 10, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);
}
else if (id == 2 && code == BN_CLICKED)
{//`MessageBox(hWnd,L"choice2",L"CLICK",0);`MoveWindow(hLayeredWindow, 140, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);
}
else if (id == 3 && code == BN_CLICKED)
{//`MessageBox(hWnd,L"choice3",L"CLICK",0);`MoveWindow(hLayeredWindow, 270, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);
}
else if (id == 4 && code == BN_CLICKED)
{//`MessageBox(hWnd,L"choice4",L"CLICK",0);`MoveWindow(hLayeredWindow, 400, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);
}
break;
...
至此,一般的悬停效果
就做好了.
完整代码:
#include <windows.h>#define RGBA(r,g,b,a) (COLORREF)(((BYTE)(r) |((WORD)((BYTE)(g)) << 8)) |(((DWORD)((BYTE)(b)) << 16)) |(((DWORD)((BYTE)(a)) << 24)))#define LAYERED_WINDOW_WIDTH 120 //分层窗口的宽分层窗口的高
#define LAYERED_WINDOW_HEIGHT 150 //声明全局变量来保存分层窗口的句柄
//
HWND hLayeredWindow = NULL;
//也要提前声明`TurnRGB`函数否则会出错
void TurnRGB(COLORREF* srcCols, COLORREF* tagCols, DWORD dwSize, DWORD dwWidth);
//声明`CreateLayeredWindow`函数方便在`WindowProc`函数里使用
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colRGBA);
//窗口过程函数
LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{switch (Msg){case WM_CREATE:{LPCREATESTRUCT pc = (LPCREATESTRUCT)lParam;HWND hButton1 = CreateWindow(L"BUTTON", L"choice1", WS_CHILD | WS_VISIBLE, 10, 10, 120, 150, hWnd, (HMENU)1, pc->hInstance, NULL);HWND hButton2 = CreateWindow(L"BUTTON", L"choice2", WS_CHILD | WS_VISIBLE, 140, 10, 120, 150, hWnd, (HMENU)2, pc->hInstance, NULL);HWND hButton3 = CreateWindow(L"BUTTON", L"choice3", WS_CHILD | WS_VISIBLE, 270, 10, 120, 150, hWnd, (HMENU)3, pc->hInstance, NULL);HWND hButton4 = CreateWindow(L"BUTTON", L"choice4", WS_CHILD | WS_VISIBLE, 400, 10, 120, 150, hWnd, (HMENU)4, pc->hInstance, NULL);//创建一个红色半透明的像素矩阵COLORREF* col = new COLORREF[120 * 150];for (size_t i = 0; i < 120 * 150; i++)//遍历填充颜色{col[i] = RGBA(255, 0, 0, 20);}//创建分层窗口,在`(10,10)`位置创建,可使分层窗口与按钮重合//hLayeredWindow = CreateLayeredWindow(pc->hInstance, hWnd, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, 10, 10, col);if (!hLayeredWindow)//创建失败就取消创建直接结束窗口SendMessage(hWnd, WM_DESTROY, 0, 0);break;}case WM_COMMAND:{WORD id = LOWORD(wParam);WORD code = HIWORD(wParam);HWND hwnd = (HWND)lParam;if (id == 1 && code == BN_CLICKED){//`MessageBox(hWnd,L"choice1",L"CLICK",0);`移动分层窗口到当前按钮位置,保持宽高不变,重画窗口,下同MoveWindow(hLayeredWindow, 10, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);}else if (id == 2 && code == BN_CLICKED){//`MessageBox(hWnd,L"choice2",L"CLICK",0);`MoveWindow(hLayeredWindow, 140, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);}else if (id == 3 && code == BN_CLICKED){//`MessageBox(hWnd,L"choice3",L"CLICK",0);`MoveWindow(hLayeredWindow, 270, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);}else if (id == 4 && code == BN_CLICKED){//`MessageBox(hWnd,L"choice4",L"CLICK",0);`MoveWindow(hLayeredWindow, 400, 10, LAYERED_WINDOW_WIDTH, LAYERED_WINDOW_HEIGHT, TRUE);}break;}case WM_DESTROY:PostQuitMessage(0);return 0;default:return DefWindowProc(hWnd, Msg, wParam, lParam);}return 0;
}
//注册窗口函数
void RegWindow(HINSTANCE hInstance, LPCWSTR lpClassName, WNDPROC wndProc, DWORD dwColor)
{WNDCLASS wnd;wnd.cbClsExtra = 0;wnd.cbWndExtra = 0;wnd.hbrBackground = (HBRUSH)(GetStockObject(dwColor));wnd.hCursor = LoadCursor(NULL, IDC_ARROW);wnd.hIcon = LoadCursor(NULL, IDI_APPLICATION);wnd.lpfnWndProc = wndProc;wnd.lpszClassName = lpClassName;wnd.lpszMenuName = NULL;wnd.style = CS_HREDRAW;wnd.hInstance = hInstance;RegisterClass(&wnd);
}
void TurnRGB(COLORREF* srcCols, COLORREF* tagCols, DWORD dwSize, DWORD dwWidth)
{if (!srcCols || !tagCols || dwSize <= dwWidth || dwSize % dwWidth != 0)return;DWORD dwHeight = dwSize / dwWidth;//计算高度for (DWORD index = 0; index < dwSize; index++)//遍历每个像素点并翻转操作{//`col`来存储当前像素点的数据COLORREF col = srcCols[index];//翻转`RGB`值tagCols[index] = RGBA((BYTE)(col >> 16), (BYTE)(col >> 8), (BYTE)col, (BYTE)(col >> 24));}
}
//创建分层窗口
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colRGBA)
//将变量名`colBGRA`改为`colRGBA`
{DWORD dwColSize = iWidth * iHeight;COLORREF* colBGRA = new COLORREF[dwColSize];TurnRGB(colRGBA, colBGRA, dwColSize, iWidth);//注册分层窗口RegWindow(hInstance, L"LayeredWindow", DefWindowProc, BLACK_BRUSH);//创建分层窗口HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, hWnd, NULL, hInstance, NULL);//将分层窗口设为本窗口的子窗口SetParent(hLayeredWindow, hWnd);//更新分层窗口//创建分层窗口的`DC`HDC hLayeredWindowDC = GetDC(hLayeredWindow);HDC hCompatibleDC = CreateCompatibleDC(hLayeredWindowDC);//填充`BLENDFUNCTION`结构BLENDFUNCTION blend = { 0 };blend.BlendOp = AC_SRC_OVER;blend.SourceConstantAlpha = 255;blend.AlphaFormat = AC_SRC_ALPHA;//控制显示位置POINT ptDst = { iPosX, iPosY };//控制窗口大小SIZE sizeWnd = { iWidth, iHeight };//为0就行POINT pSrc = { 0, 0 };//创建一副与当前`DC`兼容的位图HBITMAP hCustomBmp = NULL;hCustomBmp = CreateCompatibleBitmap(hLayeredWindowDC, iWidth, iHeight);//指定`hCustomBmp`到`hCompatibleDC`中SelectObject(hCompatibleDC, hCustomBmp);//填充`bmpInfo`BITMAPINFO bmpInfo = { 0 };bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmpInfo.bmiHeader.biWidth = iWidth;bmpInfo.bmiHeader.biHeight = iHeight;bmpInfo.bmiHeader.biPlanes = 1;bmpInfo.bmiHeader.biCompression = BI_RGB;bmpInfo.bmiHeader.biBitCount = 32;//设置位图中的像素SetDIBits(NULL, hCustomBmp, 0, iHeight, colBGRA, &bmpInfo, DIB_RGB_COLORS);//更新分层窗口UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);//释放`DC`DeleteDC(hLayeredWindowDC);return hLayeredWindow;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR lpCmdLine, int nCmdShow)
{//注册窗口RegWindow(hInstance, L"WINDOW", WindowProc, WHITE_BRUSH);//创建窗口HWND hWnd = CreateWindow(L"WINDOW", 0,WS_OVERLAPPEDWINDOW, 100, 100, 800, 500, NULL, NULL, hInstance, NULL);//显示窗口ShowWindow(hWnd, SW_SHOW);//更新窗口UpdateWindow(hWnd);MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);} return 0;
}
当然,还可添加滑动效果
让它更高级一点
,