如何保存Panel控件中绘制的图形为图片或PNG文件?
问题原因
你用Panel1.CreateGraphics()绘制的内容属于临时绘制,这些图形不会被控件的持久化绘制流程记录。当调用DrawToBitmap时,控件会重新触发自身的绘制逻辑(也就是Paint事件),但你的绘图代码不在这个事件里,所以导出的Bitmap只会有控件的默认背景,没有你画的图形。
解决方法
把所有绘图逻辑移到Panel的Paint事件中,这样无论是控件正常显示还是导出为Bitmap,都会执行绘图代码,捕获到完整的图形。同时注意释放绘图资源(比如Pen),避免内存泄漏。
修改后的代码
1. 添加Panel的Paint事件处理
Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint Dim g As Graphics = e.Graphics Dim pen1 As New Pen(Color.Red, 1) Dim pen2 As New Pen(Color.Yellow, 1) Dim pen3 As New Pen(Color.Blue, 1) ' 绘制矩形循环 For d = 1 To 72 Step 1 Dim re As New Rectangle(10 * d, 50, 1, 40) g.DrawRectangle(Pens.Black, re) Next ' 绘制底部线圈线条 For P3 = 1 To 6 Step 1 g.DrawLine(pen1, 5 + 10 * P3, 30, 5 + 10 * P3, 100) Next For p4 = 7 To 12 Step 1 g.DrawLine(pen2, 5 + 10 * p4, 30, 5 + 10 * p4, 100) Next For p5 = 13 To 18 Step 1 g.DrawLine(pen3, 5 + 10 * p5, 30, 5 + 10 * p5, 100) Next For P3 = 19 To 24 Step 1 g.DrawLine(pen1, 5 + 10 * P3, 30, 5 + 10 * P3, 100) Next For p4 = 25 To 30 Step 1 g.DrawLine(pen2, 5 + 10 * p4, 30, 5 + 10 * p4, 100) Next For p5 = 31 To 36 Step 1 g.DrawLine(pen3, 5 + 10 * p5, 30, 5 + 10 * p5, 100) Next For P3 = 37 To 42 Step 1 g.DrawLine(pen1, 5 + 10 * P3, 30, 5 + 10 * P3, 100) Next For p4 = 43 To 48 Step 1 g.DrawLine(pen2, 5 + 10 * p4, 30, 5 + 10 * p4, 100) Next For p5 = 49 To 54 Step 1 g.DrawLine(pen3, 5 + 10 * p5, 30, 5 + 10 * p5, 100) Next For P3 = 55 To 60 Step 1 g.DrawLine(pen1, 5 + 10 * P3, 30, 5 + 10 * P3, 100) Next For p4 = 61 To 65 Step 1 g.DrawLine(pen2, 5 + 10 * p4, 30, 5 + 10 * p4, 100) Next For p5 = 66 To 72 Step 1 g.DrawLine(pen3, 5 + 10 * p5, 30, 5 + 10 * p5, 100) Next ' 绘制顶部线圈线条 Dim pitch As Integer = 15 For P3 = 1 + pitch To 6 + pitch Step 1 g.DrawLine(pen1, 7 + 10 * P3, 30, 7 + 10 * P3, 100) Next For p4 = 7 + pitch To 12 + pitch Step 1 g.DrawLine(pen2, 7 + 10 * p4, 30, 7 + 10 * p4, 100) Next For p5 = 13 + pitch To 18 + pitch Step 1 g.DrawLine(pen3, 7 + 10 * p5, 30, 7 + 10 * p5, 100) Next For P3 = 19 + pitch To 24 + pitch Step 1 g.DrawLine(pen1, 7 + 10 * P3, 30, 7 + 10 * P3, 100) Next For p4 = 25 + pitch To 30 + pitch Step 1 g.DrawLine(pen2, 7 + 10 * p4, 30, 7 + 10 * p4, 100) Next For p5 = 31 + pitch To 36 + pitch Step 1 g.DrawLine(pen3, 7 + 10 * p5, 30, 7 + 10 * p5, 100) Next For P3 = 37 + pitch To 42 + pitch Step 1 g.DrawLine(pen1, 7 + 10 * P3, 30, 7 + 10 * P3, 100) Next For p4 = 43 + pitch To 48 + pitch Step 1 g.DrawLine(pen2, 7 + 10 * p4, 30, 7 + 10 * p4, 100) Next For p5 = 49 + pitch To 54 + pitch Step 1 g.DrawLine(pen3, 7 + 10 * p5, 30, 7 + 10 * p5, 100) Next For P3 = 55 + pitch To 72 Step 1 g.DrawLine(pen1, 7 + 10 * P3, 30, 7 + 10 * P3, 100) Next For P3 = 1 To 4 Step 1 g.DrawLine(pen1, 7 + 10 * P3, 30, 7 + 10 * P3, 100) Next For p4 = 61 + pitch - 72 To 65 + pitch - 72 Step 1 g.DrawLine(pen2, 7 + 10 * p4, 30, 7 + 10 * p4, 100) Next For p5 = 66 + pitch - 72 To 72 + pitch - 72 Step 1 g.DrawLine(pen3, 7 + 10 * p5, 30, 7 + 10 * p5, 100) Next ' 释放Pen资源 pen1.Dispose() pen2.Dispose() pen3.Dispose() End Sub
2. 修改按钮点击事件,只负责刷新Panel和导出
Private Sub Button19_Click(sender As Object, e As EventArgs) Handles Button19.Click ' 刷新Panel,触发Paint事件绘制图形 Panel1.Refresh() ' 导出为Bitmap Using bmp As New Bitmap(Panel1.Width, Panel1.Height) Panel1.DrawToBitmap(bmp, New Rectangle(0, 0, Panel1.Width, Panel1.Height)) bmp.Save(Path.Combine(Environment.CurrentDirectory, "winding diagram.png"), Imaging.ImageFormat.Png) End Using End Sub
补充说明
- 用
e.Graphics代替CreateGraphics():这是控件绘制时提供的官方绘图上下文,所有绘制内容会被控件的绘制流程记录,导出时能被DrawToBitmap捕获。 - 资源释放:用
Dispose()或者Using语句处理Pen、Bitmap等实现了IDisposable的对象,避免内存泄漏。 - 移除重复循环:原代码把整个绘图逻辑放在d=1到72的循环里,会重复绘制72次,现在移到Paint事件后只需要绘制一次即可。
内容的提问来源于stack exchange,提问作者Agastya Vulugundam
相关产品推荐
相关产品推荐

