Win32创建异形窗口

大家都见过在windows下各种气泡窗口、输入法窗口以及其他一些窗口,这些窗口看起来不像传统的windows窗那样,上面是标题栏,下面是窗口的客户区。这些窗口形状各异,可以是一个多边形,一幅图,甚至是一个人物画像等。这些异形窗口是怎么实现的呢?下面我们就来实现这个奇异形状的窗口。

其实在windows下实现特殊的窗口并不困难,有两种办法可以实现:

  1. 通过创建路径和区域、合并区域的办法。创建区域的API有很多,比如CreateRectRgnCreateRoundRectRgnCreateEllipticRgn以及其他创建区域函数等,具体参考MSDN。然后使用SetWindowRgn函数设置窗口区域,将区域转化为窗口。这种方式适合通过程序控制实现一些形状定制窗口。
  2. 通过位图画刷设置窗口背景,然后过滤掉指定的颜色,剩下的部分就是窗口。这种方式即简单,又适合位图化的任意窗口,用的最多,具有更炫的效果。实现方式就是将窗口属性设置分层,然后使用SetLayeredWindowAttributes这个API函数将特定颜色设置为透明色,该函数不仅可以设置为透明色,还可以设置整体窗口的透明度,将上一篇文章中设置半透明窗口效果,也是用的这个函数。

下面我们就来采用第二种方法来实现一个特殊的windows窗口。

首先我们要准备一张用于特殊窗口样子的位图,我们选择的图片如下:

为了实现这个位图的窗口形状,我们先对这个位图进行处理,将窗口以为的部分用一种特殊的颜色来填充,这个颜色需要与窗口保留部分不一样,因为只要是这种特定的颜色就会变成非窗口的部分,当然这种特殊颜色可以随便选择。从这种图来看,我们选择红色比较好,因为需要保留的部分没有红色出现。填充特殊颜色后的图片如下:

SetLayeredWindowAttributes函数原型如下:

BOOL SetLayeredWindowAttributes( HWND hwnd,

COLORREF crKey,

BYTE bAlpha,

DWORD dwFlags

);

hwnd:窗口句柄

crKey:特定的color key,就是要被透明的颜色

bAlpha:窗体的整体透明度

dwFlags:指定透明方式

下面就是实现的示意代码及注释:

#include <windows.h>

staticTCHAR szAppName[] = TEXT("异形窗口");

staticLRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAMlParm);

intWINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)

{

HWNDhwnd;

MSGmsg;

WNDCLASSwndclass;

HBITMAPhBitmap;

BITMAPbm;

hBitmap= (HBITMAP)LoadImage(NULL, TEXT("cartoon_win.bmp"),IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 该图用于创建窗口背景画刷,我们的窗口形状就是它了

if (hBitmap == NULL)

{

MessageBox(NULL,TEXT("位图加载失败"), TEXT("Error"), MB_ICONERROR);

return 0;

}

wndclass.style = CS_VREDRAW | CS_HREDRAW;

wndclass.lpfnWndProc= MainWndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground= CreatePatternBrush(hBitmap);//加载准备好的位图作为画刷

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName= szAppName;

if (!RegisterClass(&wndclass))

{

return FALSE;

}

GetObject(hBitmap,sizeof(bm), &bm);

hwnd= CreateWindowEx(WS_EX_TOPMOST,

szAppName,

szAppName,

WS_POPUP,

CW_USEDEFAULT,

CW_USEDEFAULT,

bm.bmWidth,

bm.bmHeight,

NULL,

NULL,

hInstance,

NULL);

if (hwnd == NULL)

{

return 0;

}

ShowWindow(hwnd,nShowCmd);

UpdateWindow(hwnd);

while (GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

DeleteObject(hBitmap);

return msg.wParam;

}

staticLRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAMlParm)

{

switch (message)

{

case WM_CREATE:

{

// 设置分层属性

SetWindowLong(hwnd,GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

// 设置透明色以及分层窗口属性,关键就是这个函数!

COLORREFclTransparent = RGB(255, 0, 0);

SetLayeredWindowAttributes(hwnd,clTransparent, 0, LWA_COLORKEY);

}

return 0;

case WM_KEYDOWN:

switch (wParam)

{

case VK_ESCAPE: //按下Esc键时退出

SendMessage(hwnd,WM_DESTROY, 0, 0);

return 0;

}

break;

case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口

PostMessage(hwnd,WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, message, wParam, lParm);

}

程序运行后,结果如下,该窗口的形状就跟图片上我们设定的一样,是不是很新鲜呢?赶快在你的电脑上试一下吧,你还可以换成你自己的图片,只要设置正确的透明色即可。

转载于:https://www.cnblogs.com/shenyantao/p/10712916.html

VC利用PNG图片制作异形窗口的源代码如下: 首先,在项目中添加头文件"libpng/png.h"和"zlib/zlib.h"。 然后,定义一个函数LoadPng(),用于加载PNG图片并获取图片数据和透明度信息,具体代码如下: ```c++ int LoadPng(const char* fileName, int* outWidth, int* outHeight, unsigned char** outData, std::vector<unsigned char>& outAlpha) { FILE* file = fopen(fileName, "rb"); if (!file) return 0; png_byte header[8]; fread(header, 1, 8, file); if (png_sig_cmp(header, 0, 8)) return 0; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return 0; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(file); return 0; } png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); png_bytep* row_pointers = new png_bytep[height]; for (int y = 0; y < height; ++y) row_pointers[y] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; png_read_image(png_ptr, row_pointers); std::vector<unsigned char> alpha; alpha.resize(width * height); for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) { png_bytep px = &(row_pointers[y][x * 4]); alpha[y * width + x] = px[3]; px[3] = 0xFF; //将alpha设为不透明 } *outData = *row_pointers; *outWidth = width; *outHeight = height; outAlpha = alpha; for (int y = 0; y < height; ++y) delete[] row_pointers[y]; delete[] row_pointers; fclose(file); return 1; } ``` 接下来,定义如下的异形窗口类: ```c++ class ShapedWindow { public: ShapedWindow() : m_hwnd(NULL), m_hbmp(NULL), m_hit(false), m_drag(false) { LoadPng("shape.png", &m_width, &m_height, &m_data, m_alpha); } void Create(int x, int y, int width, int height) { m_hwnd = CreateWindowEx(NULL, TEXT("ShapedWindow"), NULL, WS_POPUP | WS_VISIBLE, x, y, width, height, NULL, NULL, NULL, this); } bool HitTest(int x, int y) { if (m_hit || !m_hwnd) return false; HRGN hClipRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(m_hwnd, hClipRgn); POINT pt = { x, y }; bool bHit = PtInRegion(hClipRgn, pt.x, pt.y) != 0; DeleteObject(hClipRgn); return bHit; } void Move(int x, int y) { SetWindowPos(m_hwnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } private: static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ShapedWindow* pThis = NULL; if (uMsg == WM_CREATE) { LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); pThis = reinterpret_cast<ShapedWindow*>(lpcs->lpCreateParams); SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<ULONG_PTR>(pThis)); pThis->m_hwnd = hwnd; } else { pThis = reinterpret_cast<ShapedWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); if (!pThis) return DefWindowProc(hwnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint(hwnd, &ps); if (pThis->m_hbmp != NULL) DeleteObject(pThis->m_hbmp); pThis->m_hbmp = CreateBitmap(pThis->m_width, pThis->m_height, 1, 32, pThis->m_data); HDC hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, pThis->m_hbmp); BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; AlphaBlend(hdc, 0, 0, pThis->m_width, pThis->m_height, hdcMem, 0, 0, pThis->m_width, pThis->m_height, bf); DeleteDC(hdcMem); EndPaint(hwnd, &ps); } break; case WM_NCHITTEST: if (pThis->m_hit) return HTCAPTION; break; case WM_MOUSEMOVE: if (pThis->m_drag) { int x = LOWORD(lParam); int y = HIWORD(lParam); pThis->Move(x - pThis->m_dragX, y - pThis->m_dragY); } break; case WM_LBUTTONDOWN: pThis->m_hit = pThis->HitTest(LOWORD(lParam), HIWORD(lParam)); if (pThis->m_hit) { pThis->m_drag = true; pThis->m_dragX = LOWORD(lParam); pThis->m_dragY = HIWORD(lParam); } break; case WM_LBUTTONUP: pThis->m_hit = false; pThis->m_drag = false; break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } private: HWND m_hwnd; unsigned char* m_data; int m_width, m_height; std::vector<unsigned char> m_alpha; HBITMAP m_hbmp; bool m_hit; bool m_drag; int m_dragX; int m_dragY; }; ``` 其中,LoadPng()函数用于加载PNG图片并获取图片数据和透明度信息,ShapedWindow类用于绘制异形窗口和响应窗口消息。 最后,在WinMain()函数中创建异形窗口,并进入消息循环,具体代码如下: ```c++ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc = {}; wc.cbSize = sizeof(wc); wc.lpfnWndProc = ShapedWindow::WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = TEXT("ShapedWindow"); RegisterClassEx(&wc); ShapedWindow win; win.Create(100, 100, 300, 300); MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } ``` 这样,一个利用PNG图片制作的异形窗口就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值