WinForm 的颜色与画刷
2022 年 5 月 19 日 · 2 分钟读完
目录
两篇笔记:一篇是改了控件背景色以后找不回原来的颜色,于是研究了一下颜色的设置;另一篇是用 GDI+ 画图时遇到的各种 Brush。环境是 VS2019、.NET Framework 的 Windows 窗体项目。
颜色的三种来源
在属性窗口里点 BackColor,下拉框有三个选项卡:自定义、Web、系统。

自定义

由 RGB 三原色组成,每个分量 0 ~ 255。(0, 0, 0)是黑色,(255, 255, 255)是白色。在属性窗口里直接输入用逗号隔开的三个数。代码里:
this.BackColor = Color.FromArgb(255, 255, 255);
Web

一组预定义的命名颜色,下拉直接选。代码里是 Color 的静态属性:
this.BackColor = Color.Lime;
系统

跟随 Windows 主题的系统颜色。改掉了控件默认背景色,想改回去,找的就是这里。代码里用的是另一个类 SystemColors:
this.BackColor = SystemColors.Control; // 窗体、按钮的默认背景色
this.ForeColor = SystemColors.ControlText; // 默认文字颜色
textBox1.BackColor = SystemColors.Window; // 文本框的默认背景色
最省事的办法:在属性窗口里对 BackColor 点右键选「重置」,它会回到默认值(并且不再写进 Designer.cs)。
Color.FromArgb 的几个重载
Color.FromArgb(int red, int green, int blue); // 不透明,alpha = 255
Color.FromArgb(int alpha, int red, int green, int blue); // 带透明度
Color.FromArgb(int alpha, Color baseColor); // 在已有颜色上改透明度
Color.FromArgb(int argb); // 一个 32 位整数
每个分量超出 0 ~ 255 会抛 ArgumentException。alpha 是透明度,0 全透明、255 不透明。不是所有控件都支持半透明背景,大多数标准控件需要先 SetStyle(ControlStyles.SupportsTransparentBackColor, true)。
32 位 ARGB 按透明度、红、绿、蓝的顺序,每个分量 8 位拼起来:
A=255 R=255 G=255 B=255 → FF FF FF FF → 当 int 看是 -1
A=0 R=255 G=255 B=255 → 00 FF FF FF → 16777215
最高位是 1 时,int 是负数,这正是补码。所以写颜色常量时,用十六进制更直观:Color.FromArgb(unchecked((int)0xFF3366CC)),或者 ColorTranslator.FromHtml("#3366CC")。
GDI+ 的画刷
用 Graphics.FillXxx 填充区域时要传一个 Brush。Brush 是抽象类,用的是它的五个子类(微软文档):
| 画刷 | 命名空间 | 效果 |
|---|---|---|
SolidBrush |
System.Drawing | 纯色 |
HatchBrush |
System.Drawing.Drawing2D | 阴影线图案 |
LinearGradientBrush |
System.Drawing.Drawing2D | 线性渐变 |
PathGradientBrush |
System.Drawing.Drawing2D | 从中心向边缘渐变 |
TextureBrush |
System.Drawing | 用图片平铺 |
画刷和 Graphics 都持有 GDI 资源,用完要释放,所以下面的例子都包在 using 里。
HatchBrush:阴影线
构造时指定图案(HatchStyle 枚举,有五十多种)、前景色和可选的背景色:
using (Graphics g = this.CreateGraphics())
using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.White, Color.Black))
{
g.FillRectangle(brush, 1, 1, 100, 100);
}

LinearGradientBrush:线性渐变
可以用两个点、矩形加方向、矩形加角度来指定渐变方向:
using (Graphics g = this.CreateGraphics())
using (var brush = new LinearGradientBrush(new Point(0, 0), new Point(200, 100), Color.White, Color.Black))
{
g.FillRectangle(brush, 0, 0, 200, 100); // 从左上到右下,由白变黑
}

PathGradientBrush:从中心向外
用一条路径定义形状,CenterColor 是中心颜色,SurroundColors 是边缘颜色:
using (Graphics g = this.CreateGraphics())
using (var path = new GraphicsPath())
{
path.AddEllipse(new RectangleF(100, 100, 200, 100));
using (var brush = new PathGradientBrush(path))
{
brush.CenterColor = Color.White;
brush.SurroundColors = new[] { Color.Black };
g.FillEllipse(brush, 100, 100, 200, 100);
}
}

SolidBrush:纯色
using (Graphics g = this.CreateGraphics())
using (var brush = new SolidBrush(Color.GreenYellow))
{
g.FillEllipse(brush, 100, 100, 200, 100);
}

纯色画刷不用每次都 new:Brushes.GreenYellow 是系统缓存好的,不要 Dispose 它。
TextureBrush:图片填充
using (Graphics g = this.CreateGraphics())
using (var bmp = new Bitmap(@"D:\pattern.png"))
using (var brush = new TextureBrush(bmp))
{
g.FillEllipse(brush, 0, 0, 200, 200);
}

延伸
- 别用
CreateGraphics()画持久的图形:上面的例子为了简单都用了它,但这样画的东西在窗体最小化、被遮挡后就没了。正确做法是在Paint事件(或重写OnPaint)里用e.Graphics画,需要刷新时调Invalidate()。 - 画得多会闪:把
DoubleBuffered = true打开,见 WinForm 窗体闪烁怎么办。 - 抗锯齿:
g.SmoothingMode = SmoothingMode.AntiAlias;让圆和斜线边缘更平滑;文字用g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;。 - .NET 6 以后 System.Drawing 只支持 Windows:WinForm 本来就只在 Windows 上,影响不大;跨平台的图像处理可以看 SkiaSharp 或 ImageSharp。
原文首发于 blog.csdn.net