Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
306 views
in Technique[技术] by (71.8m points)

c# - How to save shapes which I draw on a Panel as binary

I have a mini paint program . I want to create a save button which saves the panel details(shapes and everything that is been drawing) as a binary file. I did this:

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

but it has an error which using object is invalid in bf.Serialize. how should I do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You don't need to serialize the panel, a panel is not serializable. You can consider either of these options:

  1. You can draw on a bitmap and then save the bitmap, or draw your control to an image and save the image. This way you will flatten all shapes to a single image and after loading the image they are not editable shapes anymore. It would be like paint.
  2. You can make your shapes serializable and then serialize a list of your serializable shapes in a file. Then you can deserialize them again. This way you can load your shapes and let the user edit them, for example like Visio.

I shared two examples here:

  • Save Image Example: It simply saves the drawings which you painted on panel to a bitmap image file.

  • Serialization Example: In this example I've created some serializable shape classes containing some properties like coordinates and color, then I created a Save and Load method which allows you to serialize your shapes in a file and also deserialize them from the file and show them again. You can simply extend this example to add some functionality like hit-testing and moving shapes. Also you can use a an xml serializer instead of a binary serializer.

Save Image Example

To keep things simple in this example I just save panel paintings in a file.

If you put painting logic in Paint event of your panel, then you can use DrawToBitmap to save an image of your control to a file:

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);
}

Serialization Example

You can create some serializable shapes like LineShape and RectangleShape deriving from serializable Shape class. We store properties of shapes in this class, also these classes contain drawing logic:

[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);
    }
}

You can create a ShapesList class to hold shapes and contain logic for saving and loading shapes. Also the logic for painting all shapes on a surface:

[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));
    }
}

Then you can use these shapes and shapes list this way:

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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...