0
votes

I work on a project where I need to constantly get bitmaps and draw them on a picturebox.

The idea is to draw a first initial bitmap, then retrive the rest of the bitmap and draw them above the initial one. (The first one still displayed in the picturebox, so I want to draw them on the first bitmap).

I tried to design a custom control, to implement the OnPaint event, but the second time the event is fired, it draws the second block and completely conceals the image which had been drawn before.

public class RapidPictureBox: PictureBox
{
    public pictureBox1Control()
    {
        SetStyle(
          ControlStyles.AllPaintingInWmPaint |
          ControlStyles.OptimizedDoubleBuffer |
          ControlStyles.UserPaint |
          ControlStyles.ResizeRedraw, true);
    }

     public Bitmap block = null;
     public int x = 0, y = 0;
     protected override void OnPaint(PaintEventArgs e)
     {
         e.Graphics.DrawImage(block, x, y);
     }
 }

private void Form1_Load(object sender, EventArgs e)
{  
    RapidPictureBox pictureBox1 = new RapidPictureBox();
    pictureBox1.Dock = DockStyle.Fill;
    Controls.Add(pictureBox1);

    pictureBox1.block = new Bitmap("3.png"); //first initial image

    pictureBox1.block = new Bitmap("2.png"); //draw on the initial one.
}

I'm not sure what's wrong in the code. I use the e EventArgs to draw a new block everytime I need but it seems the new drawing compeletly hides the previous bitmap.

3
You have marked Shlomi's answer as your accepted answer. How is that fixing your problem? Any image you draw with graphics object you get using pictureBox1.CreateGraphics() will be wiped immediately without redrawing it again in OnPaint overridden method.Kamalesh Wankhede
@user12572 no, without a custom control ,if i'll just use picturebox and create a graphics object from it,it would draw on top of the current image.You can see for yourself.at least here i only draw one block everyime and not the whole image.Slashy
Got it! So you need to draw second image repeatedly but no need to draw first image. Nice :)Kamalesh Wankhede
@user12572 not only the second,it's ,many small images i'm getting but yeah :)Slashy

3 Answers

2
votes

you can create a graphics object from the picturebox,then redraw it over the current image

initial =new Bitmap("test.png");
pictureBox1.Image = initial;
var graphics = pictureBox1.CreateGraphics(); //create a graphic objec
graphics.DrawImage(block, x,y);//that's the second method
1
votes

What you should do is overlay the new image on previous image. Let's say there is a primary image (first image) and you want to print next image(overlapping image) on that same primary image. Use following method to do that.

private Bitmap GetOvelappedImages(Bitmap primaryImage, Bitmap overlappingImage)
{
 //create graphics from main image
 using (Graphics g = Graphics.FromImage(primaryImage))
 {
    //draw other image on top of main Image
     g.DrawImage(overlappingImage, new Point(0, 0));
 }
 return primaryImage;
}

then set this new image to pictureBox1.block.

private void Form1_Load(object sender, EventArgs e)
{  
    RapidPictureBox pictureBox1 = new RapidPictureBox();
    pictureBox1.Dock = DockStyle.Fill;
    Controls.Add(pictureBox1);

    pictureBox1.block = GetOverlappedImages(new Bitmap("3.png"),new Bitmap("2.png")); //draw on the initial one.
}

That should work for you.

Note: You should dispose images after they are used.

Update: You need to redraw whole image because, OnPaint is called only when current image shown on picture box needs to be redrawn. The OnPaint method is overridden to repaint the image each time the form is painted; otherwise the image would only persist until the next repainting. Read documentation for OnPaint here

0
votes

The problem with your code is that you are not adding pictures to the control you are replacing them.

Side Note: With the code you have you are not disposing of the Bitmap objects set in the PictureBoxes image and so this could cause memory leaks.

You can create a similar control LayeredPictureBox. This will get all of the images and draw them on top of each other. It will have poor performance and the images will need to have transparency to look layered but you get the idea:

public class LayeredPictureBox : PictureBox
{
    public LayeredPictureBox()
    {
        SetStyle(
          ControlStyles.AllPaintingInWmPaint |
          ControlStyles.OptimizedDoubleBuffer |
          ControlStyles.UserPaint |
          ControlStyles.ResizeRedraw, true);
    }

     public List<Bitmap> blocks = new List<Bitmap>();
     public int x = 0, y = 0;
     protected override void OnPaint(PaintEventArgs e)
     {
         foreach (Bitmap block in blocks)
         {
             e.Graphics.DrawImage(block, x, y);
         }
     }
 }

private void Form1_Load(object sender, EventArgs e)
{  
    RapidPictureBox pictureBox1 = new RapidPictureBox();
    pictureBox1.Dock = DockStyle.Fill;
    Controls.Add(pictureBox1);

    pictureBox1.blocks.Add(new Bitmap("3.png")); //first initial image

    pictureBox1.blocks.Add(new Bitmap("2.png")); //draw on the initial one.
}

Another option is to merge all of the images together on adding them and then just drawing that image into the PictureBox.