windows api实现窗口透明整理

1. 实现窗口彻底透明

实现这种效果的方案网上介绍很多,基本原理都一样,在这里还是重复记录一次。
效果图:
这里写图片描述
这种透明效果整个窗口的所有内容全部透明,可以看到图中红色箭头所指,从这个窗口可以看到底层的source tree的按钮。

代码实现:

(1)设置WS_EX_LAYERED属性

    ::ShowWindow(main_window_, nCmdShow);
    ::UpdateWindow(main_window_);

    LONG ret = ::GetWindowLong(main_window_, GWL_EXSTYLE);
    ret = ret | WS_EX_LAYERED;
    ::SetWindowLong(main_window_, GWL_EXSTYLE, ret);

前面两行代码是创建窗口后刷新用的,之后三行代码是设置窗口的分层属性WS_EX_LAYERED,只有设置了这个属性,才能实现上图给出的透明效果,这几行代码的相对位置不可以更改,我试着把后三行代码放到窗口刷新操作之前,代码无法正常运行。

(2)在窗口过程函数中响应WM_PAINT时加上

::SetLayeredWindowAttributes(main_window_, 0, 255, LWA_ALPHA);

2.实现背景透明控件不透明一

这种方案其实是实现毛玻璃效果用的,只是偶然发现勉强能够实现透明效果,效果差强人意,如果发现在某些环境下不起作用,那也算正常现象。

效果:
这里写图片描述
可以看到左侧透出来的代码,有一种朦胧的感觉,这可能就是毛玻璃效果吧。

代码实现:
(1) 包含头文件

    #include <dwmapi.h>

(2) 添加编译链接

    #pragma comment(lib,"Dwmapi.lib")  

(3) 设置窗口的背景颜色

    wcex.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);

备注:窗口背景颜色设置为某些颜色无法透明,上图效果是设置为灰色时实现的。
(4) 在窗口初始化时加上如下代码

    MARGINS m = { -1 };
    DwmExtendFrameIntoClientArea(main_window_, &m);

    ::ShowWindow(main_window_, nCmdShow);
    ::UpdateWindow(main_window_);

第一个代码块是实现这种效果的关键所在,这两个代码块的相对位置可以调整。

3.实现背景透明控件不透明正式方案

效果:
这里写图片描述
可以看到,这种背景透明的效果还是比较正常的,看到底层的文字很清晰。

代码实现:
(1) 设置窗口背景颜色

    wcex.hbrBackground = CreateSolidBrush(RGB(251, 255, 242));

这里设置了一种我需要显示的图片里没有的颜色作为背景颜色,后面将看到实现透明的原理是将指定的颜色设为透明。

(2) 初始化设置窗口的WS_EX_LAYERED属性
这里和第一种方案的设置方式是一样,还是复制一次:

    ::ShowWindow(main_window_, nCmdShow);
    ::UpdateWindow(main_window_);

    LONG ret = ::GetWindowLong(main_window_, GWL_EXSTYLE);
    ret = ret | WS_EX_LAYERED;
    ::SetWindowLong(main_window_, GWL_EXSTYLE, ret);

(3)在窗口的过程函数中响应WM_PAINT消息,增加如下代码

::SetLayeredWindowAttributes(main_window_, RGB(251, 255, 242), 0, LWA_COLORKEY);

注意这里设置的是LWA_COLORKEY,而不是LWA_ALPHA,前面一种是将某种颜色(第二个参数)设置为透明,后一种是将窗口所有颜色均设置为指定透明度(第三个参数),具体区别网上搜索一下就出来了。

4.动图显示异常分析

效果
这里写图片描述
图中的gif图片显示异常,很明显错位了。第一帧显示位置,与后面的帧的显示位置相差极大。

原因分析:
窗口去除边框和标题栏是通过处理WM_SIZE消息实现的,第一帧显示时很明显是在有边框和标题栏的情况下的,而后面的帧在显示时边框和标题栏已经消失了,所以后面的帧显示位置就往左上移动了。也就是说去除窗口边框和标题栏的时机过晚,需要在开始显示gif图片之前通知窗口刷新。

    case WM_SIZE:
    {
        LONG_PTR Style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
        Style = Style & ~WS_CAPTION &~WS_SYSMENU &~WS_SIZEBOX;
        ::SetWindowLongPtr(hWnd, GWL_STYLE, Style);
        return 0;
    }

解决办法:

    ::InvalidateRect(hWnd, NULL, TRUE);
    ::UpdateWindow(hWnd);

在开始显示第一帧图片之前,强制刷新窗口,之后即可恢复正常。

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Windows API实现登录窗口的示例代码: ```c++ #include <Windows.h> // 定义窗口类名和标题 #define CLASS_NAME TEXT("LoginWindowClass") #define WINDOW_TITLE TEXT("Login") // 定义控件ID #define ID_USERNAME 100 #define ID_PASSWORD 101 #define ID_LOGIN_BTN 102 // 定义控件位置和大小 #define USERNAME_X 50 #define USERNAME_Y 50 #define USERNAME_WIDTH 200 #define USERNAME_HEIGHT 25 #define PASSWORD_X 50 #define PASSWORD_Y 90 #define PASSWORD_WIDTH 200 #define PASSWORD_HEIGHT 25 #define LOGIN_BTN_X 100 #define LOGIN_BTN_Y 140 #define LOGIN_BTN_WIDTH 100 #define LOGIN_BTN_HEIGHT 30 // 定义全局变量 HWND g_hUsername, g_hPassword, g_hLoginBtn; // 窗口过程函数 LRESULT CALLBACK LoginWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: // 创建用户名输入框 g_hUsername = CreateWindow(TEXT("EDIT"), NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, USERNAME_X, USERNAME_Y, USERNAME_WIDTH, USERNAME_HEIGHT, hwnd, (HMENU)ID_USERNAME, NULL, NULL); // 创建密码输入框 g_hPassword = CreateWindow(TEXT("EDIT"), NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_PASSWORD, PASSWORD_X, PASSWORD_Y, PASSWORD_WIDTH, PASSWORD_HEIGHT, hwnd, (HMENU)ID_PASSWORD, NULL, NULL); // 创建登录按钮 g_hLoginBtn = CreateWindow(TEXT("BUTTON"), TEXT("Login"), WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, LOGIN_BTN_X, LOGIN_BTN_Y, LOGIN_BTN_WIDTH, LOGIN_BTN_HEIGHT, hwnd, (HMENU)ID_LOGIN_BTN, NULL, NULL); break; case WM_COMMAND: if (LOWORD(wParam) == ID_LOGIN_BTN) { // 获取用户名和密码 TCHAR szUsername[256], szPassword[256]; GetWindowText(g_hUsername, szUsername, 256); GetWindowText(g_hPassword, szPassword, 256); // TODO: 进行登录验证 } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册窗口类 WNDCLASS wc = { 0 }; wc.lpfnWndProc = LoginWindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); // 创建窗口 HWND hwnd = CreateWindow(CLASS_NAME, WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 220, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); // 消息循环 MSG msg = { 0 }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } ``` 该代码使用了Windows API中的CreateWindow和GetWindowText等函数创建和操作窗口控件,实现了一个简单的登录窗口。在登录按钮被点击时,可以获取用户名和密码,并进行登录验证。需要注意的是,该代码中的登录验证部分尚未实现,需要根据具体需求进行编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值