-->

Transparent image over two controls with different

2019-08-24 02:27发布

问题:

I am trying to place a transparent image over two adjacent controls that have different background colors.
I want the image to remain transparent, meaning the Image needs to show the backcolor of each control.

The controls are two Panels set to different background colors and the Image (PictureBox or otherwise) is placed between the two panel controls.

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

回答1:

Let's try this.

  • Create a new class in the Project, call it TPanel and paste in the custom Panel class you can find below, overwriting the existing definition.
  • Compile the Project then find the new TPanel control in the ToolBox and drop one instance inside a Form.
    On the Form, not inside one of the Colored Panels, otherwise it will become child of another control and it will be confined inside its bounds.
  • Add an event handler to the Paint event of the TPanel and insert this code inside the handler method:

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
  • In the Form, create an instance of a Bitmap object that will contain the Image; also set the Location of the Panel (TPanel)
    The Controls called panColored1 and panColored2 are supposed to be the names of the two existing Panels where the Image must be positioned. The sample code positions the Image in the middle of the 2 Panels, using TPanel1.Location( (...) )

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

Result:

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

The TPanel (Transparent Panel) 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


回答2:

There is also something you can also try, It may not be professional but it works. Split the images into two halves. Draw the first half on one of the panels and the second half on the other panel. Be Sure to Import System.IO in Your project.

The code for the splitting goes like this:

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

Create Two panels on your form (Panel1 and Panel2) and a Button(Button1). Place The two panels the way you want it, set the BackgroundImageLayout property of the panels to StretchImage. Then from your code you can call the function like this, i.e From the Button's click event:

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

For More Information about the Bitmap Class, Check out this link Bitmap Class