C# GDI+绘图方法 C#如何实现图形绘制

发布时间 - 2026-02-03 00:00:00    点击率:
Graphics对象只能从Control.CreateGraphics()、OnPaint事件的e.Graphics或Graphics.FromImage(bitmap)获取,不可直接new;需注意坐标系、抗锯齿、资源释放及双缓冲启用。

Graphics 对象从哪来:别直接 new

直接调用 new Graphics() 会抛出 NotSupportedException——Graphics 不是普通类,它必须绑定到一个有效的绘图表面。常见合法来源只有三个:Control.CreateGraphics()、重写 OnPaint 中的 e.Graphics、或从 Bitmap 创建。

  • Control.CreateGraphics() 返回的 Graphics 是临时的,不参与双缓冲,窗口重绘时内容会丢失;仅适合调试或一次性绘制
  • 真正稳定的绘图入口是重写控件的 OnPaint 方法,使用参数 PaintEventArgs e 中的 e.Graphics
  • 离屏绘制(如生成图片)要用 Graphics.FromImage(bitmap),记得之后调用 graphics.Dispose()

DrawLine 和 FillRectangle 的坐标系陷阱

GDI+ 默认以控件左上角为原点 (0, 0),X 向右递增,Y 向下递增——这和数学坐标系相反,但和 Windows 窗口坐标一致。容易出错的是:线条宽度影响实际绘制范围,且 FillRectangle 填充的是「内部」,而 DrawRectangle 描边是以边线中心为基准。

  • DrawLine(pen, 0, 0, 100, 100):线段起点在 (0,0),终点在 (100,100),但若 pen.Width = 3,实际像素会覆盖从 y=−1 到 y=+2 的区域
  • FillRectangle(brush, 10, 10, 50, 30):填充区域为 x∈[10,6

    0), y∈[10,40) —— 宽高是「内尺寸」,不包含右/下边界像素
  • 抗锯齿开关:用 graphics.SmoothingMode = SmoothingMode.AntiAlias 可柔化斜线和圆弧,但会轻微降低性能

Pen 和 Brush 必须手动释放

PenBrush 类型都实现了 IDisposable,内部持有 GDI 句柄。不释放会导致句柄泄漏,程序运行一段时间后可能抛出 OutOfMemoryException 或绘图失败。

  • 避免在循环中反复 new SolidBrush(Color.Red);应复用或用 using 包裹
  • 系统预定义画刷(如 Brushes.Red)是静态只读对象,不用释放;但自定义 new LinearGradientBrush(...) 必须 Dispose()
  • 典型安全写法:
    using (var pen = new Pen(Color.Blue, 2f))
    {
        g.DrawLine(pen, 0, 0, 100, 100);
    }

双缓冲没开?闪烁就是它

OnPaint 中直接绘图却没启用双缓冲,控件在重绘时会出现明显闪烁,尤其当背景清空和图形绘制分两步进行时。

  • WinForms 中最简单开启方式:this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true),建议在构造函数末尾调用
  • 不要手动调用 g.Clear(Color.White) 再画内容——Clear 本身就会触发一次屏幕刷新;应让背景绘制和前景绘制在同一个缓冲区完成
  • 若使用 CreateGraphics(),双缓冲对其无效,因为它绕过了控件的绘制管道
GDI+ 绘图真正的难点不在 API 调用,而在资源生命周期管理与绘制时机控制。一个没 DisposePen,可能让程序跑半天才崩;一次没走 OnPaintCreateGraphics,会让动画看起来像幻灯片。


# windows  # ai  # win  # c#  # 重绘  # red  # 构造函数  # 循环  # using  # 对象  # 事件  # this  # 的是  # 句柄  # 重写  # 抛出  # 步进  # 就会  # 抗锯齿  # 而在  # 半天  # 对其 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 实现点击下箭头变上箭头来回切换的两种方法【推荐】  Laravel怎么在Blade中安全地输出原始HTML内容  Python文本处理实践_日志清洗解析【指导】  什么是JavaScript解构赋值_解构赋值有哪些实用技巧  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  香港服务器WordPress建站指南:SEO优化与高效部署策略  如何用PHP工具快速搭建高效网站?  Laravel如何实现用户注册和登录?(Auth脚手架指南)  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  Laravel如何实现全文搜索功能?(Scout和Algolia示例)  Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例  nodejs redis 发布订阅机制封装实现方法及实例代码  北京网站制作的公司有哪些,北京白云观官方网站?  HTML 中动态设置元素 name 属性的正确语法详解  如何快速登录WAP自助建站平台?  Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】  如何在建站宝盒中设置产品搜索功能?  Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理  如何用IIS7快速搭建并优化网站站点?  作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】  使用spring连接及操作mongodb3.0实例  如何用好域名打造高点击率的自主建站?  如何续费美橙建站之星域名及服务?  如何在腾讯云服务器快速搭建个人网站?  javascript中对象的定义、使用以及对象和原型链操作小结  Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践  制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?  Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤  如何在阿里云部署织梦网站?  如何用狗爹虚拟主机快速搭建网站?  极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?  Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】  *服务器网站为何频现安全漏洞?  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  php485函数参数是什么意思_php485各参数详细说明【介绍】  Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)  如何快速配置高效服务器建站软件?  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  如何注册花生壳免费域名并搭建个人网站?  Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  Laravel观察者模式如何使用_Laravel Model Observer配置  香港服务器租用每月最低只需15元?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  html5的keygen标签为什么废弃_替代方案说明【解答】  详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)