如何将我在Panel上绘制的形状保存为二进制

时间:2016-11-13 15:44:09

标签: c# .net winforms serialization gdi+

我有一个迷你颜料程序。我想创建一个保存按钮,将面板细节(形状和正在绘制的所有内容)保存为二进制文件。我这样做了:

 SaveFileDialog sfd = new SaveFileDialog();
 BinaryFormatter bf = new BinaryFormatter();
 var stream = new BinaryReader(File.Open(sfd.FileName,FileMode.Create));
 bf.Serialize(stream,object);

但是它在bf.Serialize中使用对象无效时出错。我该怎么做?

1 个答案:

答案 0 :(得分:4)

您无需序列化面板,面板不可序列化。您可以考虑以下任一选项:

  1. 您可以在位图上绘图然后保存位图,或将控件绘制到图像并保存图像。这样,您可以将所有形状展平为单个图像,并且在加载图像后,它们不再是可编辑的形状。这就像油漆。
  2. 您可以使形状可序列化,然后在文件中序列化可序列化形状的列表。然后你可以再次反序列化它们。这样,您可以加载形状并让用户编辑它们,例如像Visio。
  3. 我在这里分享了两个例子:

    • 保存图像示例:它只是将您在面板上绘制的图形保存到位图图像文件中。

    • 序列化示例:在此示例中,我创建了一些可序列化的形状类,其中包含一些属性,如坐标和颜色,然后我创建了一个SaveLoad方法,允许您序列化文件中的形状,并从文件中反序列化它们并再次显示它们。您可以简单地扩展此示例以添加一些功能,如命中测试和移动形状。您也可以使用xml序列化程序而不是二进制序列化程序。

    保存图片示例

    为了简化这个例子,我只是将面板绘画保存在一个文件中。

    如果您将绘画逻辑放在面板的Paint事件中,则可以使用DrawToBitmap将控件的图像保存到文件中:

    private void button1_Click(object sender, EventArgs e)
    {
        using (var bm = new Bitmap(panel1.Width, panel1.Height))
        {
            panel1.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
            bm.Save(@"d:\panel.bmp", System.Drawing.Imaging.ImageFormat.Bmp); 
        }
    }
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.FillRectangle(Brushes.Red, 0, 0, 100, 100);
        e.Graphics.FillRectangle(Brushes.Blue, 50, 50, 100, 100);
    }
    

    序列化示例

    您可以创建一些可序列化的形状,例如来自可序列化LineShape类的RectangleShapeShape。我们在这个类中存储形状的属性,这些类也包含绘图逻辑:

    [Serializable]
    public abstract class Shape
    {
        public abstract void Draw(Graphics g);
        public override string ToString() { return GetType().Name; }
    }
    
    [Serializable]
    public class LineShape : Shape
    {
        public LineShape(){ Color = Color.Blue; Width = 2; }
        public Point Point1 { get; set; }
        public Point Point2 { get; set; }
        public int Width { get; set; }
        public Color Color { get; set; }
        public override void Draw(Graphics g)
        {
            using (var pen = new Pen(Color, Width))
                g.DrawLine(pen, Point1, Point2);
        }
    }
    
    [Serializable]
    public class RectangleShape : Shape
    {
        public RectangleShape() { Color = Color.Red; }
        public Rectangle Rectangle { get; set; }
        public Color Color { get; set; }
        public override void Draw(Graphics g)
        {
            using (var brush = new SolidBrush(Color))
                g.FillRectangle(brush, Rectangle);
        }
    }
    

    您可以创建一个ShapesList类来保存形状并包含用于保存和加载形状的逻辑。也是在表面上绘制所有形状的逻辑:

    [Serializable]
    public class ShapesList : List<Shape>
    {
        public void Save(string file)
        {
            using (Stream stream = File.Open(file, FileMode.Create))
            {
                BinaryFormatter bin = new BinaryFormatter();
                bin.Serialize(stream, this);
            }
        }
        public void Load(string file)
        {
            using (Stream stream = File.Open(file, FileMode.Open))
            {
                BinaryFormatter bin = new BinaryFormatter();
                var shapes = (ShapesList)bin.Deserialize(stream);
                this.Clear();
                this.AddRange(shapes);
            }
        }
        public void Draw(Graphics g)
        {
            this.ForEach(x => x.Draw(g));
        }
    }
    

    然后你可以用这种方式使用这些形状和形状:

    ShapesList Shapes;
    private void Form3_Load(object sender, EventArgs e)
    {
        Shapes = new ShapesList();
        Shapes.Add(new RectangleShape() { Rectangle = new Rectangle(0, 0, 100, 100), 
            Color = Color.Green });
        Shapes.Add(new RectangleShape() { Rectangle = new Rectangle(50, 50, 100, 100), 
            Color = Color.Blue });
        Shapes.Add(new LineShape() { Point1 = new Point(0, 0), Point2 = new Point(150, 150), 
            Color = Color.Red });
        this.panel1.Invalidate();
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        Shapes.Save(@"d:\shapes.bin");
        Shapes.Clear();
        this.panel1.Invalidate();
        MessageBox.Show("Shapes saved successfully.");
        Shapes.Load(@"d:\shapes.bin");
        this.panel1.Invalidate();
        MessageBox.Show("Shapes loaded successfully.");
    }
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        Shapes.Draw(e.Graphics);
    }