当前位置: 首页 > news >正文

2408gui,分层窗口1

原文

前言

分层窗口,功能非常强大,可轻易实现一些比较漂亮的UI接口.

UpdateLayeredWindow函数

UpdateLayeredWindow函数作用是更新一个分层窗口,是分层窗口核心,定义如下:

//更新分层窗口的位置,大小,形状,内容和透明度
BOOL UpdateLayeredWindow([in]           HWND          hWnd,[in, optional] HDC           hdcDst,[in, optional] POINT         *pptDst,[in, optional] SIZE          *psize,[in, optional] HDC           hdcSrc,[in, optional] POINT         *pptSrc,[in]           COLORREF      crKey,[in, optional] BLENDFUNCTION *pblend,[in]           DWORD         dwFlags
);

1,hWnd:分层窗口的句柄
2,hdcDst:屏幕DC的句柄
3,pptDst:分层窗口的位置
4,psize:分层窗口的新大小
5,hdcSrc:分层窗口的图面DC的句柄
6,pptSrc:指定层在设环中的位置
7,crKey:指定要在组合分层窗口时使用的颜色键
8,pblend:指定要在组合分层窗口时使用的透明度值

dwFlags:此参数的取值可为下列值之一:

含义
ULW_ALPHA,0x00000002混合函数使用pblend.如果显示模式为256种或更少颜色,则此值的效果与ULW_OPAQUE的效果相同.
ULW_COLORKEY,0x00000001透明度颜色使用crKey.
ULW_OPAQUE,0x00000004绘画不透明的分层窗口.
ULW_EX_NORESIZE,0x00000008如果当前窗口大小psize中指定的大小不匹配,则强制UpdateLayeredWindowIndirect函数失败.
这里

首先需要一个分层窗口,为了方便可以先创建一个简单win32窗口

//注册窗口
{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);
}
//窗口过程函数
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;
}
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, 300, 300, NULL, NULL, hInstance, NULL);//宽高,显示窗口ShowWindow(hWnd, SW_SHOW);//更新窗口UpdateWindow(hWnd);//消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

这样就创建了一个宽和高300,白色背景普通窗口.
接着就是创建一个分层窗口,为了方便,可直接在消息循环前,创建.
创建分层窗口要用CreateWindowExW函数,比较简单,直接上代码,这里.

...
//更新窗口
UpdateWindow(hWnd);
//创建分层窗口
//注册分层窗口
RegWindow(hInstance, L"LayeredWindow", WindowProc, BLACK_BRUSH);
//创建分层窗口
HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, 100, 100, NULL, NULL, hInstance, NULL);
//将分层窗口设为本窗口的子窗口
SetParent(hLayeredWindow, hWnd);
//消息循环
MSG msg;
...

这样就创建了一个宽和高100,黑色背景的普通窗口.
但运行程序后会发现并无黑色窗口,这是因为更新分层窗口需要用UpdateLayeredWindow函数,现在应该考虑怎么使用该函数了.

...
//将分层窗口设为本窗口的子窗口
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 = { 0, 0 };
//控制窗口大小
SIZE sizeWnd = { 100, 100 };
//为0就行
POINT pSrc = { 0, 0 };
//更新分层窗口
UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);
//释放`DC`
DeleteDC(hLayeredWindowDC);
DeleteDC(hCompatibleDC);
//消息循环
MSG msg;
...

它的第一个和第二个参数很简单,只需要填分层窗口句柄和对应的DC就行了,对应的DC可用GetDC函数取.

第三个参数控制分层窗口显示位置,第四个参数控制分层窗口大小,第五个参数为用CreateCompatibleDC函数取的DC,第六个一般填为零的POINT结构,第七个为无效就行,第八个填BLENDFUNCTION结构比较简单,最后参数填ULW_ALPHA,使窗口可设置透明度.

运行程序后发现窗口上并未出现黑色窗口,可用GetLastError函数查看错误码.

...
//为0就行
POINT pSrc = { 0, 0 };
//更新分层窗口
int e1 = GetLastError();
UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);
int e2 = GetLastError();
//释放`DC`
DeleteDC(hLayeredWindowDC);
...

运行程序后可发现e1的值为0,就可排除在更新分层窗口前错误的可能,e2的值为31,意为"连到系统上的设备没有有效"

SetDIBits函数

为了解决上述问题,要用setDIBits函数设置像素,它的定义如下

int SetDIBits([in] HDC              hdc,[in] HBITMAP          hbm,[in] UINT             start,[in] UINT             cLines,[in] const VOID       *lpBits,[in] const BITMAPINFO *lpbmi,[in] UINT             ColorUse
);

它的功能是使用指定DIB中找到的颜色数据,在兼容位图上设置像素.就是给一个Bitmap填充像素.

第一个参数设环的句柄,可直接填NULL;第二个参数是一个位图句柄,只需要创建一个位图传进去就行了;第三个参数直接填0,意为从0开始读取并填充;

第四个参数填要显示的窗口的高度,如果以左上角为原点,此值需要为负数;第五个参数是RGB数组的指针,控制每个像素的颜色与透明度,第六个参数是一个BITMAPINFO结构,里面还有一个BITMAPINFOHEADER结构都比较简单,最后参数必须是以下值之一
位图
位图头

含义
DIB_PAL_COLORS颜色表包含一个由16位索引组成的,在由hdc参数标识的设环的逻辑调色板中包含的数组.
DIB_RGB_COLORS提供颜色表,并包含文本RGB

接着就可直接上代码

...
//为0就行
POINT pSrc = { 0, 0 };
//创建一副与当前`DC`兼容的位图
HBITMAP hCustomBmp = NULL;
hCustomBmp = CreateCompatibleBitmap(hLayeredWindowDC, 100, 100);
//在`hCompatibleDC`中指定`hCustomBmp`
SelectObject(hCompatibleDC, hCustomBmp);
//填充`bmpInfo`
BITMAPINFO bmpInfo = { 0 };
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = 100;
bmpInfo.bmiHeader.biHeight = -(int)100;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biBitCount = 32;
//初化位图
char* datas = new char[100 * 100 * 4];
ZeroMemory(datas, 100 * 100 * 4);
//填充像素
char* pdata = datas;
for (int i = 0; i < 100; i++)
{for (int j = 0; j < 100; j++){//顺序并不是`RGBA`,而是`BGRA`,*pdata = 233;   //蓝*(pdata + 1) = 222; //绿*(pdata + 2) = 233; //红*(pdata + 3) = 233; //透pdata += 4;}
}
//设置位图中的像素
SetDIBits(NULL, hCustomBmp, 0, 100, datas, &bmpInfo, DIB_RGB_COLORS);
//更新分层窗口
...

现在运行程序就可在主窗口上,看见一个类似粉色的正方形了.
这样就创建并显示了一个分层窗口.

接着就要开始封装,来方便创建多个分层窗口.

HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colBGRA)
{//注册分层窗口RegWindow(hInstance, L"LayeredWindow", WindowProc, BLACK_BRUSH);//创建分层窗口HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, NULL, 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);DeleteDC(hCompatibleDC);return hLayeredWindow;
}

1,hInstance:实例句柄
2,hWnd:主窗口句柄
3,iWidth/iHeight:窗口宽高
4,iPosX/iPosY:窗口位置
5,colBGRA:窗口每像素点的信息

RGBABGRA

因为一些特性,SetDIBits函数中RGB数组的指针指向的内容顺序BGRA而不是RGBA
所以colBGRA内容顺序必须是BGRA.

如果你到现在都对RGBABGRA感觉陌生,则接着的示例也许会让你恍然大悟.

//非`win32`窗口程序
#include <windows.h>
int main()
{//`COLORREF`就是存储`RGBA`的数据类型`α`默认为0一个`rgb`COLORREF rgb = RGB(1,2,3);//`bgr`就是把`rgb`反之COLORREF bgr = RGB(3,2,1);//`colBGRA`就是一个存储`多个像素点`的`BGRA`信息的`COLORREF`数组COLORREF bgrs[9];return 0;
}

RGB宏明显不能满足,因为RGB宏它无法改变透明度,所以就需要一个RGBA宏:

#define RGBA(r,g,b,a)          (COLORREF)(((BYTE)(r) |((WORD)((BYTE)(g)) << 8)) |(((DWORD)((BYTE)(b)) << 16)) |(((DWORD)((BYTE)(a)) << 24)))

完整代码:

#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);
}
//创建分层窗口
HWND CreateLayeredWindow(HINSTANCE hInstance, HWND hWnd, int iWidth, int iHeight, int iPosX, int iPosY, COLORREF* colBGRA)
{//创建分层窗口`//`注册分层窗口RegWindow(hInstance, L"LayeredWindow", WindowProc, BLACK_BRUSH);//创建分层窗口HWND hLayeredWindow = CreateWindowEx(WS_EX_LAYERED, L"LayeredWindow", 0,WS_POPUP | WS_BORDER, 0, 0, iWidth, iHeight, NULL, 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, colRGBA, &bmpInfo, DIB_RGB_COLORS);//更新分层窗口UpdateLayeredWindow(hLayeredWindow, hLayeredWindowDC, &ptDst, &sizeWnd, hCompatibleDC, &pSrc, NULL, &blend, ULW_ALPHA);//释放`DC`DeleteDC(hLayeredWindowDC);DeleteDC(hCompatibleDC);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, 300, 300, 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);//`BGRA`}//创建分层窗口HWND hLW = CreateLayeredWindow(hInstance, hWnd, 100, 100, 0, 0, colBGRA);//消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

http://www.mrgr.cn/news/4394.html

相关文章:

  • Android studio制作一个高仿计算器小demo
  • 2024年游泳耳机哪个牌子好?四大热门游泳耳机多维测评盘点!
  • 2024年最新版JavaScript学习笔记【3万字总结】(更新中...)
  • 2024年特种设备作业人员考试题库及答案(流动式起重机Q2)
  • 设计模式-创建型模式-原型模式
  • 制造业如何选择适合的工厂ERP系统?17款ERP系统推荐!
  • centos 虚拟机器刚刚安装没有ip地址的问题
  • 【数据结构算法经典题目刨析(c语言)】使用数组实现循环队列(图文详解)
  • Hystrix——服务容错保护库
  • springboot集成海康sdk,针对视频流获取某一点的实时温度
  • NSSM 注册exe服务
  • Leetcode JAVA刷刷站(55)跳跃游戏
  • SpringBoot文档之入门的阅读笔记
  • 【Solidity】变量与类型
  • 你真的了解《黑神话·悟空》吗?揭秘它背后鲜为人知的故事
  • 速度+耐力,希迪智驾引领中国商用车自动驾驶发展
  • 葡萄参考基因组
  • C语言 | Leetcode C语言题解之第338题比特位计数
  • 数据之争:网络爬虫涉及的法律问题
  • 【机器学习第十二章——计算学习理论】