具有不同背景颜色的两个控件上的透明图像

Transparent image over two controls with different back colors

我正在尝试将透明图像放置在两个具有不同背景颜色的相邻控件上。
我希望图像保持透明,这意味着图像需要显示每个控件的背景色。

控件是设置为不同背景颜色的两个面板,图像(PictureBox 或其他)放置在两个面板控件之间。

Public Class frmMain 
    Private Img1 As Image = Image.FromFile("C:\xxxx.png") 

    Private Sub frmMain_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint 
        e.Graphics.DrawImage(Img1, 5, 5) 
    End Sub 
End Class

让我们试试这个。

  • 在项目中新建一个class,命名为TPanel并粘贴到自定义面板class中,您可以在下面找到,覆盖现有定义。
  • 编译项目然后在工具箱中找到新的 TPanel 控件并将一个实例放入窗体中。
    在窗体上,而不是在其中一个彩色面板内,否则它将成为另一个控件的子控件,并且将被限制在其边界内。
  • TPanel 的 Paint 事件添加事件处理程序,并将此代码插入处理程序方法中:
Private Sub TPanel1_Paint(sender As Object, e As PaintEventArgs) Handles TPanel1.Paint
    Dim canvas As Control = DirectCast(sender, Control)
    Dim rect As Rectangle = ScaleImageFrame(imgBasketBall, canvas.ClientRectangle)

    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
    e.Graphics.CompositingMode = CompositingMode.SourceOver
    e.Graphics.PixelOffsetMode = PixelOffsetMode.Half
    e.Graphics.DrawImage(imgBasketBall, rect)
End Sub

Private Function ScaleImageFrame(sourceImage As Bitmap, destinationFrame As Rectangle) As Rectangle
    Dim rect As RectangleF = New RectangleF(0, 0, sourceImage.Width, sourceImage.Height)
    'Define the ratio between the Image Rectangle and the Container ClientRectangle
    Dim ratio As Single = CType(Math.Max(destinationFrame.Width, destinationFrame.Height) /
                                Math.Max(rect.Width, rect.Height), Single)
    rect.Size = New SizeF(rect.Width * ratio, rect.Height * ratio)
    'Use Integer division to avoid negative values
    rect.Location = New Point((destinationFrame.Width - CInt(rect.Width)) \ 2,
                              (destinationFrame.Height - CInt(rect.Height)) \ 2)
    Return Rectangle.Round(rect)
End Function
  • 在窗体中,创建将包含图像的位图对象的实例;还要设置面板​​的位置 (TPanel)
    名为 panColored1panColored2 的控件应该是图像必须位于的两个现有面板的名称定位。示例代码使用 TPanel1.Location( (...) )
  • 将图像定位在 2 个面板的中间
Private imgBasketBall As Bitmap = Nothing

Public Sub New()
    InitializeComponent()
    imgBasketBall = DirectCast(Image.FromFile("basketball.png").Clone(), Bitmap)
    TPanel1.Size = New Size(120, 120)
    TPanel1.Location = New Point(panColored1.Left + (panColored1.Width - TPanel1.Width) \ 2,
                                 panColored1.Top + (panColored1.Height + panColored2.Height - TPanel1.Height) \ 2)
    TPanel1.BringToFront()
End Sub

结果:

     Bitmap Size            Bitmap Size 
     (1245x1242)            (1178x2000)

TPanel(透明面板)class:

Imports System.ComponentModel

<DesignerCategory("Code")>
Public Class TPanel
    Inherits Panel
    Private Const WS_EX_TRANSPARENT As Integer = &H20
    Public Sub New()
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or
                    ControlStyles.UserPaint Or
                    ControlStyles.Opaque Or
                    ControlStyles.ResizeRedraw, True)
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, False)
        Me.UpdateStyles()
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        e.Graphics.FillRectangle(Brushes.Transparent, Me.ClientRectangle)
        MyBase.OnPaint(e)
    End Sub

    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get
            Dim parameters As CreateParams = MyBase.CreateParams
            parameters.ExStyle = parameters.ExStyle Or WS_EX_TRANSPARENT
            Return parameters
        End Get
    End Property
End Class

还有一些你也可以试试,可能不专业但是很管用。将图像分成两半。在一个面板上绘制上半部分,在另一个面板上绘制下半部分。 请务必在您的项目中导入 System.IO

拆分代码如下:

Imports System.IO
...
Public Function SplitImage(ByVal imgpath As String) As Image()
    Dim img As Image = Image.FromFile(imgpath)
    Dim bmp As Bitmap = DirectCast(img, Bitmap)
    Dim i As Integer = bmp.Height / 2
    Dim image1 As Bitmap = New Bitmap(bmp.Width, i)
    Dim image2 As Bitmap = New Bitmap(bmp.Width, i)
    Dim yPos As Integer = 0
    For x As Integer = 0 To image1.Width - 1
        For y As Integer = 0 To image1.Height - 1
            image1.SetPixel(x, y, bmp.GetPixel(x, y))
            yPos = y
        Next
    Next
    yPos += 1
    Dim ycount As Integer = 0
    For x As Integer = 0 To image2.Width - 1
        For y As Integer = yPos To bmp.Height - 1
            If ycount = i Then
                ycount -= 1
            End If
            image2.SetPixel(x, ycount, bmp.GetPixel(x, y))
            ycount += 1
        Next
        ycount = 0
    Next
    Dim ms As MemoryStream = New MemoryStream
    Dim ms1 As MemoryStream = New MemoryStream
    image1.Save(ms, Imaging.ImageFormat.Png)
    image2.Save(ms1, Imaging.ImageFormat.Png)
    Dim returnedImage(2) As Image
    returnedImage(0) = image1
    returnedImage(1) = image2
    Return returnedImage
End Function

在您的窗体上创建两个面板(Panel1 和 Panel2)和一个按钮 (Button1)。 将两个面板按照您想要的方式放置,将面板的 BackgroundImageLayout 属性 设置为 StretchImage。 然后从你的代码中你可以像这样调用函数,即从按钮的点击事件:

Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim pic() As Image = SplitImage("C:\xxxx.png")
    Panel1.BackgroundImage = pic(0)
    Panel2.BackgroundImage = pic(1)
End Sub

有关 Bitmap Class 的更多信息,请查看此 link Bitmap Class