简体   繁体   中英

C# custom picturebox control

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.

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

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

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 PictureBox es 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM