3

I'm doing an application with a splash screen.

I've an image an I'd like to put below a progress bar like :

Example

Example

I've succeeded to make the bitmap transparent. But, now, the image is behind the progress bar

Now

Now

Is there a way to get the image in front of the progress bar ? Thank you. F.

Code :

public partial class Form1 : Form
{
    Bitmap m_l;
    public Form1()
    {
        InitializeComponent();

        m_l = Properties.Resources.LU;

        m_l.MakeTransparent(Color.Transparent);
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.DrawImage(m_l, new Rectangle(new Point(0, -40), new Size(200, 264))); progressBar1.Refresh();
    }
}
Rand Random
  • 7,300
  • 10
  • 40
  • 88
Florence
  • 55
  • 1
  • 11
  • It would be awesome if you could provide a [mcve]. – mjwills Sep 19 '18 at 13:50
  • possible duplicate (https://stackoverflow.com/questions/3213270/how-to-set-z-order-of-a-control-using-winforms) – Ryan Wilson Sep 19 '18 at 13:52
  • The standard progressbar doesn't support this afaik. You can write your own. Many examples, yours for the searching.. – TaW Sep 19 '18 at 13:53
  • @TaW - what is there not to support - he just wants to overlay the progressbar with an image? - this should help https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-layer-objects-on-windows-forms – Rand Random Sep 19 '18 at 13:55
  • 1
    Well, if you can get it to work, why not post an answer..? – TaW Sep 19 '18 at 13:58
  • Could give this a try - http://www.richardhyland.com/diary/2009/05/26/how-to-truely-make-a-picturebox-background-transparent/ - works well enough for me – Rand Random Sep 19 '18 at 15:23
  • @TaW - FYI see my previous comment – Rand Random Sep 19 '18 at 15:25
  • Shrug. We are __not__ talking about `PictureBoxes` but `ProgressBar`, which is an animated control.. See my answer! – TaW Sep 19 '18 at 15:33
  • 1
    @TaW - see my answer – Rand Random Sep 19 '18 at 16:07
  • Hm, interesting. At least for images without semi-transparent pixels a __region__ is indeed an option. I was totally fixed on semi-transparent images. OP may well get away with that! – TaW Sep 19 '18 at 17:01
  • [How to make two transparent layer with c#?](https://stackoverflow.com/a/36102074/3110834) or [Show a Label with semi-transparent BackColor above other controls?](https://stackoverflow.com/a/34338985/3110834) or [C# Windows Form Transparent Background Image](https://stackoverflow.com/a/33531201/3110834) – Reza Aghaei Sep 19 '18 at 20:03

4 Answers4

3

(sorry, for missuing the answer function but the answer is to long for a comment)

@TaW seems like you didnt quite understand the approach, so I will try to explain it in more detail

OP asked if he can make a transparant Image over another control (a progressbar)

I assumed this transparent Image is inside a PictureBox, you seem to assume some other control

to position the control, if my assumption is correct the picturebox, infront of the progress bar all he has to do is right click and click "Bring to Front" on the PictureBox

and there you have it a "transparent" PictureBox infront of a progressbar - but as you mentioned in your answer we cannot stop there since the "transparent" isnt what I expected, but obviously you knew - its this "parent background color picking" that WinForms does and we end up with a not fully transparent image infront of the ProgressBar but instead one with a gray Background

Now the posted url comes in place: http://www.richardhyland.com/diary/2009/05/26/how-to-truely-make-a-picturebox-background-transparent/

This is the code provided, and explained in that url:

public static System.Drawing.Drawing2D.GraphicsPath Transparent(Image im)
{
    int x;
    int y;
    Bitmap bmp = new Bitmap(im);
    System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
    Color mask = bmp.GetPixel(0, 0);

    for (x = 0; x <= bmp.Width - 1; x++)
    {
        for (y = 0; y <= bmp.Height - 1; y++)
        {
            if (!bmp.GetPixel(x, y).Equals(mask))
            {
                gp.AddRectangle(new Rectangle(x, y, 1, 1));
            }
        }
    }
    bmp.Dispose();
    return gp;
}

With this we can achieve a fully transparent Picture box infront of a Progress bar.

So without this Code, we have this:

But with that Code:

Notice, this approach has some downsides:

  1. doesn't work perfectly - as you can see gray pixels around the edges of the image
  2. performs poorly on big Images - since getting each pixel with GetPixel is "challange"

(Please, ignore the fact that the image shows "JPG" and I am talking about transparent Images - this was just the first image Google search presented me and yes, the file is a transparent png)

Rand Random
  • 7,300
  • 10
  • 40
  • 88
  • The answer should include the code, properly attributed, in case that link goes stale. Using GetPixel on a large image is going to have poor performance. – LarsTech Sep 19 '18 at 16:12
  • @LarsTech - updated my "answer" to reflect your comment – Rand Random Sep 19 '18 at 16:21
  • Note that to get around the GetPixel performance issue you can use LockBits. Optimizing the Region to contain less one pixel Rectangles would be a greater challenge. As it stands it has as many Rectangles as there are non-transparent pixels. But here this is surely not necessary.. – TaW Sep 20 '18 at 09:03
3

You can accomplish this using a PictureBox with a Region.

Add a PictureBox to your form. This will hold the image. Position it to overlap the ProgressBar as you would like. Set the Image property to your overlay image.

In the form constructor we're then going to set the Region of this PictureBox. The region defines the shape of the control. We're going to set the Region equal to the non-transparent parts of the image.

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
    pictureBox1.Region = CreateRegion(Properties.Resources.LU);
  }

  private static Region CreateRegion(Bitmap maskImage)
  {
    // We're using pixel 0,0 as the "transparent" color.
    Color mask = maskImage.GetPixel(0, 0);
    GraphicsPath graphicsPath = new GraphicsPath();
    for (int x = 0; x < maskImage.Width; x++)
    {
      for (int y = 0; y < maskImage.Height; y++)
      {
        if (!maskImage.GetPixel(x, y).Equals(mask))
        {
          graphicsPath.AddRectangle(new Rectangle(x, y, 1, 1));
        }
      }
    }

    return new Region(graphicsPath);
  }
}

Screenshot of form

Much of this code came from here

gunnerone
  • 3,566
  • 2
  • 14
  • 18
  • 1
    That code looks pretty close to another answer, which was from another post. You should properly attribute the author of that code. – LarsTech Sep 19 '18 at 16:23
0

There are 5 6 options:

  1. You could set the ProgressBar's BackColor to Transparent. Result:

enter image description here

Translation:

Invalid property value. This control does not support a transparent backcolor.

This will hold true for a subclass as well.

  1. You could nest a transparent Panel with the image as its BackgroundImage. Result:

enter image description here

As you can see, despite the panel and most of the image being transparent, the progressbar still underlays it with a rectangle in its own BackColor; which, see above, can't be transparent.

  1. You could overlay with the panel.

Result:

enter image description here

Looks similar. But this time the backcolor is the original background of wherever the panel was before overlaying it. This is the way winforms fakes transparency; this faked transpareny will only work with nested controls, but not with all..

  1. You could draw your image in the progressbar's Paint event. Problem: It doesn't have one. And if you subclass it it will not work for you.

To sum it up: all those attempts fail; the conclusion is simple: ProgressBar is an animated control that won't support any messing with it.

  1. Last option: Write your own. You can subclass a Panel or Label and write your own progressbar. Many folks who wanted to have a custom look, have done this and you can find many ready made examples.

Upate: Looks like you can have a 6th option, which will work if and only if you don't need semi-transparency, like anti-aliasing etc..: You can create a GraphicsPath to create a Region which will mask some control with the image.. So while my example will not work, OP's image may look quite OK.

TaW
  • 53,122
  • 8
  • 69
  • 111
0

as ways, people are developers but seams to have a really weak logic, post code and link the rest to a site that can die at any time, here the 2 missing line of the answer

public static System.Drawing.Drawing2D.GraphicsPath Transparent(Image im)  
    {  
        int x;  
        int y;  
        Bitmap bmp = new Bitmap(im);  
        System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();  
        Color mask = bmp.GetPixel(0, 0);  

        for (x = 0; x <= bmp.Width - 1; x++)  
        {  
            for (y = 0; y <= bmp.Height - 1; y++)  
            {  
                if (!bmp.GetPixel(x, y).Equals(mask))  
                {  
                    gp.AddRectangle(new Rectangle(x, y, 1, 1));  
                }  
            }  
        }  
        bmp.Dispose();  
        return gp;  

use:

System.Drawing.Drawing2D.GraphicsPath gp = Resources.Images.Transparent(pictureBox1.Image);  
pictureBox1.Region = new System.Drawing.Region(gp);  
Marcos
  • 57
  • 6