《C# GDI+ 破境之道》:第一境 GDI+基础 —— 第三节:画圆形

有了上一节画矩形的基础,画圆形就不要太轻松+EZ:)所以,本节在画边线及填充上,就不做过多的讲解了,关注一下画“随机椭圆”、“正圆”、“路径填充”的具体实现就好。与画矩形相比较,画椭圆与之完全一致,没有任何特别之处。

在画矩形时,我们使用:

  • System.Drawing.Graphics.DrawRectangle(Brush brush, Rectangle rect);
  • System.Drawing.Graphics.FillRectangle(Brush brush, Rectangle rect);

在画圆形时,我们使用:

  • System.Drawing.Graphics.DrawEllipse(Brush brush, Rectangle rect);
  • System.Drawing.Graphics.FillEllipse(Brush brush, Rectangle rect);

看到了吧,就换了个方法名,参数连名都没换:)

所以,了解了如何画矩形,画圆形就是自然掌握的了。

本节就不多费口舌重复了:

  1 namespace MikeWare.GdiPlus.Ellipses
  2 {
  3     using System;
  4     using System.Collections.Generic;
  5     using System.Drawing;
  6     using System.Drawing.Drawing2D;
  7     using System.Windows.Forms;
  8
  9     public partial class FormDrawEllipses : Form
 10     {
 11         private Random random = null;
 12         private Color penColor = Color.Transparent;
 13
 14         public FormDrawEllipses()
 15         {
 16             InitializeComponent();
 17             random = new Random(DateTime.Now.Millisecond);
 18             penColor = GetRandomColor();
 19         }
 20
 21         private Point GetRandomPoint()
 22         {
 23             return new Point(random.Next(0, ClientRectangle.Width), random.Next(0, ClientRectangle.Height - pnlToolbox.Height));
 24         }
 25
 26         private Rectangle GetRandomRectangle()
 27         {
 28             var pointA = GetRandomPoint();
 29             var pointB = GetRandomPoint();
 30
 31             return new Rectangle(Math.Min(pointA.X, pointB.X)
 32                 , Math.Min(pointA.Y, pointB.Y)
 33                 , Math.Abs(pointA.X - pointB.X)
 34                 , Math.Abs(pointA.Y - pointB.Y));
 35         }
 36
 37         private Color GetRandomColor()
 38         {
 39             return Color.FromArgb(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
 40         }
 41
 42         private void ShowInformation(string message)
 43         {
 44             lblInformation.Text = message;
 45         }
 46
 47         private void btnChangePenColor_Click(object sender, EventArgs e)
 48         {
 49             if (colors.ShowDialog(this) == DialogResult.OK)
 50             {
 51                 penColor = colors.Color;
 52             }
 53         }
 54
 55         private void btnSwitchDoubleBuffered_Click(object sender, EventArgs e)
 56         {
 57             DoubleBuffered = !DoubleBuffered;
 58
 59             ShowInformation($"二级缓冲:{DoubleBuffered}。");
 60         }
 61
 62         private void btnDrawRandomEllipse_Click(object sender, EventArgs e)
 63         {
 64             var rectangle = GetRandomRectangle();
 65
 66             var style = (DashStyle)(random.Next(0, 6));
 67             var dashCaps = new List<int> { 0, 2, 3 };
 68             var dashCap = (DashCap)dashCaps[random.Next(0, 3)];
 69
 70             using (var g = CreateGraphics())
 71             using (var pen = new Pen(penColor, 4f))
 72             using (var brush = new LinearGradientBrush(rectangle, Color.Red, Color.Blue, LinearGradientMode.ForwardDiagonal))
 73             {
 74                 g.Clear(SystemColors.AppWorkspace);
 75                 g.SmoothingMode = SmoothingMode.HighQuality;
 76                 pen.DashStyle = style;
 77                 pen.DashCap = dashCap;
 78                 g.DrawEllipse(pen, rectangle);
 79             }
 80
 81             ShowInformation($"随机椭圆,{rectangle},虚线冒:{dashCap.ToString()},线条样式:{style.ToString()}。");
 82         }
 83
 84         private void btnDrawRandomCircle_Click(object sender, EventArgs e)
 85         {
 86             var rectangle = GetRandomRectangle();
 87             var diameter = Math.Min(rectangle.Size.Width, rectangle.Size.Height);
 88             rectangle = new Rectangle(rectangle.Location, new Size(diameter, diameter));
 89
 90             var style = (DashStyle)(random.Next(0, 6));
 91             var dashCaps = new List<int> { 0, 2, 3 };
 92             var dashCap = (DashCap)dashCaps[random.Next(0, 3)];
 93
 94             using (var g = CreateGraphics())
 95             using (var pen = new Pen(penColor, 4f))
 96             using (var brush = new LinearGradientBrush(rectangle, Color.Red, Color.Blue, LinearGradientMode.ForwardDiagonal))
 97             {
 98                 g.Clear(SystemColors.AppWorkspace);
 99                 g.SmoothingMode = SmoothingMode.HighQuality;
100                 pen.DashStyle = style;
101                 pen.DashCap = dashCap;
102                 g.DrawEllipse(pen, rectangle);
103             }
104
105             ShowInformation($"正圆,{rectangle},虚线冒:{dashCap.ToString()},线条样式:{style.ToString()}。");
106         }
107
108         private void btnFillWithPathGradientBrush_Click(object sender, EventArgs e)
109         {
110             var rectangle = GetRandomRectangle();
111
112             var wrapMode = (WrapMode)(random.Next(0, 5));
113
114             //var points = new Point[] { GetRandomPoint(), GetRandomPoint(), GetRandomPoint(), GetRandomPoint(), GetRandomPoint() };
115             var points = new Point[] { GetRandomPoint(), GetRandomPoint(), GetRandomPoint() };
116
117             using (var g = CreateGraphics())
118             using (var brush = new PathGradientBrush(points, wrapMode))
119             {
120                 g.Clear(SystemColors.AppWorkspace);
121                 g.SmoothingMode = SmoothingMode.HighQuality;
122                 g.DrawEllipse(Pens.LightGray, rectangle);
123                 g.FillEllipse(brush, rectangle);
124             }
125
126             ShowInformation($"路径填充,{rectangle},WrapMode:{wrapMode}。");
127         }
128     }
129 }

画圆 —— FormDrawEllipses

同样,一个窗体项目,窗体的布局风格与上一节的保持一致:

几个方法不细说,直接上几个效果图草草了事……

正圆就是一种特殊的椭圆,它的rectangle的宽与高相等;

随机路径填充也蛮有意思的,有的图画,我都想直接那类做logo了:)

好了,画圆的部分,内容就这么多,按照惯例,那么我们就来利用现有的知识,再耍个花活,画个贼溜溜的眼珠:)

private int maxDistance = 0;    // 最大移动距离,用来衡量鼠标距离眼球中心位置的极限;以这个距离极限,来等比缩放眼球移动的距离;
private Rectangle leftEyeBorderRect = Rectangle.Empty   // 左眼眼眶
    , rightEyeBorderRect = Rectangle.Empty              // 右眼眼眶
    , leftEyeBackRect = Rectangle.Empty                 // 左眼兰眼球
    , rightEyeBackRect = Rectangle.Empty                // 右眼兰眼球
    , leftEyeFrontRect = Rectangle.Empty                // 左眼黑眼珠
    , rightEyeFrontRect = Rectangle.Empty;              // 右眼黑眼珠

定义几个私有变量

注释里说明了这几个变量的意义;

 1 private void btnDrawFollowMouseEyes_Click(object sender, EventArgs e)
 2 {
 3     var center = new Point(ClientRectangle.Width / 2, (ClientRectangle.Height - pnlToolbox.Height) / 2);
 4     leftEyeBorderRect = new Rectangle(center.X - 250, center.Y - 40, 200, 80);
 5     rightEyeBorderRect = new Rectangle(center.X + 50, center.Y - 40, 200, 80);
 6     maxDistance = ClientRectangle.Width < (ClientRectangle.Height - pnlToolbox.Height)
 7         ? center.X - 150 - ClientRectangle.X
 8         : center.Y - ClientRectangle.Y;
 9
10     var style = (DashStyle)(random.Next(0, 6));
11     var dashCaps = new List<int> { 0, 2, 3 };
12     var dashCap = (DashCap)dashCaps[random.Next(0, 3)];
13
14     using (var g = CreateGraphics())
15     using (var pen = new Pen(penColor, 2f))
16     using (var brush = new SolidBrush(penColor))
17     {
18         g.Clear(SystemColors.AppWorkspace);
19         g.SmoothingMode = SmoothingMode.HighQuality;
20         pen.DashStyle = style;
21         pen.DashCap = dashCap;
22         g.FillEllipse(SystemBrushes.ControlLight, leftEyeBorderRect);
23         g.DrawEllipse(pen, leftEyeBorderRect);
24         g.FillEllipse(SystemBrushes.ControlLight, rightEyeBorderRect);
25         g.DrawEllipse(pen, rightEyeBorderRect);
26     }
27
28     FormDrawEllipses_MouseMove(null, new MouseEventArgs(MouseButtons.Left, 0, 0, 0, 0));
29
30     ShowInformation($"贼溜溜的眼睛,跟随鼠标移动的眼睛示例。");
31 }

贼眼珠按钮事件 —— btnDrawFollowMouseEyes_Click

这个事件中,主要就是画出眼眶和填充眼白;

 1 private void FormDrawEllipses_MouseMove(object sender, MouseEventArgs e)
 2 {
 3     if (Rectangle.Empty.Equals(leftEyeBorderRect) || Rectangle.Empty.Equals(rightEyeBorderRect))
 4         return;
 5
 6     using (var g = CreateGraphics())
 7     using (var pen = new Pen(penColor, 2f))
 8     using (var brush = new SolidBrush(penColor))
 9     {
10         if (Rectangle.Empty != leftEyeBackRect)
11             g.FillEllipse(SystemBrushes.ControlLight, leftEyeBackRect);
12         if (Rectangle.Empty != rightEyeBackRect)
13             g.FillEllipse(SystemBrushes.ControlLight, rightEyeBackRect);
14         leftEyeBackRect = CalcRect(leftEyeBorderRect, e.Location, maxDistance, 15, 25);
15         rightEyeBackRect = CalcRect(rightEyeBorderRect, e.Location, maxDistance, 15, 25);
16         leftEyeFrontRect = CalcRect(leftEyeBackRect, e.Location, maxDistance, 15, 5);
17         rightEyeFrontRect = CalcRect(rightEyeBackRect, e.Location, maxDistance, 15, 5);
18
19         brush.Color = Color.Blue;
20         g.FillEllipse(brush, leftEyeBackRect);
21         g.FillEllipse(brush, rightEyeBackRect);
22
23         brush.Color = Color.Black;
24         g.FillEllipse(brush, leftEyeFrontRect);
25         g.FillEllipse(brush, rightEyeFrontRect);
26
27         g.Flush();
28     }
29 }

窗体的鼠标移动事件 —— FormDrawEllipses_MouseMove

这个事件里,首先就是将上一次兰眼球的范围填充成眼白的颜色,然后就是根据当前鼠标位置,重新计算兰眼球和黑眼珠的位置,然后进行填充。

这样就形成了一个动态效果了。

 1 private Rectangle CalcRect(Rectangle baseRect, Point mouseLocation, int maxDistance, int maxMoveDistance, int radius)
 2 {
 3     var baseCenter = Point.Add(baseRect.Location, new Size(baseRect.Width / 2, baseRect.Height / 2));
 4
 5     var radian = Math.Atan2((mouseLocation.Y - baseCenter.Y), (mouseLocation.X - baseCenter.X));
 6
 7     var mouseDistance = Math.Min(maxDistance, Math.Sqrt(Math.Pow(mouseLocation.X - baseCenter.X, 2) + Math.Pow(mouseLocation.Y - baseCenter.Y, 2)));
 8
 9     var moveDistance = maxMoveDistance * (mouseDistance / maxDistance);
10
11     var targetCenter = new Point((int)Math.Ceiling(moveDistance * Math.Cos(radian) + baseCenter.X), (int)Math.Ceiling(moveDistance * Math.Sin(radian)) + baseCenter.Y);
12
13     return new Rectangle(targetCenter.X - radius, targetCenter.Y - radius, radius * 2, radius * 2);
14 }

辅助方法 —— 计算眼球和眼珠的矩形位置

OK,完活,收工。

喜欢本系列丛书的朋友,可以点击链接加入QQ交流群(994761602)【C# 破境之道】
方便各位在有疑问的时候可以及时给我个反馈。同时,也算是给各位志同道合的朋友提供一个交流的平台。
需要源码的童鞋,也可以在群文件中获取最新源代码。

原文地址:https://www.cnblogs.com/mikecheers/p/12343006.html

时间: 2024-10-06 18:21:50

《C# GDI+ 破境之道》:第一境 GDI+基础 —— 第三节:画圆形的相关文章

《C# 爬虫 破境之道》:第一境 爬虫原理 — 第五节:数据流处理的那些事儿

为什么说到数据流了呢,因为上一节中介绍了一下异步发送请求.同样,在数据流的处理上,C#也为我们提供几个有用的异步处理方法.而且,爬虫这生物,处理数据流是基础本能,比较重要.本着这个原则,就聊一聊吧. 我们经常使用到的流有文件流.内存流.网络流,爬虫与这三种流都有着密不可分的联系,可以联想以下这些场景: 当我们采集的数据,是一个压缩包或者照片,那么要存储它们到硬盘上,就需要使用到文件流了: 当我们采集的数据,是经过GZip等压缩算法压缩过的,那么要解压它,就需要使用到内存流了: 当我们的爬虫运行起

《C# 爬虫 破境之道》:第二境 爬虫应用 — 第一节:HTTP协议数据采集

首先欢迎您来到本书的第二境,本境,我们将全力打造一个实际生产环境可用的爬虫应用了.虽然只是刚开始,虽然路漫漫其修远,不过还是有点小鸡冻:P 本境打算针对几大派生类做进一步深耕,包括与应用的结合.对比它们之间的区别.综合共性.封装.One-By-One. System.IO.Packaging.PackWebRequest System.Net.FileWebRequest System.Net.FtpWebRequest System.Net.HttpWebRequest 第一节,我们先来说说最

《ASP.NET MVC 5 破境之道》:第一境 ASP.Net MVC5项目初探 &mdash; 第二节:MVC5项目结构

第一境 ASP.Net MVC5项目初探 第一节:运行第一个MVC5项目 第二节:MVC5项目结构 第三节:View层简单改造 第四节:打造首页面 第二节:MVC5项目结构 接下来,我们来看看,VS为我们自动创建的项目,是什么样子的? 可以通过菜单中[View]->[Solution Explorer]项来打开解决方案资源管理器.这是一个树形结构的视图,根节点是解决方案,解决方案节点下,就是一个一个的项目了,目前,我们的解决方案里只有一个项目(HonorShop.Web). 接下来,展开(Hon

《C# 爬虫 破境之道》:第一境 爬虫原理 — 第一节:整体思路

在构建本章节内容的时候,笔者也在想一个问题,究竟什么样的采集器框架,才能算得上是一个“全能”的呢?就我自己以往项目经历而言,可以归纳以下几个大的分类: 根据通讯协议:HTTP的.HTTPS的.TCP的.UDP的: 根据数据类型:纯文本的.json的.压缩包的.图片的.视频的: 根据更新周期:不定期更新的.定期更新的.增量更新的: 根据数据来源:单一数据源.多重数据源.多重数据源混合: 根据采集点分布:单机的,集群的: 根据反爬虫策略:控制频率的,使用代理的,使用特定UA的: 根据配置:可配置的,

《C# 爬虫 破境之道》:第一境 爬虫原理 — 第二节:WebRequest

本节主要来介绍一下,在C#中制造爬虫,最为常见.常用.实用的基础类 ------ WebRequest.WebResponse. 先来看一个示例 [1.2.1]: 1 using System; 2 using System.IO; 3 using System.Net; 4 using System.Text; 5 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 var request = WebRequest.Crea

《C# 爬虫 破境之道》:概述

第一节:写作本书的目的 关于笔者 张晓亭(Mike Cheers),1982年出生,内蒙古辽阔的大草原是我的故乡. 没有高学历,没有侃侃而谈的高谈阔论,拥有的就是那一份对技术的执著,对自我价值的追求. 我是谁,其实并不重要,我是高级开发.我是架构师.我是技术经理,这些都是我,跟各位没有半毛钱关系.最重要的是,我能给读者带来什么.接下来的日子里,就看看本书能给各位带来什么惊喜,也许到最后,你都不会记得我的名字,没有关系,相信我,那并不重要. 关于本书 本书是<破境之道>系列技术丛书中的一部分,将

二维码已死?谁将是互联网+下的破局之道

原文标题:二维码已死?谁将是互联网+下的破局之道 随着科技的进步,互联网+和工业4.0的进程,增强现实和虚拟现实将会得到前所未有爆发性的增长,并将引领下一代互联网的走向,甚至取代目前人人离不开的手机.这已成为业内人士的共识,然而VR/AR的发展是否真如想象中的美呢? 黑科技大热!你到底抓住几分发展重心? 以智能手机的快速普及过程来看,硬件.内容和网络这三大基石成为信息革命的关键点,同样AR/VR亦是.随着第五代移动通信技术(5G)频繁进入大众视野并布局,其超过4G千倍的网速将能提供更大的容量,同

程序员修炼之道第一章读后感

首先我读了序言,明白了这本书可能现在还是读不懂,但是书中的有些知识可能会帮助我以后开发软件少走点弯路, 所以,可能我现在还不太懂,但是我一定会好好阅读,尽量多理解书中的一些经验和内容,这是我对自己读这本书的要求. 求. 接着我读了第一章的内容,虽然第一章篇幅不多,但整体读下来还是收获很多的.在第一章的一开始,就教会了我做一 个做一个程序员的原则,那就是诚实和负责任.如果你做错了某些事,承认它,并给出补救的选择,不要把责任推卸给别人. 更不要找各种各样的借口.不要说事情做不到,而要说能够做什么来挽

程序员修炼之道——第一章读后感

这两天读了程序员的修炼之道第一章,感觉收获很多. 注重实效的编程源于注重实效的思考的哲学. 注重实效的程序员的特征:他们处理问题的能力,寻求解决问题的风格.态度.哲学.他们能直接超越问题本身去思考, 而我们却不能,这是值得我们思考的,总是把问题放在大语境中,,总是设法引起更大的图景,,总是设法注意更大的图景, 没有个更大的语境,就没办法注重实效,就没办法做纯更大的妥协,更长远的展望. 程序员成功的原因之一是他们对每件事情都很负责,他们不会看着项目土崩瓦.注重时效的程序员对自己的职业生涯负责,并且