用PNG做半透明窗体 调用 UpdateLayeredWindow 怎么窗体变为全透明了PNG图片没显示?

时间:2022-08-10 06:07:36
想用PNG做半透明窗体 我为窗体加上WS_EX_LAYERED后 调用 UpdateLayeredWindow 怎么窗体变为全透明了PNG图片没显示?有那位大侠能帮帮手吗?
这是源码:
Public Function SinkUpdate(frm As Form, sinkbmp As String) As Boolean
With bmph.bmiHeader
.biSize = Len(bmph.bmiHeader)
.biBitCount = 32
.biWidth = frm.ScaleWidth
.biHeight = frm.ScaleHeight
.biPlanes = 1
.biSizeImage = .biWidth * .biHeight * (.biBitCount / 8)
End With

cdc = CreateCompatibleDC(frm.hdc)
If cdc = 0 Then Exit Function
mbmp = CreateDIBSection(cdc, bmph, 0, ByVal 0, 0, 0)'创建与设备无关位图
obmp = SelectObject(cdc, mbmp)

GdipCreateFromHDC frm.hdc, grh
If grh = 0 Then Exit Function

GdipLoadImageFromFile StrConv(sinkbmp, vbUnicode), bmp ‘sinkbmp 为当前目录下的PNG文件的路径
If bmp = 0 Then Exit Function

Call GdipDrawImage(grh, bmp, 0, 0)'调用GDI+画出图象

curWinLong = GetWindowLong(frm.hWnd, GWL_EXSTYLE)
  SetWindowLong frm.hWnd, GWL_EXSTYLE, curWinLong Or WS_EX_LAYERED
   
sz.CX = frm.ScaleWidth
sz.CY = frm.ScaleHeight
pz.x = 0
pz.y = 0
With bln
.AlphaFormat = &H1
.BlendFlags = 0
.BlendOp = &H0
.SourceConstantAlpha = 0
End With
re = UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, sz, cdc, pz, 0, bln, &H2)’更新窗体

SinkUpdate = True

End Function

14 个解决方案

#1


改改下面红色的地方,然后你修改一下你的PNG图片
图片是怎么透明就应该怎么透明了
...
sz.CX = frm.ScaleWidth 
sz.CY = frm.ScaleHeight 
pz.x = 0 
pz.y = 0 
With bln 
.AlphaFormat = &H1 
.BlendFlags = 0 
.BlendOp = &H0 
.SourceConstantAlpha = 255 
End With 
re = UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, sz, cdc, pz, 0, bln, &H2)’更新窗体 

#2


如果你只是想全部半透明,你可以这样改
... 
sz.CX = frm.ScaleWidth 
sz.CY = frm.ScaleHeight 
pz.x = 0 
pz.y = 0 
With bln 
.AlphaFormat = &H1 
.BlendFlags = 0 
.BlendOp = &H0 
.SourceConstantAlpha = 128 
End With 
re = UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, sz, cdc, pz, 0, bln, &H2)’更新窗体 

#3


你的代码我没测试过,但大概看了看,你用GDI+的时候没有用GdipDisposeImage和GdipDeleteGraphics
这样会就占用内存的,如果程序多启动几次那就麻烦了。

#4


还有,如果你要作纯半透明的窗口,就是说透明度统一是半透明的,
没必要用到这么复杂,这样就可以了

      Public Const WS_EX_LAYERED = &H80000
      Public Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, _
              ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
      '标志
      Public Const LWA_ALPHA = &H2   'crKey参数无效
      Public Const LWA_COLORKEY = &H1   'bAlpha参数有效
      '------------------------------------------------------

      Dim rtn As Long
      rtn = GetWindowLong(hwnd, GWL_EXSTYLE)
      rtn = rtn Or WS_EX_LAYERED
      SetWindowLong hwnd, GWL_EXSTYLE, rtn
      'SetLayeredWindowAttributes 窗口句柄,要全透明的颜色,透明度(0-255),标志
      SetLayeredWindowAttributes hwnd, 255, 128, LWA_COLORKEY

#5


要全透明的颜色我上面的范例是红色,所以是255
你可以这样用

SetLayeredWindowAttributes hwnd, Rgb(255,0,0), 128, LWA_COLORKEY

#6


不对呀,改了这样还是不行
Public Function SinkUpdate2(frm As Form, imgPath As String) As Boolean

With tempBI.bmiHeader
.biSize = Len(tempBI.bmiHeader)
.biBitCount = 32
.biHeight = frm.ScaleHeight
.biWidth = frm.ScaleWidth
.biPlanes = 1
.biSizeImage = .biWidth * .biHeight * (.biBitCount / 8)
End With
mDC = CreateCompatibleDC(frm.hdc)
mainBitmap = CreateDIBSection(mDC, tempBI, DIB_RGB_COLORS, ByVal 0, 0, 0)
oldBitmap = SelectObject(mDC, mainBitmap)
 Call GdipCreateFromHDC(mDC, graphics)
 Call GdipLoadImageFromFile(StrConv(imgPath, vbUnicode), img)
 Call GdipGetImageHeight(img, lngHeight)
 Call GdipGetImageWidth(img, lngWidth)
 Call GdipDrawImageRect(graphics, img, 0, 0, lngWidth, lngHeight)
 curWinLong = GetWindowLong(frm.hWnd, GWL_EXSTYLE)
 SetWindowLong frm.hWnd, GWL_EXSTYLE, curWinLong Or WS_EX_LAYERED
 srcPoint.x = 0
 srcPoint.y = 0
 winSize.CX = frm.ScaleWidth
 winSize.CY = frm.ScaleHeight
 With blendFunc32bpp
 .AlphaFormat = AC_SRC_ALPHA
 .BlendFlags = 0
 .BlendOp = AC_SRC_OVER
 .SourceConstantAlpha = 255
 End With
 Call GdipDisposeImage(img)
 Call UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, winSize, mDC, srcPoint, 0, blendFunc32bpp, ULW_ALPHA)
End Function

#7


你的PNG图片是什么样的?

#8


自己画的带Alpha值的的Vvista窗体图片

#9


你在使用GDI+之前有没有对GDI+库进行初始化?

   Dim token As Long

   '初始化gdi+库,通常放在类里的Class_Initialize事件执行
   '如果你不是类,只是单纯的函数,最好在函数头初始化,函数结束时释放
   Dim GpInput As GdiplusStartupInput
   GpInput.GdiplusVersion = 1
   If GdiplusStartup(token, GpInput) <> 0 Then
       MsgBox "没有找到GDI+库!gdip.dll", vbCritical
   End If


   '当不再使用GDI+用以下方法释放GDI+,通常放在类里的Class_Terminate事件执行
   GdiplusShutdown token

#10


当然初始化了,窗口没加WS_EX_LAYERED图片是可以显示,但加了此样式后窗口全透明了,什么也看不见 注:UpdateLayeredWindow 返回值为1,GdiDrawImage返回值为常量'ok',就是不知道出什么问题,代码应该没错啊

#11


你这样看看

...
With tempBI.bmiHeader 
.biSize = Len(tempBI.bmiHeader) 
.biBitCount = 32 
.biHeight = Screen.Height / 15
.biWidth = Screen.Width / 15
.biPlanes = 1 
.biSizeImage = .biWidth * .biHeight * (.biBitCount / 8) 
End With 
...

#12


设置了WS_EX_LAYERED窗口样式后, 窗口不再处理Paint消息. 所以你的窗口画不出来, 但是窗口上的按钮啥的仍然可以响应按键消息.

#13


'       将窗体AutoRedraw设为true,ScaleMode设为3    我没加载图片,只是画了半透明的圆

Dim tempBI As BITMAPINFO, mDc As Long, mainBitmap As Long, oldBitmap As Long, winSize As size, srcPoint As POINTAPI, blendFunc32bpp As BLENDFUNCTION

    '初始化GDI+   略
    '初始化LayeredWindow
    With tempBI.bmiHeader
        .biSize = Len(tempBI.bmiHeader)
        .biBitCount = 32
        .biHeight = Screen.Height / 15
        .biWidth = Screen.Width / 15
        .biPlanes = 1
        .biSizeImage = .biWidth * .biHeight * (.biBitCount / 8)
    End With
    
        '创建32位DC
    mDc = CreateCompatibleDC(Me.hDC)
    mainBitmap = CreateDIBSection(mDc, tempBI, 0, ByVal 0, 0, 0)
    'mainBitmap = CreateDIBSection(mDC, tempBI, DIB_RGB_COLORS, ByVal 0, 0, 0)
    oldBitmap = SelectObject(mDc, mainBitmap)
        '==========================================
        '设置扩展样式 
    SetWindowLong Me.hwnd, -20, GetWindowLong(Me.hwnd, -20) Or &H80000
    
    GdipCreateFromHDC mDc, Graphics

    GdipCreateSolidFill &H99FF0000, Brush
    GdipFillEllipseI Graphics, Brush, 0, 0, 300, 300
    
    winSize.cx = Me.ScaleWidth
    winSize.cy = Me.ScaleHeight
    srcPoint.x = 0
    srcPoint.y = 0
    
    With blendFunc32bpp
      .AlphaFormat = &H1
      .BlendFlags = 0
      .BlendOp = &H0
      .SourceConstantAlpha = 250
    End With
    UpdateLayeredWindow Me.hwnd, Me.hDC, ByVal 0&, winSize, mDc, srcPoint, 0, blendFunc32bpp, &H2

#14


我本来也是跟楼主出一样的问题。关键在于GDI要用CreateCompatibleDC创建的32位DC来创建Graphics

更改后的代码在上楼。此代码通过调试。

#1


改改下面红色的地方,然后你修改一下你的PNG图片
图片是怎么透明就应该怎么透明了
...
sz.CX = frm.ScaleWidth 
sz.CY = frm.ScaleHeight 
pz.x = 0 
pz.y = 0 
With bln 
.AlphaFormat = &H1 
.BlendFlags = 0 
.BlendOp = &H0 
.SourceConstantAlpha = 255 
End With 
re = UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, sz, cdc, pz, 0, bln, &H2)’更新窗体 

#2


如果你只是想全部半透明,你可以这样改
... 
sz.CX = frm.ScaleWidth 
sz.CY = frm.ScaleHeight 
pz.x = 0 
pz.y = 0 
With bln 
.AlphaFormat = &H1 
.BlendFlags = 0 
.BlendOp = &H0 
.SourceConstantAlpha = 128 
End With 
re = UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, sz, cdc, pz, 0, bln, &H2)’更新窗体 

#3


你的代码我没测试过,但大概看了看,你用GDI+的时候没有用GdipDisposeImage和GdipDeleteGraphics
这样会就占用内存的,如果程序多启动几次那就麻烦了。

#4


还有,如果你要作纯半透明的窗口,就是说透明度统一是半透明的,
没必要用到这么复杂,这样就可以了

      Public Const WS_EX_LAYERED = &H80000
      Public Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, _
              ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
      '标志
      Public Const LWA_ALPHA = &H2   'crKey参数无效
      Public Const LWA_COLORKEY = &H1   'bAlpha参数有效
      '------------------------------------------------------

      Dim rtn As Long
      rtn = GetWindowLong(hwnd, GWL_EXSTYLE)
      rtn = rtn Or WS_EX_LAYERED
      SetWindowLong hwnd, GWL_EXSTYLE, rtn
      'SetLayeredWindowAttributes 窗口句柄,要全透明的颜色,透明度(0-255),标志
      SetLayeredWindowAttributes hwnd, 255, 128, LWA_COLORKEY

#5


要全透明的颜色我上面的范例是红色,所以是255
你可以这样用

SetLayeredWindowAttributes hwnd, Rgb(255,0,0), 128, LWA_COLORKEY

#6


不对呀,改了这样还是不行
Public Function SinkUpdate2(frm As Form, imgPath As String) As Boolean

With tempBI.bmiHeader
.biSize = Len(tempBI.bmiHeader)
.biBitCount = 32
.biHeight = frm.ScaleHeight
.biWidth = frm.ScaleWidth
.biPlanes = 1
.biSizeImage = .biWidth * .biHeight * (.biBitCount / 8)
End With
mDC = CreateCompatibleDC(frm.hdc)
mainBitmap = CreateDIBSection(mDC, tempBI, DIB_RGB_COLORS, ByVal 0, 0, 0)
oldBitmap = SelectObject(mDC, mainBitmap)
 Call GdipCreateFromHDC(mDC, graphics)
 Call GdipLoadImageFromFile(StrConv(imgPath, vbUnicode), img)
 Call GdipGetImageHeight(img, lngHeight)
 Call GdipGetImageWidth(img, lngWidth)
 Call GdipDrawImageRect(graphics, img, 0, 0, lngWidth, lngHeight)
 curWinLong = GetWindowLong(frm.hWnd, GWL_EXSTYLE)
 SetWindowLong frm.hWnd, GWL_EXSTYLE, curWinLong Or WS_EX_LAYERED
 srcPoint.x = 0
 srcPoint.y = 0
 winSize.CX = frm.ScaleWidth
 winSize.CY = frm.ScaleHeight
 With blendFunc32bpp
 .AlphaFormat = AC_SRC_ALPHA
 .BlendFlags = 0
 .BlendOp = AC_SRC_OVER
 .SourceConstantAlpha = 255
 End With
 Call GdipDisposeImage(img)
 Call UpdateLayeredWindow(frm.hWnd, frm.hdc, ByVal 0&, winSize, mDC, srcPoint, 0, blendFunc32bpp, ULW_ALPHA)
End Function

#7


你的PNG图片是什么样的?

#8


自己画的带Alpha值的的Vvista窗体图片

#9


你在使用GDI+之前有没有对GDI+库进行初始化?

   Dim token As Long

   '初始化gdi+库,通常放在类里的Class_Initialize事件执行
   '如果你不是类,只是单纯的函数,最好在函数头初始化,函数结束时释放
   Dim GpInput As GdiplusStartupInput
   GpInput.GdiplusVersion = 1
   If GdiplusStartup(token, GpInput) <> 0 Then
       MsgBox "没有找到GDI+库!gdip.dll", vbCritical
   End If


   '当不再使用GDI+用以下方法释放GDI+,通常放在类里的Class_Terminate事件执行
   GdiplusShutdown token

#10


当然初始化了,窗口没加WS_EX_LAYERED图片是可以显示,但加了此样式后窗口全透明了,什么也看不见 注:UpdateLayeredWindow 返回值为1,GdiDrawImage返回值为常量'ok',就是不知道出什么问题,代码应该没错啊

#11


你这样看看

...
With tempBI.bmiHeader 
.biSize = Len(tempBI.bmiHeader) 
.biBitCount = 32 
.biHeight = Screen.Height / 15
.biWidth = Screen.Width / 15
.biPlanes = 1 
.biSizeImage = .biWidth * .biHeight * (.biBitCount / 8) 
End With 
...

#12


设置了WS_EX_LAYERED窗口样式后, 窗口不再处理Paint消息. 所以你的窗口画不出来, 但是窗口上的按钮啥的仍然可以响应按键消息.

#13


'       将窗体AutoRedraw设为true,ScaleMode设为3    我没加载图片,只是画了半透明的圆

Dim tempBI As BITMAPINFO, mDc As Long, mainBitmap As Long, oldBitmap As Long, winSize As size, srcPoint As POINTAPI, blendFunc32bpp As BLENDFUNCTION

    '初始化GDI+   略
    '初始化LayeredWindow
    With tempBI.bmiHeader
        .biSize = Len(tempBI.bmiHeader)
        .biBitCount = 32
        .biHeight = Screen.Height / 15
        .biWidth = Screen.Width / 15
        .biPlanes = 1
        .biSizeImage = .biWidth * .biHeight * (.biBitCount / 8)
    End With
    
        '创建32位DC
    mDc = CreateCompatibleDC(Me.hDC)
    mainBitmap = CreateDIBSection(mDc, tempBI, 0, ByVal 0, 0, 0)
    'mainBitmap = CreateDIBSection(mDC, tempBI, DIB_RGB_COLORS, ByVal 0, 0, 0)
    oldBitmap = SelectObject(mDc, mainBitmap)
        '==========================================
        '设置扩展样式 
    SetWindowLong Me.hwnd, -20, GetWindowLong(Me.hwnd, -20) Or &H80000
    
    GdipCreateFromHDC mDc, Graphics

    GdipCreateSolidFill &H99FF0000, Brush
    GdipFillEllipseI Graphics, Brush, 0, 0, 300, 300
    
    winSize.cx = Me.ScaleWidth
    winSize.cy = Me.ScaleHeight
    srcPoint.x = 0
    srcPoint.y = 0
    
    With blendFunc32bpp
      .AlphaFormat = &H1
      .BlendFlags = 0
      .BlendOp = &H0
      .SourceConstantAlpha = 250
    End With
    UpdateLayeredWindow Me.hwnd, Me.hDC, ByVal 0&, winSize, mDc, srcPoint, 0, blendFunc32bpp, &H2

#14


我本来也是跟楼主出一样的问题。关键在于GDI要用CreateCompatibleDC创建的32位DC来创建Graphics

更改后的代码在上楼。此代码通过调试。