效果图:
其实实现方法非常简单,只需要两个窗口,一个负责主窗口另外一个负责透明即可:
首先依旧创建一个Win32工程:
#include "stdafx.h"
#include <windows.h>
HWND hWnd; //progman
//消息函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//判断消息ID
switch (uMsg){
case WM_DESTROY: // 窗口销毁消息
PostQuitMessage(0); // 发送退出消息
return 0;
}
// 其他的消息调用缺省的消息处理程序
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// 3、注册窗口类型
BOOL RegisterWindow(LPCSTR lpcWndName, HINSTANCE hInstance)
{
ATOM nAtom = 0;
// 构造创建窗口参数
WNDCLASS wndClass = { 0 };
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WindowProc; // 指向窗口过程函数
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = NULL;
wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = lpcWndName; // 注册的窗口名称,并非标题,以后创建窗口根据此注册的名称创建
nAtom = RegisterClass(&wndClass);
return TRUE;
}
//创建窗口(lpClassName 一定是已经注册过的窗口类型)
HWND CreateMyWindow(LPCTSTR lpClassName, HINSTANCE hInstance)
{
HWND hWnd = NULL;
// 创建窗口
hWnd = CreateWindow(lpClassName, "test", WS_OVERLAPPEDWINDOW^WS_THICKFRAME, 0, 0, 1000, 800, NULL, NULL, hInstance, NULL);
return hWnd;
}
//显示窗口
void DisplayMyWnd(HWND hWnd)
{
//获得屏幕尺寸
int scrWidth = GetSystemMetrics(SM_CXSCREEN);
int scrHeight = GetSystemMetrics(SM_CYSCREEN);
RECT rect;
GetWindowRect(hWnd, &rect);
ShowWindow(hWnd, SW_SHOW);
//重新设置rect里的值
rect.left = (scrWidth - rect.right) / 2;
rect.top = (scrHeight - rect.bottom) / 2;
//移动窗口到指定的位置
SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
UpdateWindow(hWnd);
}
void doMessage() // 消息循环处理函数
{
MSG msg = { 0 };
// 获取消息
while (GetMessage(&msg, NULL, 0, 0)) // 当接收到WM_QIUT消息时,GetMessage函数返回0,结束循环
{
DispatchMessage(&msg); // 派发消息,到WindowPro函数处理
}
}
// 入口函数
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
LPCTSTR lpClassName = "MyWnd"; // 注册窗口的名称
RegisterWindow(lpClassName, hInstance);
hWnd = CreateMyWindow(lpClassName, hInstance);
DisplayMyWnd(hWnd);
doMessage();
return 0;
}
在主窗口消息循环里添加绘图消息绘制背景图:
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
HBITMAP hbmp;// 位图绘制对象句柄,模糊图像
HDC mdc;
hdc = BeginPaint(hwnd, &ps);
mdc = CreateCompatibleDC(hdc); // 创建兼容的缓存DC对象
//加载位图
hbmp = (HBITMAP)LoadImage(
NULL, // 模块实例句柄
"C:\\Users\\ZZH\\Desktop\\D.bmp", // 位图路径。注意双斜杠,单斜杠表示转义,此时文件会加载不成功!!!
IMAGE_BITMAP, // 图片类型
1000,
800,
LR_LOADFROMFILE // 从路径处加载图片
);
// 缓存DC(mdc)选择位图绘制对象(可以理解为将图片保存到mdc中)
SelectObject(mdc, hbmp);
BitBlt(
hdc, // 目的DC
0, 0,
1000, // 目的DC的 x,y 坐标
800,
mdc, // 缓存DC
0, 0, // 缓存DC的x,y坐标
SRCCOPY // 粘贴方式
);
DeleteObject(hbmp);
DeleteDC(mdc);
EndPaint(hwnd, &ps);
break;
在Main函数里创建一个透明窗口,并在上面添加edit控件:
在此之前添加一个全局的句柄变量用于保存透明窗口的HWND方便移动:
HWND M_hwnd;
//CREATE
GetClientRect(hWnd, &rect); //对于客户区左上角为0
PO.x = rect.left; //0
PO.y = rect.top; //0
//屏幕坐标转换,转换前需要给PO结构体赋予客户区坐标,也就是给PO结构体赋予初始值Windows才能转换
ClientToScreen(hWnd, &PO);
M_hwnd = CreateWindowEx(WS_EX_LAYERED, lpClassName, NULL, WS_POPUP, PO.x + 10, PO.y + 10, 33, 22, hWnd, NULL, GetModuleHandle(NULL), NULL); //坐标是左上角坐标所以我们要+偏移量得到对应的客户区坐标
//透明化
SetLayeredWindowAttributes(M_hwnd, RGB(0, 0, 0), 155, LWA_ALPHA);
//创建控件
Edit = CreateWindow( //edit控件
"edit",
"SS",
WS_VISIBLE | WS_CHILD | WS_BORDER/*|DT_CENTER*/ | DT_VCENTER,
0, 0, 33, 22,
M_hwnd,
NULL,
NULL,
NULL);
//SHOW
ShowWindow(M_hwnd, SW_SHOW);
在主窗口的消息循环函数里修改MOVE消息:
case WM_MOVE:
RECT rect; //RECT
POINT PO; //屏幕坐标
//获取窗口的客户区坐标
GetClientRect(hWnd, &rect); //对于客户区左上角为0
PO.x = rect.left; //0
PO.y = rect.top; //0
//屏幕坐标转换,转换前需要给PO结构体赋予客户区坐标,也就是给PO结构体赋予初始值Windows才能转换
ClientToScreen(hWnd, &PO);
MoveWindow(M_hwnd, PO.x + 10, PO.y + 10, 33, 22, TRUE);
break;
运行效果:
完整代码:
#include "stdafx.h"
#include <windows.h>
HWND hWnd; //progman
HWND M_hwnd;
//消息函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//判断消息ID
switch (uMsg){
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
HBITMAP hbmp;// 位图绘制对象句柄,模糊图像
HDC mdc;
hdc = BeginPaint(hwnd, &ps);
mdc = CreateCompatibleDC(hdc); // 创建兼容的缓存DC对象
//加载位图
hbmp = (HBITMAP)LoadImage(
NULL, // 模块实例句柄
"C:\\Users\\ZZH\\Desktop\\D.bmp", // 位图路径。注意双斜杠,单斜杠表示转义,此时文件会加载不成功!!!
IMAGE_BITMAP, // 图片类型
1000,
800,
LR_LOADFROMFILE // 从路径处加载图片
);
// 缓存DC(mdc)选择位图绘制对象(可以理解为将图片保存到mdc中)
SelectObject(mdc, hbmp);
BitBlt(
hdc, // 目的DC
0, 0,
1000, // 目的DC的 x,y 坐标
800,
mdc, // 缓存DC
0, 0, // 缓存DC的x,y坐标
SRCCOPY // 粘贴方式
);
DeleteObject(hbmp);
DeleteDC(mdc);
EndPaint(hwnd, &ps);
break;
case WM_MOVE:
RECT rect; //RECT
POINT PO; //屏幕坐标
//获取窗口的客户区坐标
GetClientRect(hWnd, &rect); //对于客户区左上角为0
PO.x = rect.left; //0
PO.y = rect.top; //0
//屏幕坐标转换,转换前需要给PO结构体赋予客户区坐标,也就是给PO结构体赋予初始值Windows才能转换
ClientToScreen(hWnd, &PO);
MoveWindow(M_hwnd, PO.x + 10, PO.y + 10, 33, 22, TRUE);
break;
case WM_DESTROY: // 窗口销毁消息
PostQuitMessage(0); // 发送退出消息
return 0;
}
// 其他的消息调用缺省的消息处理程序
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// 3、注册窗口类型
BOOL RegisterWindow(LPCSTR lpcWndName, HINSTANCE hInstance)
{
ATOM nAtom = 0;
// 构造创建窗口参数
WNDCLASS wndClass = { 0 };
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WindowProc; // 指向窗口过程函数
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = NULL;
wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = lpcWndName; // 注册的窗口名称,并非标题,以后创建窗口根据此注册的名称创建
nAtom = RegisterClass(&wndClass);
return TRUE;
}
//创建窗口(lpClassName 一定是已经注册过的窗口类型)
HWND CreateMyWindow(LPCTSTR lpClassName, HINSTANCE hInstance)
{
HWND hWnd = NULL;
// 创建窗口
hWnd = CreateWindow(lpClassName, "test", WS_OVERLAPPEDWINDOW^WS_THICKFRAME, 0, 0, 1000, 800, NULL, NULL, hInstance, NULL);
return hWnd;
}
//显示窗口
void DisplayMyWnd(HWND hWnd)
{
//获得屏幕尺寸
int scrWidth = GetSystemMetrics(SM_CXSCREEN);
int scrHeight = GetSystemMetrics(SM_CYSCREEN);
RECT rect;
GetWindowRect(hWnd, &rect);
ShowWindow(hWnd, SW_SHOW);
//重新设置rect里的值
rect.left = (scrWidth - rect.right) / 2;
rect.top = (scrHeight - rect.bottom) / 2;
//移动窗口到指定的位置
SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
UpdateWindow(hWnd);
}
void doMessage() // 消息循环处理函数
{
MSG msg = { 0 };
// 获取消息
while (GetMessage(&msg, NULL, 0, 0)) // 当接收到WM_QIUT消息时,GetMessage函数返回0,结束循环
{
DispatchMessage(&msg); // 派发消息,到WindowPro函数处理
}
}
// 入口函数
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
LPCTSTR lpClassName = "MyWnd"; // 注册窗口的名称
RegisterWindow(lpClassName, hInstance);
hWnd = CreateMyWindow(lpClassName, hInstance);
HWND Edit; //EDIT
RECT rect; //RECT
POINT PO; //屏幕坐标
//创建具有扩展风格的窗口
//获取窗口的客户区坐标
DisplayMyWnd(hWnd);
//CREATE
GetClientRect(hWnd, &rect); //对于客户区左上角为0
PO.x = rect.left; //0
PO.y = rect.top; //0
//屏幕坐标转换,转换前需要给PO结构体赋予客户区坐标,也就是给PO结构体赋予初始值Windows才能转换
ClientToScreen(hWnd, &PO);
M_hwnd = CreateWindowEx(WS_EX_LAYERED, lpClassName, NULL, WS_POPUP, PO.x + 10, PO.y + 10, 33, 22, hWnd, NULL, GetModuleHandle(NULL), NULL); //坐标是左上角坐标所以我们要+偏移量得到对应的客户区坐标
//透明化
SetLayeredWindowAttributes(M_hwnd, RGB(0, 0, 0), 155, LWA_ALPHA);
//创建控件
Edit = CreateWindow( //edit控件
"edit",
"SS",
WS_VISIBLE | WS_CHILD | WS_BORDER/*|DT_CENTER*/ | DT_VCENTER,
0, 0, 33, 22,
M_hwnd,
NULL,
NULL,
NULL);
//SHOW
ShowWindow(M_hwnd, SW_SHOW);
doMessage();
return 0;
}