【学习笔记】Windows GDI绘图(八)画笔Pen与画刷Brush

news2024/11/16 7:54:55

文章目录

  • 关于Pen
    • 改变Pen的宽度width和对齐方式Alignment
    • 带线帽的线段
    • 连接线条LineJoin
    • 自定义虚线
    • 用纹理填充线条
  • 关于Brush
    • HatchBrush阴影
    • LinearGradientBrush线性渐变
    • PathGradientBrush

详细示例Pen与Brush的属性与方法
Pen与Brush

关于Pen

改变Pen的宽度width和对齐方式Alignment

可以通过构造函数,或修改Pen类的Width属性更改线宽。
线的理论宽度为0。绘制宽度为1个像素的线时,像素以理论线为中心。
Alignment虽然有5个枚举值,但只有Center和Insert会改变绘制线条的样式。设置另外3个时,也是按Center样式绘制。
设置为Inset时,可能产生不可预测的结果,有时按Inset绘制,有时按Center绘制。
Inset不能用于绘制复合线段,也不能用三角形破折号绘制虚线。

using (var blackPen = new Pen(Color.Black, 1))
using (var lightgreenPen = new Pen(Color.LightGreen))
{
    //改变笔宽
    lightgreenPen.Width = 10F;
    var linePt1 = new Point(100, 100);
    var linePt2 = new Point(200,200);
    e.Graphics.DrawLine(lightgreenPen, linePt1,linePt2);
    e.Graphics.DrawLine(blackPen, linePt1, linePt2);

    var rect = new Rectangle(240, 100, 100, 100);

    e.Graphics.DrawRectangle(lightgreenPen, rect);
    e.Graphics.DrawRectangle(blackPen, rect);

    e.Graphics.TranslateTransform(0, 150);

    //注意,除了Inset和Center,其它的绘制效果与Center一样
    lightgreenPen.Alignment = PenAlignment.Inset;

    e.Graphics.DrawLine(lightgreenPen, linePt1, linePt2);
    e.Graphics.DrawLine(blackPen, linePt1, linePt2);

    e.Graphics.DrawRectangle(lightgreenPen, rect);
    e.Graphics.DrawRectangle(blackPen, rect);
}

定义两个点和一个矩形,分别用两种方式绘制,区别Alginment不同值时的效果。
注意,左下角线条是按Center样式绘制的,而右下的矩形是在轮廓内部
Alignment

带线帽的线段

使用系统定义的线帽(LineCap枚举)与自定义线帽(CustomLineCap)绘制线段

using (var lightgreenPen = new Pen(Color.LightGreen,10))
{
    LineCap[] lineCaps = (LineCap[])Enum.GetValues(typeof(LineCap));
    lineCaps = lineCaps.Where(z => z != LineCap.Custom).ToArray();

    var pt1 = new Point(100, 50);
    var pt2 = new Point(200, 50);
    for (int i = 0; i < lineCaps.Length; i += 2)
    {
        lightgreenPen.StartCap = lineCaps[i];
        lightgreenPen.EndCap = lineCaps[i + 1];
        e.Graphics.DrawLine(lightgreenPen, pt1, pt2);
        e.Graphics.DrawString($"StartCap:{lineCaps[i]}\tEndCap:{lineCaps[i + 1]}", Font, Brushes.Red, 230, 40);
        e.Graphics.TranslateTransform(0, 60);
    }


    var lintPt1 = new Point(100, 100);
    var lintPt2 = new Point(200, 200);


    //设置线帽
    lightgreenPen.StartCap = LineCap.ArrowAnchor;
    lightgreenPen.EndCap = LineCap.RoundAnchor;
    e.Graphics.DrawLine(lightgreenPen, lintPt1, lintPt2);

    //自定义线帽
    GraphicsPath hPath = new GraphicsPath();
    hPath.AddEllipse(new Rectangle(-5, -5, 10, 10));
    // Create the outline for our custom end cap.

    // Construct the hook-shaped end cap.
    CustomLineCap HookCap = new CustomLineCap(null, hPath);

    // Set the start cap and end cap of the HookCap to be rounded.
    HookCap.SetStrokeCaps(LineCap.Round, LineCap.Round);

    // Create a pen and set end custom start and end
    // caps to the hook cap.
    Pen customCapPen = new Pen(Color.Black, 2);
    customCapPen.CustomStartCap = HookCap;
    customCapPen.CustomEndCap = HookCap;

    // Create a second pen using the start and end caps from
    // the hook cap.
    Pen capPen = new Pen(Color.Red, 10);
    LineCap startCap;
    LineCap endCap;
    HookCap.GetStrokeCaps(out startCap, out endCap);
    capPen.StartCap = startCap;
    capPen.EndCap = endCap;

    // Create a line to draw.
    Point[] points = { new Point(250, 100), new Point(350, 100),new Point(400, 250) };

    // Draw the lines.
    e.Graphics.DrawLines(capPen, points);
    e.Graphics.DrawLines(customCapPen, points);
}

绘制各种LineCap及自定线帽
Pen的线帽

连接线条LineJoin

线条连接表示两条连续边的末端的连接样式。
注意不同的LineJoin也会影响路径的GetBounds带Pen参数时的结果。

using (var bluePen = new Pen(Color.Blue, 30))
{
    var linePts = new Point[]
    {
        new Point(100, 100),
        new Point(300, 100),
        new Point(230, 150)
    };
    float offset = 40f;
    e.Graphics.DrawLines(bluePen, linePts);
    e.Graphics.DrawString($"LineJoin:{bluePen.LineJoin},MiterLimit={bluePen.MiterLimit}", Font, Brushes.Red, linePts[0].X, linePts[0].Y- offset);

    e.Graphics.TranslateTransform(300, 0);
    bluePen.LineJoin = LineJoin.Round;
    e.Graphics.DrawLines(bluePen, linePts);
    e.Graphics.DrawString($"LineJoin:{bluePen.LineJoin}", Font, Brushes.Red, linePts[0].X, linePts[0].Y - offset);

    e.Graphics.TranslateTransform(0, 100);
    bluePen.LineJoin = LineJoin.Bevel;
    e.Graphics.DrawLines(bluePen, linePts);
    e.Graphics.DrawString($"LineJoin:{bluePen.LineJoin},MiterLimit={bluePen.MiterLimit}", Font, Brushes.Red, linePts[0].X, linePts[0].Y - offset);

    e.Graphics.TranslateTransform(-300, 0);
    bluePen.MiterLimit = 1;
    bluePen.LineJoin = LineJoin.MiterClipped;
    e.Graphics.DrawLines(bluePen, linePts);
    e.Graphics.DrawString($"LineJoin:{bluePen.LineJoin},MiterLimit={bluePen.MiterLimit}", Font, Brushes.Red, linePts[0].X, linePts[0].Y - offset);
}

定义三个点,使用不同的LineJoin和MiterLimit什绘制线段,查看转角的区别。
Pen的LineJoin

自定义虚线

通过设置Pen的DashPatten属性,为一个浮点型数组(非零正数,第1个设置破折号长度,第2个设置空格长度,第3个设置破折号长度,依此类推)。

using (var bluePen = new Pen(Color.Blue, 3))
{
    var linePts = new Point[]
    {
        new Point(100, 100),
        new Point(300, 100),
        new Point(230, 150)
    };
    //自定义虚线
    bluePen.DashPattern = new float[] { 5, 3, 16, 7 };
    e.Graphics.DrawLines(bluePen, linePts);

    e.Graphics.TranslateTransform(300, 0);
    bluePen.DashPattern = new float[] { 2,1};
    e.Graphics.DrawLines(bluePen, linePts);
}

分别定义两种虚线格式,绘制线段。
自定义虚线

用纹理填充线条

使用纹理图案填充线条。

using(var bmp=new Bitmap("MyTexture.gif"))
using(var bBrush=new TextureBrush(bmp))
using (var texturePen = new Pen(bBrush, 21))
{
    var linePts = new Point[]
    {
        new Point(100, 100),
        new Point(300, 100),
        new Point(230, 150)
    };

    e.Graphics.DrawImage(bmp, 50, 50, bmp.Width, bmp.Height);

    e.Graphics.DrawLines(texturePen, linePts);

    e.Graphics.DrawEllipse(texturePen, new Rectangle(350, 100, 200, 100));
}

使用纹理填充线段和椭圆路径。
用纹理填充线条

关于Brush

定义用于填充图形形状内部的对象,例如矩形、椭圆形、饼形、多边形和路径。
该类是抽象类,使用时请使用其派生类HatchBrush,LinearGradienBrush,PathGradienBrush,SolidBrush和TextureBrush。

HatchBrush阴影

定义具有阴影样式、前景色和背景色的矩形画笔。

var rect = new Rectangle(10, 20, 90, 80);
//枚举所有HatchStyle
var hatchStyles = Enum.GetValues(typeof(HatchStyle)) as HatchStyle[];
hatchStyles = hatchStyles.Distinct().ToArray();
StringFormat format1 = new StringFormat(StringFormatFlags.NoClip);
format1.LineAlignment = StringAlignment.Center;
format1.Alignment = StringAlignment.Center;
for (int i=0;i<hatchStyles.Length;i++)
{
    var hatchStyle = hatchStyles[i];
    using (var hatchBrush = new HatchBrush(hatchStyle, //样式
                                           Color.Red, //前景色
                                           Color.Green))//背景色
    {
        var matrix = new Matrix();
        matrix.Translate((i % 8) * 120, (i / 8) * 100);
        e.Graphics.Transform = matrix;
        e.Graphics.DrawString($"{hatchStyle}", Font, Brushes.Red, new Point(65, 10), format1);
        //水平
        e.Graphics.FillEllipse(hatchBrush, rect);
    }
}

枚举所有HatchStyle,并一一绘制出来。
不同样式的HatchBrush

LinearGradientBrush线性渐变

具有线性渐变效果的画笔。
指定两点或矩形、LinearGradientMode样式或角度,还可以指定Blend属性。

var rect = new Rectangle(10, 20, 90, 80);
//枚举所有HatchStyle
var values = Enum.GetValues(typeof(LinearGradientMode)) as LinearGradientMode[];
StringFormat format1 = new StringFormat(StringFormatFlags.NoClip);
format1.LineAlignment = StringAlignment.Center;
format1.Alignment = StringAlignment.Center;
int i;
//测试不同的 LinearGradientMode
for (i = 0; i < values.Length; i++)
{
    var val = values[i];
    using (var hatchBrush = new LinearGradientBrush(rect,
                                           Color.Red,
                                           Color.Green,
                                           val))
    {
        var matrix = new Matrix();
        matrix.Translate((i % 7) * 120, (i / 7) * 100);
        e.Graphics.Transform = matrix;
        e.Graphics.DrawString($"{val}", Font, Brushes.Red, new Point(65, 10), format1);
        //水平
        e.Graphics.FillEllipse(hatchBrush, rect);
    }
}
Blend blend = new Blend();
blend.Positions = new float[] { 0.0f, 0.5f, 1.0f };
blend.Factors = new float[] { 0.0f, 1.0f, 0.0f };
//测试不两只的角度与Blend
for (int angle = 0; angle <720; angle += 60)
{
    var valAngle = angle % 360;
    using (var hatchBrush2 = new LinearGradientBrush(rect,
                               Color.Red,
                               Color.Green,
                               valAngle))
    {
        var matrix = new Matrix();
        matrix.Translate((i % 8) * 120, (i / 8) * 100);
        // 定义Blend数组

        if (angle >= 360)
        {
            // 应用Blend到线性渐变刷
            hatchBrush2.Blend = blend;
        }


        e.Graphics.Transform = matrix;
        e.Graphics.DrawString($"{valAngle},Blend:{angle>360}", Font, Brushes.Red, new Point(65, 10), format1);
        //水平
        e.Graphics.FillEllipse(hatchBrush2, rect);
    }
    i++;
}

绘制不同方式的渐变效果。
不同效果的渐变

PathGradientBrush

从中心往边界渐变,边界可以是椭圆(圆)或指定多边形。

var rect = new Rectangle(10, 20, 150, 80);
//枚举所有HatchStyle
var values = Enum.GetValues(typeof(LinearGradientMode)) as LinearGradientMode[];
StringFormat format1 = new StringFormat(StringFormatFlags.NoWrap);
format1.LineAlignment = StringAlignment.Center;
format1.Alignment = StringAlignment.Center;

//绘制一个椭圆渐变
using (var path = new GraphicsPath())
{
    path.AddEllipse(rect);
    var pathGrBrush = new PathGradientBrush(path);
    pathGrBrush.CenterColor = Color.LightGreen;
    pathGrBrush.SurroundColors = new Color[] { Color.Green };
    e.Graphics.FillEllipse(pathGrBrush, rect);
}

//绘制一个五角星渐变
// Put the points of a polygon in an array.
Point[] points = {
                new Point(75, 0),
                new Point(100, 50),
                new Point(150, 50),
                new Point(112, 75),
                new Point(150, 150),
                new Point(75, 100),
                new Point(0, 150),
                new Point(37, 75),
                new Point(0, 50),
                new Point(50, 50)};

// Use the array of points to construct a path.
using (GraphicsPath path = new GraphicsPath())
{
    path.AddLines(points);

    // Use the path to construct a path gradient brush.
    PathGradientBrush pthGrBrush = new PathGradientBrush(path);

    // Set the color at the center of the path to red.
    pthGrBrush.CenterColor = Color.FromArgb(255, 255, 0, 0);

    // Set the colors of the points in the array.
    var colors = new Color[] {
            Color.FromArgb(255, 0, 0, 0),
            Color.FromArgb(255, 0, 255, 0),
            Color.FromArgb(255, 0, 0, 255),
            Color.FromArgb(255, 255, 255, 255),
            Color.FromArgb(255, 0, 0, 0),
            Color.FromArgb(255, 0, 255, 0),
            Color.FromArgb(255, 0, 0, 255),
            Color.FromArgb(255, 255, 255, 255),
            Color.FromArgb(255, 0, 0, 0),
            Color.FromArgb(255, 0, 255, 0)};

    pthGrBrush.SurroundColors = colors;
    e.Graphics.TranslateTransform(200, 50); 
    // Fill the path with the path gradient brush.
    e.Graphics.FillPath(pthGrBrush, path);
}

//指定边界上的点
// Construct a path gradient brush based on an array of points.
PointF[] ptsF = {
    new PointF(0, 0),
    new PointF(160, 0),
    new PointF(160, 200),
    new PointF(80, 150),
    new PointF(0, 200)};

PathGradientBrush pBrush = new PathGradientBrush(ptsF);

// An array of five points was used to construct the path gradient
// brush. Set the color of each point in that array.
Color[] colors2 = {
    Color.FromArgb(255, 255, 0, 0),  // (0, 0) red
    Color.FromArgb(255, 0, 255, 0),  // (160, 0) green
    Color.FromArgb(255, 0, 255, 0),  // (160, 200) green
    Color.FromArgb(255, 0, 0, 255),  // (80, 150) blue
    Color.FromArgb(255, 255, 0, 0)}; // (0, 200) red

pBrush.SurroundColors = colors2;

// Set the center color to white.
pBrush.CenterColor = Color.White;

e.Graphics.TranslateTransform(0, 200);
// Use the path gradient brush to fill a rectangle.
e.Graphics.FillRectangle(pBrush, new Rectangle(0, 0, 160, 200));

// Create a path that consists of a single ellipse.
var path2 = new GraphicsPath();
path2.AddEllipse(0, 0, 200, 100);


//自定义路径渐变
// Create a path gradient brush based on the elliptical path.
PathGradientBrush pthGrBrush2 = new PathGradientBrush(path2);

// Set the color along the entire boundary to blue.
Color[] color = { Color.Blue };
pthGrBrush2.SurroundColors = color;

// Set the center color to aqua.
pthGrBrush2.CenterColor = Color.Aqua;
e.Graphics.TranslateTransform(220.0f, 0.0f);
// Use the path gradient brush to fill the ellipse.
e.Graphics.FillPath(pthGrBrush2, path2);

// Set the focus scales for the path gradient brush.
pthGrBrush2.FocusScales = new PointF(0.3f, 0.8f);

// Use the path gradient brush to fill the ellipse again.
// Show this filled ellipse to the right of the first filled ellipse.
e.Graphics.TranslateTransform(220.0f, 0.0f);
e.Graphics.FillPath(pthGrBrush2, path2);

绘制一个椭圆渐变,五角星渐变、多边形,即修改FocusScales时的渐变效果。
PathGradientBrush

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1717279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IntelliJ IDEA Ultimate 2024.1 Mac激活码 Java开发首选IDE

IntelliJ IDEA Ultimate 2024 搜Mac软件之家下载IDEA Mac中文版 IntelliJ IDEA Ultimate 2024是JetBrains公司推出的一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为专业开发者设计&#xff0c;支持多种编程语言和框架。它提供了一系列高级功能&…

【免费Web系列】JavaWeb实战项目案例五

这是Web第一天的课程大家可以传送过去学习 http://t.csdnimg.cn/K547r 新增员工 前面我们已经实现了员工信息的条件分页查询。 那今天我们要实现的是新增员工的功能实现&#xff0c;页面原型如下&#xff1a; ​ 首先我们先完成"新增员工"的功能开发&#xff0…

Linux--线程的分离、线程库的地址关系的理解、线程的简单封装(二)

线程系列&#xff1a; 线程的认识&#xff1a;讲解线程的概念和线程的基本控制 线程的分离 线程分离是指将一个线程从主线程中分离出来&#xff0c;使其能够独立运行。当一个线程被设置为分离状态时&#xff0c;它结束时系统会自动回收其资源&#xff0c;而不需要其他线程使用…

【喜报】科大睿智服务企业通过CMMI3级认证

​北京建投科信科技发展股份有限公司&#xff08;以下简称“北京建投科技” &#xff09;前身为北京银帝科技发展公司&#xff0c;成立于1993年&#xff0c;注册资本6,000万元&#xff0c;为中国建银投资有限责任公司&#xff08;简称“中国建投”&#xff09;的成员企业建投华…

ovs-vsctl错误:Port does not contain a column whoes name matches “--id“

出错的命令是: ovs-vsctl -- set Bridge br-int mirrors=@m -- --id=@snooper0 get Port snooper0\ -- --id=@patch-tun get Port patch-tun -- --id=@m create Mirror name=mymirror \ select

微软Edge浏览器深度解析:功能、同步、隐私与安全

微软Edge浏览器是微软公司开发的一款网页浏览器,它基于Chromium内核,提供了快速、安全和兼容性良好的网页浏览体验。以下是关于微软Edge浏览器的详细信息和使用指南: 微软Edge浏览器的主要特点: 1. 基于Chromium内核: 渲染引擎:Chromium内核是基于开源项目Blink的,它…

LNMP分布式搭建

一、准备三台主机 192.168.100.11 mysql 192.168.100.12 nginx 192.168.100.13 php 二、关闭防火墙及安全策略 systemctl stop firewalld setenforce 0 三、安装nginx&#xff08;192.168.100.11&#xff09; 1、添加nginx源 vim /etc/yum.repos.d/ng…

数据整理的Compact流程 (二)|OceanBase数据转储合并技术解读(二)

上篇文章《数据整理的Compact流程 &#xff08;一&#xff09;&#xff5c;OceanBase数据转储合并技术解读&#xff08;二&#xff09;》中&#xff0c;有讲解到&#xff0c;在OceanBase数据库中&#xff0c;当MemTable写满时&#xff0c;将其下刷到Mini SSTable的过程包含两个…

正邦科技(day4)

烧录 一、烧录固件二、 通讯模块升级1&#xff1a;USB的方式升级固件2&#xff1a;通过mqtt的方式升级固件3&#xff1a;切换环境 三、 烧录WiFi1&#xff1a;短接2&#xff1a;烧录脚本 设备注意事项&#xff1a; 第一种方式&#xff1a;通信模组和MCU都可以统一烧录BoodLoade…

数据结构---栈队列

栈和队列是我们数据结构中经常使用的数据结构&#xff0c;所以现在来了解一下栈和队列。 栈 特点&#xff1a; 栈是一种特殊的线性表&#xff0c;其中进行数据插入和弹出的部分叫做栈顶&#xff0c;另一端叫做栈底。 只允许数据从栈顶压入&#xff0c;从栈顶弹出即先进后出的…

Mac | Mac M 芯片应用意外退出问题

现象问题 电脑配置&#xff1a;MacBook Pro M1&#xff0c;系统 Sonoma 很多小伙伴新买了 M 芯片的 MacBook&#xff0c;在下载下应用后进行安装&#xff0c;安装成功后却无法打开&#xff0c;提示意外退出。报错如图 原因 部分应用过适配了 M 芯片&#xff0c;但还是有些应…

Windows配置共享文件夹

正文共&#xff1a;888 字 16 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们前面介绍了如果安装NAS工具&#xff08;废物利用&#xff0c;矿渣装个黑群晖。家庭小NAS搞起来&#xff01;&#xff09;&#xff0c;也介绍过如果配置远程桌面的多账号登录&#xff08;Windows…

Apache Nemo: A Framework for Optimizing Distributed Data Processing——论文泛读

TOCS 2021 Paper 论文阅读笔记整理 问题 针对资源和数据特性优化分布式数据处理的调度和通信&#xff0c;对于实现高性能至关重要。在最近的研究中广泛讨论的例子是&#xff1a;地理分布的资源[14&#xff0c;30&#xff0c;47&#xff0c;48]、廉价的瞬时资源[34&#xff0c…

五分钟“手撕”链表

为了提高大家的学习效率&#xff0c;我把代码放开头&#xff0c;供查阅。 目录 一、链表的实现代码 二、什么是链表 三、链表的分类 四、链表的常见操作 插入 删除 五、Java自带的LinkedList 两个构造方法 一些常用方法 六、LinkedList的遍历 七、ArrayList和Linke…

基恩士PLC与ModbusTCP转Profibus网关实现与激光设备的高效连接

本文将探讨如何通过使用基恩士PLC以及无锡耐特森ModbusTCP转Profibus网关来实现与激光设备的高效连接。在当今工业自动化领域&#xff0c;不同厂商的硬件设备和软件系统之间的互联互通性成为了提高生产效率、实现智能制造的关键因素。其中&#xff0c;可编程逻辑控制器&#xf…

spring boot 3.x版本 引入 swagger2启动时报错

一&#xff0c;问题 Spring Boot 3.x版本的项目里&#xff0c;准备引入Swagger2作为接口文档&#xff0c;但是项目启动报错&#xff1a; java.lang.TypeNotPresentException: Type javax.servlet.http.HttpServletRequest not present at java.base/sun.reflect.generics.…

高等教育的AI革新:OpenAI面向大学推出ChatGPT Edu

OpenAI推出了ChatGPT Edu&#xff0c;这是一个为大学设计的专用版本&#xff0c;旨在让学生、教职员工、研究人员和校园运营能够负责任地使用AI。 ChatGPT Edu 将AI技术引入了教育领域&#xff0c;其建立在GPT-4o的基础上&#xff0c;它不仅能够处理文本和图像&#xff0c;还…

【linux深入剖析】进程间通信

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1.进程间通信目的2. 什么…

dubbo复习:(17)dubbo连接skywalking

一、准备skywalking 8.7.0并启动 二、配置好skywalking agent 三、服务提供者端的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema…

结构体中内存的对齐

前言 学C的同学应该知道~ 想精通C语言就不得不面对—指针与内存 续上次指针进阶&#xff0c;这一章我来聊一聊C语言内存对齐的问题 学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的&#x1f601; 思考 #include<stdio.h> typedef struct s1 {char a;char …