返回

如何在 Windows Aero 模糊中保持 TextBox 文本不透明?

windows

如何让 Aero 模糊中的 TextBox 文本保持不透明?

引言

在 Windows Vista、7 和 10 中,利用 Aero 模糊效果创建无边框窗体的方法是使用 UpdateAeroBlur 函数。然而,这个函数会导致一个烦恼的副作用:TextBox 控件中的文本变得透明。

问题

使用抗锯齿文本 GDI+ 绘制的按钮文本仍然是不透明的,而 TextBox 控件中的文本却变成了透明。虽然尝试了 SetLayeredWindowAttributes 函数,但问题仍然存在。

解决方案

解决这个问题的办法是修改 UpdateAeroBlur 函数,添加以下代码行:

// 在调用 DwmEnableBlurBehindWindow 之前添加此行
NativeApi.SetWindowLongPtr(Handle, GWL_EXSTYLE, (IntPtr)(
    NativeApi.GetWindowLongPtr(Handle, GWL_EXSTYLE) |
    NativeApi.WS_EX_LAYERED
));

运作原理

这个代码行将 WS_EX_LAYERED 扩展样式添加到窗口。这允许窗口混合自身和底层窗口,从而使 TextBox 文本保持不透明。

更新后的 UpdateAeroBlur 函数

以下是更新后的 UpdateAeroBlur 函数:

private void UpdateAeroBlur() {
    if (!SupportsAeroBlur) //do not do anything if XP or older
        return;
    else if (useSetWindowComposition) { //true if SetWindowCompositionAttribute function
                                        //exists in user32.dll
        AccentPolicy accent = new AccentPolicy();
        accent.AccentState = enableAeroBlur ? AccentState.ENABLE_BLURBEHIND : AccentState.DISABLED;
        WindowCompositionAttributeData data = new WindowCompositionAttributeData();
        data.Attribute = DwmWindowAttribute.ACCENT_POLICY;
        data.SizeOfData = AccentPolicy.Size;
        unsafe
        {
            data.Data = new IntPtr(&accent);
        }
        NativeApi.SetWindowCompositionAttribute(Handle, ref data);
    }
    
    // 在调用 DwmEnableBlurBehindWindow 之前添加此行
    NativeApi.SetWindowLongPtr(Handle, GWL_EXSTYLE, (IntPtr)(
        NativeApi.GetWindowLongPtr(Handle, GWL_EXSTYLE) |
        NativeApi.WS_EX_LAYERED
    ));
    
    DWM_BLURBEHIND style = new DWM_BLURBEHIND() {
        dwFlags = DWM_BB.Enable,
        fEnable = true
    };
    NativeApi.DwmEnableBlurBehindWindow(Handle, ref style);
}

结论

通过修改 UpdateAeroBlur 函数并添加 WS_EX_LAYERED 扩展样式,可以使 TextBox 文本在 Aero 模糊中保持不透明,同时保持边框的半透明效果。

常见问题解答

1. 这个解决方案适用于所有版本的 Windows 吗?

是的,它适用于 Windows Vista、7 和 10。

2. 我需要使用 SetLayeredWindowAttributes 函数吗?

不需要。修改后的 UpdateAeroBlur 函数已经包括了必要的更改。

3. 为什么 GDI+ 按钮文本保持不透明,而 TextBox 文本不会?

这是因为按钮文本使用抗锯齿文本 GDI+ 绘制,而 TextBox 文本则使用非抗锯齿文本 GDI+ 绘制。

4. 除了修改 UpdateAeroBlur 函数之外,还有什么其他方法可以解决这个问题吗?

没有。修改 UpdateAeroBlur 函数是解决这个问题的唯一方法。

5. 这个解决方案有性能问题吗?

不,这个解决方案对性能没有影响。