【问题标题】:Transparent image over two controls with different back colors具有不同背景颜色的两个控件上的透明图像
【发布时间】:2019-06-13 01:56:14
【问题描述】:

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

控件是设置为不同背景颜色的两个面板,图像(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

【问题讨论】:

  • 您能展示一下您是如何尝试绘制/分配此位图的吗? + 面板是否需要在某些时候移动,或者一切都是静态的?你需要用这个位图做点什么吗?它会动吗?可以点击吗?还有什么可以用来更好地理解你的上下文的吗?
  • 一切都是静止的,不会移动。我也不需要对位图做任何事情,只是一张静态图片。我尝试用分配的背景图像覆盖另一个面板,这会切断图像的一半。与图片框类似的结果。如前所述,在表单绘制事件中没有容器的情况下在表单上绘制图像会将其绘制在所有内容的后面。
  • 好的。您是否尝试过在某处绘制此位图?你有一些代码吗?
  • 公共类 frmMain Private Img1 As Image = Image.FromFile("C:\xxxx.png") Private Sub frmMain_Paint(sender As Object, e As PaintEventArgs) 处理 Me.Paint e.Graphics.DrawImage (Img1, 5, 5) End Sub End Class

标签: vb.net winforms graphics transparency gdi+


【解决方案1】:

让我们试试这个。

  • 在项目中创建一个新类,将其命名为 TPanel 并粘贴到您可以在下面找到的自定义 Panel 类中,覆盖现有定义。
  • 编译项目,然后在工具箱中找到新的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(透明面板)类:

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

【讨论】:

  • 效果很好!我删除了相对定位部分,只设置了一个 x,y 坐标。谢谢!
  • 对不起 - 最后一个问题。如何保留原始纵横比?类似,将 Size Mode 设置为 Zoom?
  • 是的,当图像不是完全正方形并且其 DPI 与屏幕 DPI 不同时,这可能是一个问题。我将为此更新代码,它可能很有用。顺便说一句,看看这个答案:Image is not drawn at the correct spot。代码是C#,但如果您不会说该语言,您只需要备注即可。
  • 效果很好 - 这非常方便。谢谢!
  • 大声笑,说这种语言,它不是“口语”写的。
【解决方案2】:

还有一些东西你也可以试试,可能不专业但是很管用。将图像分成两半。在其中一个面板上绘制前半部分,在另一个面板上绘制后半部分。 请务必在您的项目中导入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 课程的更多信息,请查看此链接Bitmap Class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    • 2012-07-26
    • 2012-02-29
    • 1970-01-01
    相关资源
    最近更新 更多