26

I am working on a Windows Forms application in VS 2008, and I want to display one image over the top of another, with the top image being a gif or something with transparent parts.

Basically I have a big image and I want to put a little image on top if it, so that they kinda appear as one image to the user.

I've been trying to use a picturebox, but this doesn't seem to have worked, any suggestions?

Fiona
  • 7,747
  • 4
  • 19
  • 8
  • Duplicate question answered here (same applies to C#)- http://stackoverflow.com/questions/394426/how-vbnet-handles-image-transparency-with-images-thatre-on-top-of-each-other#394478 http://stackoverflow.com/questions/392257/transparency-for-images-in-visual-basic-net#392264 – user21826 Dec 28 '08 at 20:44
  • Link to duplicate answer is broken – Christian Gibbs Dec 05 '19 at 02:23

6 Answers6

28

I was in a similar situation a couple of days ago. You can create a transparent control to host your image.

using System;
using System.Windows.Forms;
using System.Drawing;

public class TransparentControl : Control
{
    private readonly Timer refresher;
    private Image _image;

    public TransparentControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        BackColor = Color.Transparent;
        refresher = new Timer();
        refresher.Tick += TimerOnTick;
        refresher.Interval = 50;
        refresher.Enabled = true;
        refresher.Start();
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x20;
            return cp;
        }
    }

    protected override void OnMove(EventArgs e)
    {
        RecreateHandle();
    }


    protected override void OnPaint(PaintEventArgs e)
    {
        if (_image != null)
        {
            e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
       //Do not paint background
    }

    //Hack
    public void Redraw()
    {
        RecreateHandle();
    }

    private void TimerOnTick(object source, EventArgs e)
    {
        RecreateHandle();
        refresher.Stop();
    }

    public Image Image
    {
        get
        {
            return _image;
        }
        set
        {
            _image = value;
            RecreateHandle();
        }
    }
}
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
Leon Tayson
  • 4,741
  • 7
  • 37
  • 36
  • Whats the Hack for I don't see Redraw called internally. When does it need to be called? – Greg Dean Feb 28 '09 at 05:05
  • as you can see, it's Public. IIRC, i encountered a bug when resizing the form of an anchored TransparentControl. I think it disappears from the form, so I put that Redraw method to be called from the form's resize. – Leon Tayson Mar 01 '09 at 01:34
  • works great. The only problem I faced is that unlike the PictureBox, I couldnt set this to auto-resize or stretch. Other than that, it works like a charm. Thanks Leon! – GR7 Feb 24 '10 at 16:05
  • 1
    What's the timer/Refresh for? – Cheeso Apr 15 '10 at 21:05
  • Set `ControlFlags.ResizeRedraw`. – SLaks Jun 08 '10 at 19:37
  • The Redraw() hack was just what I needed! – simon.d Jan 26 '12 at 19:20
  • @Slaks I think you mean: SetStyle(ControlStyles.ResizeRedraw, true); – BillW Feb 05 '14 at 06:55
  • This TransparentControl code was a disaster for me, it wouldn't even paint the image I'd set, it would paint some other part of the UI, at random. Probably because my UI is hidden while repainting... not sure. But unusable for me – PandaWood Dec 15 '14 at 03:23
  • Excelent! But unfortunately, when a control refreshes under the image, it makes the piece of the image that is immediately above it disappear (talking about the z-axis here) – Hellon Nov 27 '18 at 17:52
  • Normally you would use Invalidate() to repaint the image. RecreateHandle() is kind of overkill. – Elmue Oct 06 '20 at 18:47
7

PictureBox has 2 layers of images: BackgroundImage and Image, that you can use independently of each other including drawing and clearing.

Nav
  • 1,185
  • 16
  • 23
4

Put the big/bottom image on a PictureBox, then add a handler to the OnPaint event and use one of the e.Graphics.DrawImage() overloads. You can load the image using Image.FromFile().

The small/top image will have to have an alpha channel and be transparent in the background for the overlay to work. You should be able to ensure this pretty easily in Photoshop or something similar. Make sure you save in a format that supports the alpha channel, such as PNG.

Jon Grant
  • 11,369
  • 2
  • 37
  • 58
3

The vb.net code (All credits to Leon Tayson):

Imports System
Imports System.Windows.Forms
Imports System.Drawing

Public Class TransparentControl
    Inherits Control

    Private ReadOnly Local_Timer As Timer
    Private Local_Image As Image

    Public Sub New()
        SetStyle(ControlStyles.SupportsTransparentBackColor, True)
        BackColor = Color.Transparent
        Local_Timer = New Timer
        With Local_Timer
            .Interval = 50
            .Enabled = True
            .Start()
        End With

        AddHandler Local_Timer.Tick, AddressOf TimerOnClick

    End Sub

    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim cp As CreateParams
            cp = MyBase.CreateParams
            cp.ExStyle = &H20
            Return cp
        End Get
    End Property

    Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
        MyBase.OnMove(e)
        RecreateHandle()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        If Local_Image IsNot Nothing Then _
            e.Graphics.DrawImage(Local_Image, New Rectangle(0, 0, (Width / 2) - (Local_Image.Width / 2), (Height / 2) - (Local_Image.Height / 2)))

    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
        ' DO NOT PAINT BACKGROUND
    End Sub

    ''' <summary>
    ''' Hack
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ReDraw()
        RecreateHandle()
    End Sub

    Private Sub TimerOnClick(ByVal sender As Object, ByVal e As System.EventArgs)
        RecreateHandle()
        Local_Timer.Stop()

    End Sub

    Public Property Image As Image
        Get
            Return Local_Image
        End Get
        Set(ByVal value As Image)
            Local_Image = value
            RecreateHandle()
        End Set
    End Property
End Class
MiBol
  • 1,985
  • 10
  • 37
  • 64
2

A list of similar posts is referenced at the bottom of this reply.

This reply addresses pictureBoxes and Winforms (in the other posts below, several reiterate that WPF solves this well already)

  1. Create Winform
  2. Create x2 pictureBoxes
    • foreground_pictureBox // picture box 'in front' of 'background'
    • background_pictureBox // picture box 'behind' the 'foreground'
  3. Add the 'paint' event for each pictureBox
    • select object in the 'designer'
    • choose the 'properties' tab (or right-click and choose from popup menu)
    • select the events button (small lightning bolt)
    • double-click in the empty field to the right of the 'paint' event
  4. Add the following code to the main form's 'load' function (if not already added, use the approach in step 3 and select 'on load' rather than 'paint')

=

private void cFeedback_Form_Load(object sender, EventArgs e)
{
    ...
    // Ensure that it is setup with transparent background
    foreground_pictureBox.BackColor = Color.Transparent;

    // Assign it's 'background'
    foreground_pictureBox.Parent = background_pictureBox;
    ...
}

5 . In the 'paint' call for the 'background_pictureBox':

=

private void background_pictureBox_Paint(object sender, PaintEventArgs e)
{
    ...foreground_pictureBox_Paint(sender, e);
}

6 . Within the 'foreground_pictureBox_Paint' call, add in whatever graphics calls you want to be displayed in the foreground.

This topic repeats itself in several posts it seems:

how-to-make-picturebox-transparent

c-sharp-picturebox-transparent-background-doesnt-seem-to-work

make-overlapping-picturebox-transparent-in-c-net

a-picturebox-problem

Community
  • 1
  • 1
0

I've always found that I've had to composite the images myself, using a single picturebox or control. Having two pictureboxes with transparent parts has never worked for me.

Charlie Salts
  • 13,109
  • 7
  • 49
  • 78