C#中Graphics.DrawLine在PictureBox的Paint事件绘图不生效问题
问题产生原因
- 全局
Graphics对象是通过构造函数中调用pictureBox1.CreateGraphics()得到的,该对象对应的是临时绘制上下文,通过它绘制的内容属于临时表层渲染,不会被系统缓存,一旦触发窗体重绘(最小化恢复、窗口大小调整、被其他窗口遮挡后重新显示等场景都会触发重绘),这部分临时绘制内容会被直接清空。 PictureBox的Paint事件是系统触发重绘时的回调入口,该事件参数PaintEventArgs e中提供了专门用于本次重绘的Graphics对象,但你在事件处理逻辑中依然调用全局临时Graphics对象绘制,导致重绘逻辑实际没有作用到最终显示的画面上,重绘完成后十字标记自然就消失了。- 代码中创建的
Pen对象未手动释放,存在GDI资源泄漏风险,长期运行可能引发程序性能下降、绘制异常等问题。
解决方法
修改代码逻辑如下即可解决问题:
- 移除全局
Graphics g变量,不要长期持有CreateGraphics()返回的临时绘制上下文。 - 为
DrawCrosses方法新增Graphics类型的入参,所有绘制操作都基于传入的有效绘制上下文执行。 - 按钮点击事件中需要即时绘制时,临时创建
Graphics对象使用后立即释放;Paint事件中直接传入事件参数携带的Graphics对象执行绘制。 - 使用
using语句自动管理Pen等GDI资源,避免资源泄漏。
修正后完整代码
public partial class Form1 : Form { Point[] points = new Point[2]; public Form1() { InitializeComponent(); points[0] = new Point(50, 50); points[1] = new Point(100, 100); } private void button1_Click(object sender, EventArgs e) { // 按钮点击即时绘制,临时创建Graphics对象用完即释放 using (var g = pictureBox1.CreateGraphics()) { DrawCrosses(g, points); } } private void DrawCrosses(Graphics g, Point[] points) { // 使用using自动释放Pen资源 using (Pen pen = new Pen(Color.Red) { Width = 2 }) { foreach (Point p in points) { Point pt1 = new Point(p.X, p.Y - 10); Point pt2 = new Point(p.X, p.Y + 10); Point pt3 = new Point(p.X - 10, p.Y); Point pt4 = new Point(p.X + 10, p.Y); g.DrawLine(pen, pt1, pt2); g.DrawLine(pen, pt3, pt4); } } } private void pictureBox1_Paint(object sender, PaintEventArgs e) { // 重绘时使用Paint事件提供的有效Graphics对象 DrawCrosses(e.Graphics, points); } }
如果需要将绘制的十字标记持久化保存到PictureBox的Image属性中,可直接绘制到Image对应的Graphics上下文,再调用pictureBox1.Invalidate()触发重绘即可。
内容的提问来源于stack exchange,提问作者pado
相关产品推荐
相关产品推荐

