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

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

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. 您可以在位图上绘制然后保存位图,或将控件绘制到图像并保存图像。 这样,您可以将所有形状展平为单个图像,并且在加载图像后,它们不再是可编辑的形状。 这就像油漆。
  2. 您可以使形状可序列化,然后在文件中序列化可序列化形状的列表。 然后你可以再次反序列化它们。 这样,您可以加载形状并让用户编辑它们,例如像Visio。

我在这里分享了两个例子:

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

  • 序列化示例:在此示例中,我创建了一些可序列化的形状类,其中包含一些属性,如坐标和颜色,然后我创建了一个Save and Load方法,该方法允许您在文件中序列化形状,并从文件中反序列化它们并显示它们再次。 您可以简单地扩展此示例以添加一些function,如命中测试和移动形状。 您也可以使用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); } 

序列化示例

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

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