C#自定义picturebox控件

C#自定义picturebox控件,c#,bitmap,custom-controls,paint,picturebox,C#,Bitmap,Custom Controls,Paint,Picturebox,我在一个项目中工作,在这个项目中,我需要不断地获取位图并将它们绘制在一个图片盒上 其思想是绘制第一个初始位图,然后检索位图的其余部分,并在初始位图上方绘制它们。(第一个仍然显示在picturebox中,因此我想在第一个位图上绘制它们) 我试图设计一个自定义控件来实现OnPaint事件,但第二次触发该事件时,它会绘制第二个块,并完全隐藏以前绘制的图像 public class RapidPictureBox: PictureBox { public pictureBox1Control()

我在一个项目中工作,在这个项目中,我需要不断地获取位图并将它们绘制在一个图片盒上

其思想是绘制第一个初始位图,然后检索位图的其余部分,并在初始位图上方绘制它们。(第一个仍然显示在picturebox中,因此我想在第一个位图上绘制它们)

我试图设计一个自定义控件来实现
OnPaint
事件,但第二次触发该事件时,它会绘制第二个
,并完全隐藏以前绘制的图像

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.
}

我不确定代码中出了什么问题。每次需要时,我都使用
e
EventArgs来绘制一个新块,但新的图形似乎完全隐藏了以前的位图。

代码的问题是,您没有将图片添加到要替换的控件中

旁注:使用您拥有的代码,您不会处理
PictureBox
es图像中设置的
位图
对象,因此这可能会导致内存泄漏

您可以创建类似的控件
LayeredPictureBox
。这将获得所有图像,并将它们相互叠加。它的性能很差,图像需要有透明度才能看起来分层,但你知道了:

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.
}
公共类分层PictureBox:PictureBox
{
公共分层PictureBox()
{
固定方式(
ControlStyles.AllPaintingWimPaint|
ControlStyles.OptimizedDubleBuffer|
ControlStyles.UserPaint|
ControlStyles.ResizerDraw,true);
}
公共列表块=新列表();
公共整数x=0,y=0;
受保护的覆盖无效OnPaint(PaintEventArgs e)
{
foreach(块中的位图块)
{
e、 图形.绘图图像(块,x,y);
}
}
}
私有void Form1\u加载(对象发送方、事件参数e)
{  
RapidPictureBox pictureBox1=新的RapidPictureBox();
pictureBox1.Dock=DockStyle.Fill;
控件。添加(pictureBox1);
pictureBox1.blocks.Add(新位图(“3.png”);//第一个初始图像
pictureBox1.blocks.Add(新位图(“2.png”);//在初始位图上绘制。
}

另一种选择是在添加图像时将所有图像合并在一起,然后将该图像绘制到PictureBox中。

代码的问题是,您没有将图像添加到要替换的控件中

旁注:使用您拥有的代码,您不会处理
PictureBox
es图像中设置的
位图
对象,因此这可能会导致内存泄漏

您可以创建类似的控件
LayeredPictureBox
。这将获得所有图像,并将它们相互叠加。它的性能很差,图像需要有透明度才能看起来分层,但你知道了:

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.
}
公共类分层PictureBox:PictureBox
{
公共分层PictureBox()
{
固定方式(
ControlStyles.AllPaintingWimPaint|
ControlStyles.OptimizedDubleBuffer|
ControlStyles.UserPaint|
ControlStyles.ResizerDraw,true);
}
公共列表块=新列表();
公共整数x=0,y=0;
受保护的覆盖无效OnPaint(PaintEventArgs e)
{
foreach(块中的位图块)
{
e、 图形.绘图图像(块,x,y);
}
}
}
私有void Form1\u加载(对象发送方、事件参数e)
{  
RapidPictureBox pictureBox1=新的RapidPictureBox();
pictureBox1.Dock=DockStyle.Fill;
控件。添加(pictureBox1);
pictureBox1.blocks.Add(新位图(“3.png”);//第一个初始图像
pictureBox1.blocks.Add(新位图(“2.png”);//在初始位图上绘制。
}

另一种选择是在添加图像时将所有图像合并在一起,然后将该图像绘制到PictureBox中。

您应该做的是将新图像覆盖到以前的图像上。 假设有一个主图像(第一个图像),您希望在该主图像上打印下一个图像(重叠图像)。使用以下方法来完成此操作

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;
}
然后将此新图像设置为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.
}
那应该对你有用

注意:您应该在使用图像后处理它们

更新: 您需要重画整个图像,因为只有当图片框上显示的当前图像需要重画时,才会调用OnPaint。 OnPaint方法被重写,以便在每次绘制窗体时重新绘制图像;否则,图像将仅持续到下一次重新绘制。
阅读OnPaint的文档

您应该做的是将新图像覆盖在前一图像上。 假设有一个主图像(第一个图像),您希望在该主图像上打印下一个图像(重叠图像)。使用以下方法来完成此操作

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;
}
然后将此新图像设置为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.
}
那应该对你有用

注意:您应该在使用图像后处理它们

更新: 您需要重画整个图像,因为只有当图片框上显示的当前图像需要重画时,才会调用OnPaint。 OnPaint方法被重写,以便在每次绘制窗体时重新绘制图像;否则,图像将仅持续到下一次重新绘制。
阅读OnPaint的文档

您可以从picturebox创建图形对象,然后在当前图像上重新绘制它

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

您可以从picturebox创建图形对象,然后在当前图像上重新绘制它

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

实际上,你不知道的是,每次刷新时,控件都会画出整个列表……这太糟糕了。我将在这里告诉大家一个简短的想法:这是一个屏幕共享项目,在这个项目中,我从一个套接字接收一个完整的deksopt位图,然后我从套接字中检索许多小位图块,并需要在一个picturebox中更新它们,该picturebox将提供一个更新的桌面图像-@Slashy我知道这很糟糕,我说,这是一个非常基本的id