Here is a test application which demonstrates how to work with transparent images in picture box.
using System;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace Test
{
class Program
{
static Image GetBackImage()
{
Bitmap bmp = new Bitmap(400, 200);
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(Brushes.LightSteelBlue, new Rectangle(0, 0, bmp.Width, bmp.Height));
for (int i = 5; i < bmp.Height; i += 20)
for (int j = 5; j < bmp.Width; j += 20)
g.FillRectangle(Brushes.DarkBlue, new Rectangle(j, i, 10, 10));
}
// Alterntively, load image from file
return bmp;
}
static Image GetForeImage()
{
Bitmap bmp = new Bitmap(30, 30);
Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(Brushes.White, r);
g.FillEllipse(Brushes.DarkRed, r);
bmp.MakeTransparent(Color.White);
}
// Alterntively, load image from file
return bmp;
}
static Form CreateForm(ref PictureBox picBox)
{
Form f = new Form();
f.Text = "Image test";
f.FormBorderStyle = FormBorderStyle.FixedDialog;
f.Size = new Size(500, 500);
f.MinimizeBox = true;
f.MaximizeBox = false;
f.ControlBox = true;
picBox = new PictureBox();
picBox.BorderStyle = BorderStyle.None;
_backImage = GetBackImage();
picBox.Size = _backImage.Size;
picBox.Image = _backImage;
picBox.Left = (f.ClientRectangle.Width - picBox.Width) / 2;
picBox.Top = (f.ClientRectangle.Height - picBox.Height) / 2;
f.Controls.Add(picBox);
return f;
}
static Image CombineImages(Image back, Image fore, PointF pf)
{
Image combined = back.Clone() as Image;
using (Graphics g = Graphics.FromImage(combined))
{
g.DrawImage(fore, pf);
}
return combined;
}
delegate void SetImageDelegate(PictureBox pb, Image img);
static void SetImage(PictureBox pb, Image img)
{
pb.Image = img;
}
static void TimerEllapsed(object state)
{
lock (_sync)
{
if (_foreImage == null)
_foreImage = GetForeImage();
int steps = 200;
float height = (_backImage.Height + _foreImage.Height) * _iteration / (float)steps - _foreImage.Height;
float width = (_backImage.Width + _foreImage.Width) * _iteration / (float)steps - _foreImage.Width;
_iteration = (_iteration + 1) % steps;
Image img = CombineImages(_backImage, _foreImage, new PointF(width, height));
PictureBox pb = state as PictureBox;
pb.BeginInvoke(new SetImageDelegate(SetImage), pb, img);
}
}
static void Main(string[] args)
{
_form = CreateForm(ref _pictureBox);
_form.HandleCreated += new EventHandler(FormHandleCreated);
_form.ShowDialog();
}
static void FormHandleCreated(object sender, EventArgs e)
{
_timer = new System.Threading.Timer(new TimerCallback(TimerEllapsed), _pictureBox, 20, 20);
}
static Image _backImage;
static Image _foreImage;
static int _iteration;
static object _sync = new object();
static System.Threading.Timer _timer;
static Form _form;
static PictureBox _pictureBox;
}
}In this code, specific background image is kept aside and it's used to create new image which is set to PictureBox each time when picture has to be changed. At any time, PictureBox has its own image set and nobody is drawing over it.
Before compiling this code, add references to System.Drawing and System.Windows.Forms libraries.
Attached is the compiled executable, hopefully without viruses.
EDIT: Added thread safety. PictureBox is now updated on control's thread rather than thread executing timer.
Edited by zoranh, 08 October 2010 - 12:10 PM.
Added thread safety.