有了上一节画矩形的基础,画圆形就不要太轻松+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# 破境之道】
方便各位在有疑问的时候可以及时给我个反馈。同时,也算是给各位志同道合的朋友提供一个交流的平台。
需要源码的童鞋,也可以在群文件中获取最新源代码。
posted @ 2020-02-22 08:53 MikeCheers 阅读(896) 评论(0) 推荐(0) 编辑
摘要: 我们在第五节中提到一个问题,任务队列增长速度太快,与之对应的采集、分析、处理速度远远跟不上,造成内存快速增长,带宽占用过高,CPU使用率过高,这样是极度有害系统健康的。 我们在开发采集程序的时候,总是希望能够尽快将数据爬取下来,如果总任务数量很小(2~3K请求数之内),总耗费时长很短(1~2分钟之内 阅读全文
posted @ 2020-02-21 10:24 MikeCheers 阅读(694) 评论(5) 推荐(5) 编辑
摘要: 有了上一节画线的基础,画矩形的各种边线就特别好理解了,所以,本节在矩形边线上,就不做过多的讲解了,关注一下画“随机矩形”的具体实现就好。与画线相比较,画矩形稍微复杂的一点就是在于它多了很多填充的样式。接下来,我们就来细细品味一番。 同样,一个窗体项目,窗体的布局风格与上一节的保持一致: 1 name 阅读全文
posted @ 2020-02-20 10:37 MikeCheers 阅读(1266) 评论(1) 推荐(3) 编辑
摘要: 之前的章节也略有提及反爬策略,本节,我们就来系统的对反爬、反反爬的种种,做一个了结。 从防盗链说起: 自从论坛兴起的时候,网上就有很多人会在论坛里发布一些很棒的文章,与当下流行的“点赞”“分享”一样,很多人都会因为“欣赏”而选择“转发”到各大论坛。今时今日,我们大多数人在转载他人文章时,还会特别注明 阅读全文
posted @ 2020-02-19 13:03 MikeCheers 阅读(1146) 评论(3) 推荐(7) 编辑
摘要: 今天正式开一本新书,《C# GDI+ 破镜之道》,同样是破镜之道系列丛书的一分子。 关于GDI+呢,官方的解释是这样的: GDI+ 是 Microsoft Windows 操作系统的窗体子系统应用程序编程接口 (API)。 GDI+ 是负责在屏幕和打印机上显示的信息。 顾名思义,GDI+ 是包含 G 阅读全文
posted @ 2020-02-19 09:17 MikeCheers 阅读(1982) 评论(0) 推荐(6) 编辑
摘要: 在上一节中,我们完成了一个简单的采集示例。本节呢,我们先来小结一下,这个示例可能存在的问题: 没有做异常处理 没有做反爬应对策略 没有做重试机制 没有做并发限制 …… 呃,看似平静的表面下还是隐藏着不少杀机的…… 但本节不打算对付上述问题,而是先关注一个隐藏更深的问题,这个问题,可能会牵扯很多人(包 阅读全文
posted @ 2020-02-18 09:28 MikeCheers 阅读(463) 评论(0) 推荐(3) 编辑
摘要: 之前的章节,我们陆续的介绍了使用C#制作爬虫的基础知识,而且现在也应该比较了解如何制作一只简单的Web爬虫了。 本节,我们来做一个完整的爬虫系统,将之前的零散的东西串联起来,可以作为一个爬虫项目运作流程的初探,但实际项目中,还需要解决其他一些问题,我们后续章节也将继续深耕:) 先来看一下解决方案的整 阅读全文
posted @ 2020-02-17 09:15 MikeCheers 阅读(1042) 评论(0) 推荐(1) 编辑
摘要: 背景: 工作机器上安装了4个T的磁盘,包含很多食之无味、弃之可惜的历史项目文件、学习资料(文本、视频),毕竟十多年的积累,基本都在,但却凌乱不堪,想找点儿什么,也似大海捞针。 目标: 历史项目 以项目名称创建根目录,划分源码文档、需求文档、设计文档、资源文件、数据库、编译输出、加壳加密、交付历史等子 阅读全文
posted @ 2020-02-10 18:23 MikeCheers 阅读(197) 评论(0) 推荐(0) 编辑
摘要: 续上一节内容,本节主要讲解一下Web压缩数据的处理方法。 在HTTP协议中指出,可以通过对内容压缩来减少网络流量,从而提高网络传输的性能。 那么问题来了,在HTTP中,采用的是什么样的压缩格式和机制呢? 首先呢,先说压缩格式,主要有三种: DEFLATE,是一种使用 Lempel-Ziv 压缩算法( 阅读全文
posted @ 2020-01-19 10:34 MikeCheers 阅读(885) 评论(0) 推荐(4) 编辑
摘要: 续上一节内容,对Web爬虫进行进一步封装,通过委托将爬虫自己的状态变化以及数据变化暴露给上层业务处理或应用程序。 为了方便以后的扩展,我先定义一个蚂蚁抽象类(Ant),并让WorkerAnt(工蚁)继承自它。 [Code 2.2.1] 1 using System; 2 3 public abstr 阅读全文
posted @ 2020-01-16 01:28 MikeCheers 阅读(395) 评论(0) 推荐(1) 编辑
点击右上角即可分享
微信分享提示