扩展的非客户区域上的Windows公共控件

时间:2018-12-15 10:48:01

标签: desktop-application

在我的应用程序中,我想在非客户区域使用由DwmExtendFrameIntoClientArea扩展的通用控件(即EDIT,BUTTON COMBOBOXEX32)。整个扩展过程效果很好,但是当我在此扩展区域上使用Windows公共控件时,绘制文本时会出现讨厌的效果。阅读一段时间后,我发现使用GDI +可以以合成方式绘制文本,因此可以使用GDI +绘制标签。

下图显示了一个示例。您将看到由

创建的拆分按钮
  BStyle = BS_PUSHBUTTON Or WS_CHILD Or WS_VISIBLE Or &HC&
  .hwnd = CreateWindowEX(0, "BUTTON", vbNullString, BStyle, _
                         ScaleLeft, ScaleTop, ScaleWidth, ScaleHeight, _
                         UserControl.hwnd, 0&, App.hInstance, _
                         ByVal 0&)

同样由CreateWindowEx创建的EDIT和使用主题,GDI +标签和图像的用户绘制按钮。

由CreateWindowEx创建的控件显然是在没有GDI +支持的情况下绘制的,因此所有内容均未正确合成。这确实很难看,因为输入的文本不可读。自己创建编辑器是一件大事,所以我在这里更喜欢Windows的支持。

在Win7到Win10下,即使在Win8,Win10下首选有光泽的Win7背景或不透明样式,也会出现此问题。

我的问题是:清单中是否有可用于正确绘制常用控件的设置,或者是否存在扩展样式来支持它? Windows为什么不原生支持它?

Screenshot of common controls on NC area

1 个答案:

答案 0 :(得分:0)

我找到了使用uxtheme缓冲绘画功能的解决方案。

在通用控件的WM_PAINT上执行以下操作:

  1. 通过调用BeginPaint获取绘图dc
  2. 调用lib uxtheme的BufferedPaintInit
  3. 通过调用BeginBufferedPaint创建缓冲的绘画位图
  4. 将公共控件的客户区打印到缓冲区
  5. 通过BufferedPaintSetAlpha使缓冲区的所有像素不透明
  6. 通过EndBufferedPaint绘制缓冲区以绘制dc
  7. 致电BufferedPaintUnInit

为方便起见,这里是经典VB类clsBufferedPaint的代码

Option Explicit

Public Enum BP_BUFFERFORMAT
    BPBF_COMPATIBLEBITMAP = 0
    BPBF_DIB = 1
    BPBF_TOPDOWNDIB = 2
    BPBF_TOPDOWNMONODIB = 3
End Enum

Public Enum BP_PAINTPARAMS_FLAGS
    BPPF_ERASE = 1
    BPPF_NOCLIP = 2
    BPPF_NONCLIENT = 4
End Enum

Public Type BP_PAINTPARAMS
    cbSize As Long
    dwFlags As BP_PAINTPARAMS_FLAGS
    prcExclude As Long
    pBlendFunction As Long
End Type

Private mHandle As Long

Private Declare Function BeginBufferedPaint Lib "uxtheme" (ByVal hdcTarget As Long, ByRef prcTarget As RECT, ByVal dwFormat As BP_BUFFERFORMAT, ByRef pPaintParams As Any, ByRef HDC As Long) As Long
Private Declare Function BufferedPaintClear Lib "uxtheme" (ByVal hBufferedPaint As Long, ByRef prc As RECT) As Long
Private Declare Function BufferedPaintInit Lib "uxtheme" () As Long
Private Declare Function BufferedPaintSetAlpha Lib "uxtheme" (ByVal hBufferedPaint As Long, ByRef prc As RECT, ByVal Alpha As Byte) As Long
Private Declare Function BufferedPaintUnInit Lib "uxtheme" () As Long
Private Declare Function EndBufferedPaint Lib "uxtheme.dll" (ByVal hBufferedPaint As Long, ByVal fUpdateTarget As Long) As Long

Friend Function BeginPaint(ByVal targetDC As Long, ByRef targetRect As RECT, _
                  ByVal format As BP_BUFFERFORMAT) As Long
    mHandle = BeginBufferedPaint(targetDC, targetRect, BPBF_TOPDOWNDIB, ByVal 0&, BeginPaint)
End Function

Public Function EndPaint(ByVal updatetargetDC As Long) As Long
    EndPaint = EndBufferedPaint(mHandle, updatetargetDC)
    mHandle = 0
End Function

Friend Sub SetAlpha(ByRef r As RECT, ByVal Alpha As Byte)
    BufferedPaintSetAlpha mHandle, r, Alpha
End Sub


Private Sub Class_Initialize()
    BufferedPaintInit
End Sub


Private Sub Class_Terminate()
    BufferedPaintUnInit
End Sub

并在通用控件的WM_PAINT中使用它(必须通过使用消息来子类化)

Dim bp As New clsBufferedPaint, rct As RECT, DC As Long, pDC As Long

GetClientRect hwnd, rct

DC = BeginPaint(hwnd, ps)

pDC = bp.BeginPaint(DC, rct, BPBF_TOPDOWNDIB)
SendMessage hwnd, WM_PRINTCLIENT, pDC, PRF_CLIENT
bp.SetAlpha rct, 255
ISubclass_WindowProc = bp.EndPaint(DC)

EndPaint hwnd, ps

要解决的问题:编辑线的角是不透明的,但根据系统使用的主题它们是透明的。

Editline on non client area