Winforms Label on top of gif - c#

I want to place a Label on top of a gif inside a PictureBox in winforms.
The problem ist that the label has a white background. I want it to be transparent.
My Code is as follows:
this.pictureBox = new PictureBox();
this.pictureBox.Image = Image.FromFile("my_background.gif");
this.pictureBox.Dock = DockStyle.Fill;
this.pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
this.label = new Label();
this.label.Text = "Hallo";
this.label.BackColor = Color.Transparent;
this.label.Location = new System.Drawing.Point(100, 100);
this.Controls.Add(this.label);
this.Controls.Add(this.pictureBox);
My problem is that the Label has a white Background even though the background is set to transparent. The solution for other having a similar problem was setting the parent of the label to the picture Box like this:
this.label.parent = this.pictureBox;
But that didn't solve the problem for me. Is there any other way to achieve this?
Thanks for any answers.

Thanks for the hint.
It worked fine when putting only a view controls in front of the gif. When adding to many it got very buggy and only some rectangular parts of the gif would update.
I solved the problem by splitting my gif into single images and displaying them in the OnPaint Event of the form
this.Paint += new PaintEventHandler(this.Paint_Background);
The Paint Method looked like this.
private void Paint_Background(object sender, PaintEventArgs e)
{
Graphics background_graphics = e.Graphics;
Graphics graphicsObj;
graphicsObj = this.CreateGraphics();
int image_num = ((int)((DateTime.Now - start_time).TotalMilliseconds) / gif_speed) % num_images;
Image background= Image.FromFile("Filename_"+image_num+".jpg");
background_graphics.DrawImage(background, 0, 0, ClientSize.Width, ClientSize.Height);
background.Dispose();
}
All of my Controls where added directly to the view and not the imagebox anymore, as the imagebox was removed entirely.
Maybe this can help someone else too

Related

Dictating Panel and PictureBox Transparency Order

I need a little help understanding transparency order in windows forms. I created a simple form with nothing on it called test.
Within the construction of the form, I created a panel and a picture like so:
public partial class test : Form
{
public test()
{
InitializeComponent();
//create a panel
Panel panel = new Panel();
panel.Location = new Point(10, 10);
panel.Size = new Size(100, 100);
panel.BackColor = Color.FromArgb(255, 0, 0);
panel.Show();
//put panel on screen
this.Controls.Add(panel);
//create a picture box
PictureBox picture = new PictureBox();
picture.ImageLocation = "../myPicture2.png";
picture.Location = new Point(20, 20);
picture.Size = new Size(100, 100);
picture.BackColor = Color.Transparent;
picture.Show();
this.Controls.Add(picture);
picture.BringToFront();
}
}
At first the image I used was myPicture1.png, an image with a white background giving me this result.
But then I cropped out the white background with gimp to make it a transparent background.
However, now the form's background is showing up instead of panel.
When I'm putting this PictureBox on top of the panel I'm trying to keep the background color of the panel behind the Image.
Like this:
Can someone please explain to me how to acheive the desired result of having the panel background behind the transparent image in the picturebox? All advice is greatly appreciated as always!
Isn't this problem caused by the picturebox being on the form instead of being inside the panel?
panel.Controls.Add(picture);

How to create transparent controls in Windows Forms when controls are layered

I am trying to implement a "Fillable Form" in which editable text fields appear over top of an image of a pre-preprinted form for a dot matrix printer. (using c# and Windows Forms and targeting .Net 2.0) My first idea was to use the image as the Windows Form background, but it looked horrible when scrolling and also did not scroll properly with the content.
My next attempt was to create a fixed-size window with a panel that overflows the bounds of the window (for scrolling purposes.) I added a PictureBox to the panel, and added my textboxes on top of it. This works fine, except that TextBoxes do not support transparency, so I tried several methods to make the TextBoxes transparent. One approach was to use an odd background color and a transparency key. Another, described in the following links, was to create a derived class that allows transparency:
Transparency for windows forms textbox
TextBox with a Transparent Background
Neither method works, because as I have come to find out, "transparency" in Windows Forms just means that the background of the window is painted onto the control background. Since the PictureBox is positioned between the Window background and the TextBox, it gives the appearance that the TextBox is not transparent, but simply has a background color equal to the background color of the Window. With the transparency key approach, the entire application becomes transparent so that you can see Visual Studio in the background, which is not what I want. So now I am trying to implement a class that derives from TextBox and overrides either OnPaint or OnPaintBackground to paint the appropriate part of the PictureBox image onto the control background to give the illusion of transparency as described in the following link:
How to create a transparent control which works when on top of other controls?
First of all, I can't get it working (I have tried various things, and either get a completely black control, or just a standard label background), and second of all, I get intermittent ArgumentExceptions from the DrawToBitmap method that have the cryptic message "Additional information: targetBounds." Based on the following link from MSDN, I believe that this is because the bitmap is too large - in either event it seems inefficient to capture the whole form image here because I really just want a tiny piece of it.
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.drawtobitmap(v=vs.100).aspx
Here is my latest attempt. Can somebody please help me with the OnPaintBackground implementation or suggest a different approach? Thanks in advance!
public partial class TransparentTextbox : TextBox
{
public TransparentTextbox()
{
InitializeComponent();
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint, true);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e); // not sure whether I need this
if (Parent != null)
{
foreach (Control c in Parent.Controls)
{
if (c.GetType() == typeof(PictureBox))
{
PictureBox formImg = (PictureBox)c;
Bitmap bitmap = new Bitmap(formImg.Width, formImg.Height);
formImg.DrawToBitmap(bitmap, formImg.Bounds);
e.Graphics.DrawImage(bitmap, -Left, -Top);
break;
}
}
Debug.WriteLine(Name + " didn't find the PictureBox.");
}
}
}
NOTE: This has been tagged as a duplicate, but I referenced the "duplicate question" in my original post, and explained why it was not working. That solution only works if the TextBox sits directly over the Window - if another control (such as my Panel and PictureBox) sit between the window and the TextBox, then .Net draws the Window background onto the TextBox background, effectively making its background look gray, not transparent.
I think I have finally gotten to the bottom of this. I added a Bitmap variable to my class, and when I instantiate the textboxes, I am setting it to contain just the portion of the form image that sits behind the control. Then I overload OnPaintBackground to display the Bitmap, and I overload OnPaint to manually draw the text string. Here is the updated version of my TransparentTextbox class:
public partial class TransparentTextbox : TextBox
{
public Bitmap BgBitmap { get; set; }
public TransparentTextbox()
{
InitializeComponent();
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawString(this.Text, this.Font, Brushes.Black, new PointF(0.0F, 0.0F));
}
protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.DrawImage(BgBitmap, 0, 0);
}
}
... and here is the relevant part of how I instantiate:
Bitmap bgImage = (Bitmap)Bitmap.FromStream(Document.FormImage);
PictureBox pb = new PictureBox();
pb.Image = bgImage;
pb.Size = pb.Image.Size;
pb.Top = 0;
pb.Left = 0;
panel1.Controls.Add(pb);
foreach (FormField field in Document.FormFields)
{
TransparentTextbox tb = new TransparentTextbox();
tb.Width = (int)Math.Ceiling(field.MaxLineWidth * 96.0);
tb.Height = 22;
tb.Font = new Font("Courier", 12);
tb.BorderStyle = BorderStyle.None;
tb.Text = "Super Neat!";
tb.TextChanged += tb_TextChanged;
tb.Left = (int)Math.Ceiling(field.XValue * 96.0);
tb.Top = (int)Math.Ceiling(field.YValue * 96.0);
tb.Visible = true;
Bitmap b = new Bitmap(tb.Width, tb.Height);
using (Graphics g = Graphics.FromImage(b))
{
g.DrawImage(bgImage, new Rectangle(0, 0, b.Width, b.Height), tb.Bounds, GraphicsUnit.Pixel);
tb.BgBitmap = b;
}
panel1.Controls.Add(tb);
}
I still need to work on how the text looks when I highlight it, and other things like that, but I feel like I am on the right track. +1 to Reza Aghaei and Mangist for commenting with other viable solutions!

Best way to make images scrollable that where painted on the control

I draw images (lets say 200x200) on control in C# depending on how many there are (could be over 100) they get drawn offscreen since they are stacked one above the other. What is the best way to make a dynamic scroll so that i can scroll to the ones that are offscreen.
I was thinking of using a Panel and painting them on there and then just place the Panel on the control. But with the panel being transparent and the control on which the panel is sitting is changing its image (its a map that you can move with draging) the panel lags behind when drawing and creates a ugly jitter effect.
So are there any good solutions where i wont need to implement the whole logic of a scroller myself for such a solution?
PictureBox is doublebuffered and will take care of the flicker.
For your case don't draw onto a control, no matter which, but instead draw into a PictureBox's Image.
Put the PictureBox inside an autoscroll panel and make it a large as the Size you need. No jitter, smooth scrolling..
Here is an example. It randomly draws around 200 small images into the Image of a PictureBox. I create the Image with a large size and I put the PB into a Panel:
Random R = new Random();
private void button1_Click(object sender, EventArgs e)
{
panel1.AutoScroll = true;
pictureBox1.Parent = panel1;
pictureBox1.Location = Point.Empty;
pictureBox1.Image = new Bitmap(3000, 500);
pictureBox1.ClientSize = pictureBox1.Image.Size;
var imgFiles = Directory.GetFiles(#"D:\scrape\", "*.png");
foreach(string file in imgFiles)
{
using (Graphics G = Graphics.FromImage(pictureBox1.Image))
using (Bitmap bmp = new Bitmap(file))
{
if (bmp.Size.Width < 300)
{
for (int i = 0; i < 10; i++ )
G.DrawImage(bmp, R.Next(2500), R.Next(400));
}
}
}
}
You can easily adapt it to your own project, I'm sure..

How can I correctly align an image to the right edge of a "Label"?

Using a standard Label I aligned my image to the right side.
However there is a small indent (marked in red) that I cannot remove.
So my question: Is there an easy way to correctly align/snap an image to the right edge of a label? Or do I need to edit the label paint method so I can manually draw the image?
The label in question sits inside a "Panel", the following is my code:
label1.BackColor = System.Drawing.Color.Red;
label1.Image = global::TestProject.Properties.Resources.Header;
label1.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
label1.Size = new System.Drawing.Size(200, 40);
The simple answer appears to be: No there is no easy way to correctly align the image.
The "PictureBox" seems like the preferred component for working with images, however the image can be correctly aligned by editing the paint method of the label:
label1.Paint += new System.Windows.Forms.PaintEventHandler(this.label1_Paint);
And the paint method:
private void label1_Paint(object sender, PaintEventArgs e)
{
Image image = global::TestProject.Properties.Resources.Header;
Graphics g = e.Graphics;
//Align to far right: label width - image width
g.DrawImage(image, this.label1.Width - image.Width, 0);
}

set panel border thickness in c# winform

I have searching and the result cannot solve my case.
Actually I have a panel and I want the panel have thicker border than Windows given.
I need BorderStyle
BorderStyle.FixedSingle
thicker..
Thanks before
You have to customize your own Panel with a little custom painting:
//Paint event handler for your Panel
private void panel1_Paint(object sender, PaintEventArgs e){
if(panel1.BorderStyle == BorderStyle.FixedSingle){
int thickness = 3;//it's up to you
int halfThickness = thickness/2;
using(Pen p = new Pen(Color.Black,thickness)){
e.Graphics.DrawRectangle(p, new Rectangle(halfThickness,
halfThickness,
panel1.ClientSize.Width-thickness,
panel1.ClientSize.Height-thickness));
}
}
}
Here is the screen shot of panel with thickness of 30:
NOTE: The Size of Rectangle is calculated at the middle of the drawing line, suppose you draw line with thickness of 4, there will be an offset of 2 outside and 2 inside.
I didn't test the case given by Mr Hans, to fix it simply handle the event SizeChanged for your panel1 like this:
private void panel1_SizeChanged(object sender, EventArgs e){
panel1.Invalidate();
}
You can also setting ResizeRedraw = true using Reflection without having to handle the SizeChanged event as above like this:
typeof(Control).GetProperty("ResizeRedraw", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(panel1, true, null);
You may see a little flicker when resizing, just add this code to enable doubleBuffered for your panel1:
typeof(Panel).GetProperty("DoubleBuffered",
BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(panel1,true,null);
To create a panel with border I place a panel in a panel. The "border panel" has the background color of the wanted border color and a padding, while the padding size is the wanted border thickness.
The advantage of this solution is that there is no flickering and no problems with resize.
This can be very simple be created in the designer or in code behind.
Code behind:
Panel panel_Border = new Panel();
Panel panel_Embedded = new Panel();
panel_Border.BackColor = Color.Green;
panel_Border.Controls.Add(panel_Embedded);
// this is the border thickness
panel_Border.Padding = new System.Windows.Forms.Padding(6);
panel_Border.Size = new System.Drawing.Size(200, 100);
panel_Embedded.BackColor = System.Drawing.SystemColors.Control;
panel_Embedded.Dock = System.Windows.Forms.DockStyle.Fill;
Create a new, slightly larger panel and set the background colour to Black (or whatever). Place the original panel INSIDE the larger panel.

Categories