<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [原創(chuàng)]《C#高級GDI+實(shí)戰(zhàn):從零開發(fā)一個(gè)流程圖》第05章:有鋸齒?拖動(dòng)閃爍?優(yōu)化!優(yōu)化!

      一、前言

      前面的課程我們實(shí)現(xiàn)了矩形、圓形的拖動(dòng),以及不同形狀間的連線,在實(shí)現(xiàn)的過程中,很多讀者都發(fā)現(xiàn)并提出來了存在顯示質(zhì)量差有鋸齒、拖動(dòng)不流暢還閃爍等問題,作為承上啟下的一節(jié)課程,我們本節(jié)就來看一上如何解決這些問題。

      相信看完的你,一定會有所收獲!

      本文地址:http://www.rzrgm.cn/lesliexin/p/18930941

      二、先看效果

      照例我們先來看一下實(shí)現(xiàn)效果:

      第1個(gè)視頻我們只需要看最后一部分,這部分對照了優(yōu)化后的連線和形狀顯示質(zhì)量:

      第2個(gè)視頻我們通過對照,看到了優(yōu)化前后拖動(dòng)流暢度及閃爍問題:

      我們下面就來依次講解。

      三、實(shí)現(xiàn)效果1:優(yōu)化鋸齒等顯示質(zhì)量

      這部分其實(shí)是很簡單的,只需要設(shè)置GDI+的一些顯示屬性就行了,我們這里為了對照,直接將這些屬性都設(shè)置為最高:

      image

      這些屬性設(shè)置后,就實(shí)現(xiàn)了效果1,不再有鋸齒之類的問題了,是不是很簡單。

      下面是完整代碼,大家可以自行編譯嘗試:

      點(diǎn)擊查看代碼
      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      
      namespace FlowChartDemo
      {
          public partial class FormDemo03V3 : FormBase
          {
              public FormDemo03V3()
              {
                  InitializeComponent();
                  DemoTitle = "第05節(jié)隨課Demo  Part3";
                  DemoNote = "效果:優(yōu)化顯示質(zhì)量,平滑圓形鋸齒、連線鋸齒等";
              }
      
              /// <summary>
              /// 矩形定義
              /// </summary>
              public class RectShape
              {
                  /// <summary>
                  /// 矩形ID
                  /// </summary>
                  public string Id { get; set; }
                  /// <summary>
                  /// 矩形位置和尺寸
                  /// </summary>
                  public Rectangle Rect { get; set; }
              }
      
              /// <summary>
              /// 圓形定義
              /// </summary>
              public class EllipseShape
              {
                  /// <summary>
                  /// 矩形ID
                  /// </summary>
                  public string Id { get; set; }
                  /// <summary>
                  /// 矩形位置和尺寸
                  /// </summary>
                  public Rectangle Rect { get; set; }
              }
      
      
              /// <summary>
              /// 直線連線定義
              /// </summary>
              public class LineLink
              {
                  /// <summary>
                  /// 連線ID
                  /// </summary>
                  public string Id { get; set; }
                  /// <summary>
                  /// 開始形狀是否是矩形
                  /// </summary>
                  public bool StartShapeIsRect { get; set; }
                  /// <summary>
                  /// 結(jié)束開關(guān)是否是矩形
                  /// </summary>
                  public bool EndShapeIsRect { get; set; }
                  /// <summary>
                  /// 連線開始形狀I(lǐng)D
                  /// </summary>
                  public string StartShapeId { get; set; }
                  /// <summary>
                  /// 連線結(jié)束形狀I(lǐng)D
                  /// </summary>
                  public string EndShapeId { get; set; }
              }
      
              /// <summary>
              /// 矩形集合
              /// </summary>
              List<RectShape> RectShapes = new List<RectShape>();
              /// <summary>
              /// 圓形集合
              /// </summary>
              List<EllipseShape> EllipseShapes = new List<EllipseShape>();
              /// <summary>
              /// 當(dāng)前界面連線集合
              /// </summary>
              List<LineLink> Links = new List<LineLink>();
      
              /// <summary>
              /// 畫一個(gè)矩形(不同顏色)
              /// </summary>
              /// <param name="g"></param>
              /// <param name="shape"></param>
              void DrawRectShape2(Graphics g, RectShape shape)
              {
                  var index = RectShapes.FindIndex(a => a.Id == shape.Id);
                  g.FillRectangle(GetBrush(index), shape.Rect);
                  g.DrawString(shape.Id, Font, Brushes.White, shape.Rect);
              }
      
              /// <summary>
              /// 畫一個(gè)圓形(不同顏色)
              /// </summary>
              /// <param name="g"></param>
              /// <param name="shape"></param>
              void DrawEllipseShape2(Graphics g, EllipseShape shape)
              {
                  var index = EllipseShapes.FindIndex(a => a.Id == shape.Id);
                  g.FillEllipse(GetBrush(index), shape.Rect);
                  g.DrawString(shape.Id, Font, Brushes.White, shape.Rect.X+20,shape.Rect.Y+20);            //注:這里可以講一下,要+20,是顯示文本
              }
      
              /// <summary>
              /// 繪制一條連線(不同顏色)
              /// </summary>
              /// <param name="g"></param>
              /// <param name="line"></param>
              void DrawLine2(Graphics g, LineLink line)
              {
                  //通過連線的開始形狀I(lǐng)D和結(jié)束形狀I(lǐng)D,計(jì)算兩個(gè)形狀的中心點(diǎn)坐標(biāo)
                  var startPoint = line.StartShapeIsRect? GetCentertPointRect(line.StartShapeId): GetCentertPointEllipse(line.StartShapeId);
                  var endPoint =line.EndShapeIsRect? GetCentertPointRect(line.EndShapeId) : GetCentertPointEllipse(line.EndShapeId);
      
                  var index = Links.FindIndex(a => a.Id == line.Id);
                  //繪制一條直線
                  g.DrawLine(GetPen(index), startPoint, endPoint);
              }
      
              /// <summary>
              /// 重新繪制當(dāng)前所有矩形和連線
              /// </summary>
              /// <param name="g"></param>
              void DrawAll(Graphics g)
              {
                  //設(shè)置顯示質(zhì)量
                  g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                  g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                  g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                  g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                  g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
      
                  g.Clear(panel1.BackColor);
                  //繪制所有矩形
                  foreach (var sp in RectShapes)
                  {
                      DrawRectShape2(g, sp);
                  }
                  //繪制所有圓形
                  foreach (var sp in EllipseShapes)
                  {
                      DrawEllipseShape2(g, sp);
                  }
                  //繪制所有連線
                  foreach (var ln in Links)
                  {
                      DrawLine2(g, ln);
                  }
              }
      
              //注:文章中說明;此處不過于抽象,后續(xù)章節(jié)會有
      
              /// <summary>
              /// 當(dāng)前是否有鼠標(biāo)按下,且有矩形被選中
              /// </summary>
              bool _isMouseDown = false;
              /// <summary>
              /// 是否是矩形被選中,不是則是圓形
              /// </summary>
              bool _isRectMouseDown = true;
              /// <summary>
              /// 最后一次鼠標(biāo)的位置
              /// </summary>
              Point _lastMouseLocation = Point.Empty;
              /// <summary>
              /// 當(dāng)前被鼠標(biāo)選中的矩形
              /// </summary>
              RectShape _selectedRectShape = null;
              /// <summary>
              /// 當(dāng)前被鼠標(biāo)選中的圓形
              /// </summary>
              EllipseShape _selectedEllipseShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第一個(gè)是否是矩形,不是則是圓形
              /// </summary>
              bool _selectedStartIsRect = true;
              /// <summary>
              /// 添加連線時(shí)選中的第一個(gè)矩形
              /// </summary>
              RectShape _selectedStartRectShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第一個(gè)圓形
              /// </summary>
              EllipseShape _selectedStartEllipseShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第二個(gè)是否是矩形,不是則是圓形
              /// </summary>
              bool _selectedEndIsRect = true;
              /// <summary>
              /// 添加連線時(shí)選中的第二個(gè)矩形
              /// </summary>
              RectShape _selectedEndRectShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第二個(gè)圓形
              /// </summary>
              EllipseShape _selectedEndEllipseShape = null;
              /// <summary>
              /// 是否正添加連線
              /// </summary>
              bool _isAddLink = false;
      
              /// <summary>
              /// 獲取不同的背景顏色
              /// </summary>
              /// <param name="i"></param>
              /// <returns></returns>
              Brush GetBrush(int i)
              {
                  switch (i)
                  {
                      case 0: return Brushes.Red;
                      case 1: return Brushes.Green;
                      case 2: return Brushes.Blue;
                      case 3: return Brushes.Orange;
                      case 4: return Brushes.Purple;
                      default: return Brushes.Red;
                  }
              }
              /// <summary>
              /// 獲取不同的畫筆顏色
              /// </summary>
              /// <param name="i"></param>
              /// <returns></returns>
              Pen GetPen(int i)
              {
                  return new Pen(GetBrush(i), 2);
              }
      
              /// <summary>
              /// 根據(jù)形狀I(lǐng)D獲取形狀的中心點(diǎn),以作為連線的起點(diǎn)或終點(diǎn)
              /// </summary>
              /// <param name="shapeId"></param>
              /// <returns></returns>
              Point GetCentertPointRect(string shapeId)
              {
                  var sp = RectShapes.Find(a => a.Id == shapeId);
                  if (sp != null)
                  {
                      var line1X = sp.Rect.X + sp.Rect.Width / 2;
                      var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
                      return new Point(line1X, line1Y);
                  }
                  return Point.Empty;
              }
              /// <summary>
              /// 根據(jù)形狀I(lǐng)D獲取形狀的中心點(diǎn),以作為連線的起點(diǎn)或終點(diǎn)
              /// </summary>
              /// <param name="shapeId"></param>
              /// <returns></returns>
              Point GetCentertPointEllipse(string shapeId)
              {
                  var sp = EllipseShapes.Find(a => a.Id == shapeId);
                  if (sp != null)
                  {
                      var line1X = sp.Rect.X + sp.Rect.Width / 2;
                      var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
                      return new Point(line1X, line1Y);
                  }
                  return Point.Empty;
              }
      
      
              private void toolStripButton1_Click(object sender, EventArgs e)
              {
                  var rs = new RectShape()
                  {
                      Id = "矩形" + (RectShapes.Count + 1),
                      Rect = new Rectangle()
                      {
                          X = 50,
                          Y = 50,
                          Width = 100,
                          Height = 100,
                      },
                  };
                  RectShapes.Add(rs);
      
                  //重繪所有矩形
                  DrawAll(panel1.CreateGraphics());
              }
      
              private void panel1_MouseDown(object sender, MouseEventArgs e)
              {
                  //當(dāng)鼠標(biāo)按下時(shí)
      
                  //取最上方的矩形,也就是最后添加的矩形
                  var sp = RectShapes.FindLast(a => a.Rect.Contains(e.Location));
                  //取最上方的圓形,也就是最后添加的圓形
                  var ep = EllipseShapes.FindLast(a => a.Rect.Contains(e.Location));
      
                  if (!_isAddLink)
                  {
                      //注:說明,這里是簡化情況,因?yàn)槭莾蓚€(gè)LIST,無法判斷序號,就先判斷矩形
                      
                      //當(dāng)前沒有處理連線狀態(tài)
                      if (sp != null)
                      {
                          //設(shè)置狀態(tài)及選中矩形
                          _isMouseDown = true;
                          _lastMouseLocation = e.Location;
                          _selectedRectShape = sp;
                          _selectedEllipseShape = null;
                          _isRectMouseDown = true;
                      }
                      else if (ep != null)
                      {
                          //設(shè)置狀態(tài)及選中圓形
                          _isMouseDown = true;
                          _lastMouseLocation = e.Location;
                          _selectedRectShape = null;
                          _selectedEllipseShape = ep;
                          _isRectMouseDown = false;
                      }
                  }
                  else
                  {
                      //正在添加連線
      
                      if (_selectedStartRectShape == null && _selectedStartEllipseShape == null)
                      {
                          //證明沒有矩形和圓形被選中則設(shè)置開始形狀
                          if (sp != null)
                          {
                              //設(shè)置開始形狀是矩形
                              _selectedStartRectShape = sp;
                              _selectedStartEllipseShape = null;
                              _selectedStartIsRect = true;
                          }
                          else if (ep != null)
                          {
                              //設(shè)置開始形狀是圓形
                              _selectedStartRectShape = null;
                              _selectedStartEllipseShape = ep;
                              _selectedStartIsRect = false;
                          }
                          toolStripStatusLabel1.Text = "請點(diǎn)擊第2個(gè)形狀";
                      }
                      else
                      {
                          //判斷第2個(gè)形狀是否是第1個(gè)形狀
                          if (sp != null)
                          {
                              //證明當(dāng)前選中的是矩形
                              if (_selectedStartRectShape != null)
                              {
                                  //證明第1步選中的矩形
      
                                  //判斷當(dāng)前選中的矩形是否是第1步選中的矩形
                                  if (_selectedStartRectShape.Id == sp.Id)
                                  {
                                      toolStripStatusLabel1.Text = "不可選擇同一個(gè)形狀,請重新點(diǎn)擊第2個(gè)形狀";
                                      return;
                                  }
                              }
                          }
                          else if (ep != null)
                          {
                              //證明當(dāng)前選中的圓形
                              if (_selectedStartEllipseShape != null)
                              {
                                  //證明第1步選中的矩形
      
                                  //判斷當(dāng)前選中的矩形是否是第1步選中的矩形
                                  if (_selectedStartEllipseShape.Id == ep.Id)
                                  {
                                      toolStripStatusLabel1.Text = "不可選擇同一個(gè)形狀,請重新點(diǎn)擊第2個(gè)形狀";
                                      return;
                                  }
                              }
                          }
      
      
                          //注:文章中說明:因?yàn)樘^復(fù)雜,且不是本節(jié)重點(diǎn),但不再進(jìn)行去重判斷
      
                          if (sp != null)
                          {
                              //設(shè)置結(jié)束形狀是矩形
                              _selectedEndRectShape = sp;
                              _selectedEndEllipseShape = null;
                              _selectedEndIsRect = true;
                          }
                          else if (ep != null)
                          {
                              //設(shè)置結(jié)束形狀是圓形
                              _selectedEndRectShape = null;
                              _selectedEndEllipseShape = ep;
                              _selectedEndIsRect = false;
                          }
                          else
                          {
                              return;
                          }
      
      
                          //兩個(gè)形狀都設(shè)置了,便添加一條新連線
                          Links.Add(new LineLink()
                          {
                              Id = "連線" + (Links.Count + 1),
                              StartShapeId =_selectedStartIsRect? _selectedStartRectShape.Id:_selectedStartEllipseShape.Id,
                              EndShapeId =_selectedEndIsRect? _selectedEndRectShape.Id:_selectedEndEllipseShape.Id,
                              StartShapeIsRect=_selectedStartIsRect,
                              EndShapeIsRect=_selectedEndIsRect,
                          });
                          //兩個(gè)形狀都已選擇,結(jié)束添加連線狀態(tài)
                          _isAddLink = false;
                          toolStripStatusLabel1.Text = "";
                          //重繪以顯示連線
                          DrawAll(panel1.CreateGraphics());
      
      
                      }
      
                  }
      
              }
      
              private void panel1_MouseMove(object sender, MouseEventArgs e)
              {
                  //當(dāng)鼠標(biāo)移動(dòng)時(shí)
      
                  //如果處于添加連線時(shí),則不移動(dòng)形狀
                  if (_isAddLink) return;
      
                  if (_isMouseDown)
                  {
                      //當(dāng)且僅當(dāng):有鼠標(biāo)按下且有矩形被選中時(shí),才進(jìn)行后續(xù)操作
      
                      //改變選中矩形的位置信息,隨著鼠標(biāo)移動(dòng)而移動(dòng)
      
                      //計(jì)算鼠標(biāo)位置變化信息
                      var moveX = e.Location.X - _lastMouseLocation.X;
                      var moveY = e.Location.Y - _lastMouseLocation.Y;
      
                      //將選中形狀的位置進(jìn)行同樣的變化
                      if (_isRectMouseDown)
                      {
                          var oldXY = _selectedRectShape.Rect.Location;
                          oldXY.Offset(moveX, moveY);
                          _selectedRectShape.Rect = new Rectangle(oldXY, _selectedRectShape.Rect.Size);
      
                      }
                      else
                      {
                          var oldXY = _selectedEllipseShape.Rect.Location;
                          oldXY.Offset(moveX, moveY);
                          _selectedEllipseShape.Rect = new Rectangle(oldXY, _selectedEllipseShape.Rect.Size);
      
                      }
      
                      //記錄當(dāng)前鼠標(biāo)位置
                      _lastMouseLocation.Offset(moveX, moveY);
      
                      //重繪所有矩形
                      DrawAll(panel1.CreateGraphics());
                  }
      
              }
      
              private void panel1_MouseUp(object sender, MouseEventArgs e)
              {
                  //當(dāng)鼠標(biāo)松開時(shí)
                  if (_isMouseDown)
                  {
                      //當(dāng)且僅當(dāng):有鼠標(biāo)按下且有矩形被選中時(shí),才進(jìn)行后續(xù)操作
      
                      //重置相關(guān)記錄信息
                      _isMouseDown = false;
                      _lastMouseLocation = Point.Empty;
                      _selectedRectShape = null;
                      _selectedEllipseShape = null;
                  }
              }
      
              private void toolStripButton2_Click(object sender, EventArgs e)
              {
                  _isAddLink = true;
                  _selectedStartRectShape = null;
                  _selectedEndRectShape = null;
                  _selectedStartEllipseShape = null;
                  _selectedEndEllipseShape = null;
                  toolStripStatusLabel1.Text = "請點(diǎn)擊第1個(gè)形狀";
              }
      
              private void toolStripButton3_Click(object sender, EventArgs e)
              {
                  _isAddLink = false;
                  _selectedStartRectShape = null;
                  _selectedEndRectShape = null;
                  toolStripStatusLabel1.Text = "";
                  DrawAll(panel1.CreateGraphics());
              }
      
              private void toolStripButton4_Click(object sender, EventArgs e)
              {
                  var rs = new EllipseShape()
                  {
                      Id = "圓形" + (EllipseShapes.Count + 1),
                      Rect = new Rectangle()
                      {
                          X = 50,
                          Y = 50,
                          Width = 100,
                          Height = 100,
                      },
                  };
                  EllipseShapes.Add(rs);
      
                  //重繪所有矩形
                  DrawAll(panel1.CreateGraphics());
              }
          }
      
      
      }
      
      

      四、實(shí)現(xiàn)效果2:解決拖動(dòng)慢、閃爍等問題

      本來未設(shè)置顯示質(zhì)量時(shí),拖動(dòng)形狀時(shí)就會閃爍,而經(jīng)過上面的設(shè)置后,拖動(dòng)變慢了,閃爍更嚴(yán)重了。

      閃爍是因?yàn)槲覀兠看瓮蟿?dòng)都是整個(gè)控件清空再依次繪制所有形狀和連線,這些耗時(shí)就會導(dǎo)致閃爍問題。而在設(shè)置為高質(zhì)量顯示后,繪制更慢,閃爍便會更明顯,拖動(dòng)起來也感覺不跟手變慢了。

      我們下面就來解決一下這個(gè)問題。

      注:更詳細(xì)深入的圖文講解在這個(gè)教程里有說明,不再贅述:http://www.rzrgm.cn/lesliexin/p/16554752.html

      1,開啟雙緩沖

      可以說遇事不決,先開雙緩沖,如圖:

      image

      當(dāng)然,僅僅開啟雙緩沖效果并不大,還要搭配下面的處理才行。

      2,使用內(nèi)存繪圖

      內(nèi)存繪圖,沒什么神秘的,就是將所有形狀、連線繪制在一個(gè)位圖(Bitmap)對象上而已,當(dāng)繪制完成后,再將此位圖繪制到控件上,以提高繪制效率,達(dá)到去除閃爍的問題。

      image

      如上所示,我們先創(chuàng)建一個(gè)與控件尺寸一樣大的位圖對象,然后在此位圖上繪制所有連線,最后繪制到控件上。

      好了,到此我們就實(shí)現(xiàn)了效果2,基本上就不會有拖動(dòng)慢和拖動(dòng)時(shí)閃爍的問題了。

      下面是完整代碼,大家可以自行編譯嘗試:

      點(diǎn)擊查看代碼
      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      
      namespace FlowChartDemo
      {
          public partial class FormDemo04V1 : FormBase
          {
              public FormDemo04V1()
              {
                  InitializeComponent();
                  DemoTitle = "第06節(jié)隨課Demo  Part1";
                  DemoNote = "效果:優(yōu)化拖動(dòng)慢、拖動(dòng)時(shí)閃爍等問題";
      
                  SetStyle(ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.UserPaint |
                      ControlStyles.OptimizedDoubleBuffer,true);
              }
      
              /// <summary>
              /// 矩形定義
              /// </summary>
              public class RectShape
              {
                  /// <summary>
                  /// 矩形ID
                  /// </summary>
                  public string Id { get; set; }
                  /// <summary>
                  /// 矩形位置和尺寸
                  /// </summary>
                  public Rectangle Rect { get; set; }
              }
      
              /// <summary>
              /// 圓形定義
              /// </summary>
              public class EllipseShape
              {
                  /// <summary>
                  /// 矩形ID
                  /// </summary>
                  public string Id { get; set; }
                  /// <summary>
                  /// 矩形位置和尺寸
                  /// </summary>
                  public Rectangle Rect { get; set; }
              }
      
      
              /// <summary>
              /// 直線連線定義
              /// </summary>
              public class LineLink
              {
                  /// <summary>
                  /// 連線ID
                  /// </summary>
                  public string Id { get; set; }
                  /// <summary>
                  /// 開始形狀是否是矩形
                  /// </summary>
                  public bool StartShapeIsRect { get; set; }
                  /// <summary>
                  /// 結(jié)束開關(guān)是否是矩形
                  /// </summary>
                  public bool EndShapeIsRect { get; set; }
                  /// <summary>
                  /// 連線開始形狀I(lǐng)D
                  /// </summary>
                  public string StartShapeId { get; set; }
                  /// <summary>
                  /// 連線結(jié)束形狀I(lǐng)D
                  /// </summary>
                  public string EndShapeId { get; set; }
              }
      
              /// <summary>
              /// 矩形集合
              /// </summary>
              List<RectShape> RectShapes = new List<RectShape>();
              /// <summary>
              /// 圓形集合
              /// </summary>
              List<EllipseShape> EllipseShapes = new List<EllipseShape>();
              /// <summary>
              /// 當(dāng)前界面連線集合
              /// </summary>
              List<LineLink> Links = new List<LineLink>();
      
              /// <summary>
              /// 畫一個(gè)矩形(不同顏色)
              /// </summary>
              /// <param name="g"></param>
              /// <param name="shape"></param>
              void DrawRectShape2(Graphics g, RectShape shape)
              {
                  var index = RectShapes.FindIndex(a => a.Id == shape.Id);
                  g.FillRectangle(GetBrush(index), shape.Rect);
                  g.DrawString(shape.Id, Font, Brushes.White, shape.Rect);
              }
      
              /// <summary>
              /// 畫一個(gè)圓形(不同顏色)
              /// </summary>
              /// <param name="g"></param>
              /// <param name="shape"></param>
              void DrawEllipseShape2(Graphics g, EllipseShape shape)
              {
                  var index = EllipseShapes.FindIndex(a => a.Id == shape.Id);
                  g.FillEllipse(GetBrush(index), shape.Rect);
                  g.DrawString(shape.Id, Font, Brushes.White, shape.Rect.X+20,shape.Rect.Y+20);            //注:這里可以講一下,要+20,是顯示文本
              }
      
              /// <summary>
              /// 繪制一條連線(不同顏色)
              /// </summary>
              /// <param name="g"></param>
              /// <param name="line"></param>
              void DrawLine2(Graphics g, LineLink line)
              {
                  //通過連線的開始形狀I(lǐng)D和結(jié)束形狀I(lǐng)D,計(jì)算兩個(gè)形狀的中心點(diǎn)坐標(biāo)
                  var startPoint = line.StartShapeIsRect? GetCentertPointRect(line.StartShapeId): GetCentertPointEllipse(line.StartShapeId);
                  var endPoint =line.EndShapeIsRect? GetCentertPointRect(line.EndShapeId) : GetCentertPointEllipse(line.EndShapeId);
      
                  var index = Links.FindIndex(a => a.Id == line.Id);
                  //繪制一條直線
                  g.DrawLine(GetPen(index), startPoint, endPoint);
              }
      
              //注:文章中說明,參見下面的地址,講的很清楚。
      
      
              Bitmap _bmp;
      
              /// <summary>
              /// 重新繪制當(dāng)前所有矩形和連線
              /// </summary>
              /// <param name="g"></param>
              void DrawAll(Graphics g1)
              {
                  //創(chuàng)建內(nèi)存繪圖,將形狀和連線繪制到此內(nèi)存繪圖上,然后再一次性繪制到控件上
                  _bmp = new Bitmap(panel1.Width, panel1.Height);
                  var g = Graphics.FromImage(_bmp);
      
                  //設(shè)置顯示質(zhì)量
                  g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                  g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                  g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                  g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                  g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
      
                  g.Clear(panel1.BackColor);
                  //繪制所有矩形
                  foreach (var sp in RectShapes)
                  {
                      DrawRectShape2(g, sp);
                  }
                  //繪制所有圓形
                  foreach (var sp in EllipseShapes)
                  {
                      DrawEllipseShape2(g, sp);
                  }
                  //繪制所有連線
                  foreach (var ln in Links)
                  {
                      DrawLine2(g, ln);
                  }
      
                  //繪制內(nèi)存繪圖到控件上
                  g1.DrawImage(_bmp, new PointF(0, 0));
              }
      
              //注:文章中說明;此處不過于抽象,后續(xù)章節(jié)會有
      
              /// <summary>
              /// 當(dāng)前是否有鼠標(biāo)按下,且有矩形被選中
              /// </summary>
              bool _isMouseDown = false;
              /// <summary>
              /// 是否是矩形被選中,不是則是圓形
              /// </summary>
              bool _isRectMouseDown = true;
              /// <summary>
              /// 最后一次鼠標(biāo)的位置
              /// </summary>
              Point _lastMouseLocation = Point.Empty;
              /// <summary>
              /// 當(dāng)前被鼠標(biāo)選中的矩形
              /// </summary>
              RectShape _selectedRectShape = null;
              /// <summary>
              /// 當(dāng)前被鼠標(biāo)選中的圓形
              /// </summary>
              EllipseShape _selectedEllipseShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第一個(gè)是否是矩形,不是則是圓形
              /// </summary>
              bool _selectedStartIsRect = true;
              /// <summary>
              /// 添加連線時(shí)選中的第一個(gè)矩形
              /// </summary>
              RectShape _selectedStartRectShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第一個(gè)圓形
              /// </summary>
              EllipseShape _selectedStartEllipseShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第二個(gè)是否是矩形,不是則是圓形
              /// </summary>
              bool _selectedEndIsRect = true;
              /// <summary>
              /// 添加連線時(shí)選中的第二個(gè)矩形
              /// </summary>
              RectShape _selectedEndRectShape = null;
              /// <summary>
              /// 添加連線時(shí)選中的第二個(gè)圓形
              /// </summary>
              EllipseShape _selectedEndEllipseShape = null;
              /// <summary>
              /// 是否正添加連線
              /// </summary>
              bool _isAddLink = false;
      
              /// <summary>
              /// 獲取不同的背景顏色
              /// </summary>
              /// <param name="i"></param>
              /// <returns></returns>
              Brush GetBrush(int i)
              {
                  switch (i)
                  {
                      case 0: return Brushes.Red;
                      case 1: return Brushes.Green;
                      case 2: return Brushes.Blue;
                      case 3: return Brushes.Orange;
                      case 4: return Brushes.Purple;
                      default: return Brushes.Red;
                  }
              }
              /// <summary>
              /// 獲取不同的畫筆顏色
              /// </summary>
              /// <param name="i"></param>
              /// <returns></returns>
              Pen GetPen(int i)
              {
                  return new Pen(GetBrush(i), 2);
              }
      
              /// <summary>
              /// 根據(jù)形狀I(lǐng)D獲取形狀的中心點(diǎn),以作為連線的起點(diǎn)或終點(diǎn)
              /// </summary>
              /// <param name="shapeId"></param>
              /// <returns></returns>
              Point GetCentertPointRect(string shapeId)
              {
                  var sp = RectShapes.Find(a => a.Id == shapeId);
                  if (sp != null)
                  {
                      var line1X = sp.Rect.X + sp.Rect.Width / 2;
                      var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
                      return new Point(line1X, line1Y);
                  }
                  return Point.Empty;
              }
              /// <summary>
              /// 根據(jù)形狀I(lǐng)D獲取形狀的中心點(diǎn),以作為連線的起點(diǎn)或終點(diǎn)
              /// </summary>
              /// <param name="shapeId"></param>
              /// <returns></returns>
              Point GetCentertPointEllipse(string shapeId)
              {
                  var sp = EllipseShapes.Find(a => a.Id == shapeId);
                  if (sp != null)
                  {
                      var line1X = sp.Rect.X + sp.Rect.Width / 2;
                      var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
                      return new Point(line1X, line1Y);
                  }
                  return Point.Empty;
              }
      
      
              private void toolStripButton1_Click(object sender, EventArgs e)
              {
                  var rs = new RectShape()
                  {
                      Id = "矩形" + (RectShapes.Count + 1),
                      Rect = new Rectangle()
                      {
                          X = 50,
                          Y = 50,
                          Width = 100,
                          Height = 100,
                      },
                  };
                  RectShapes.Add(rs);
      
                  //重繪所有矩形
                  DrawAll(panel1.CreateGraphics());
              }
      
              private void panel1_MouseDown(object sender, MouseEventArgs e)
              {
                  //當(dāng)鼠標(biāo)按下時(shí)
      
                  //取最上方的矩形,也就是最后添加的矩形
                  var sp = RectShapes.FindLast(a => a.Rect.Contains(e.Location));
                  //取最上方的圓形,也就是最后添加的圓形
                  var ep = EllipseShapes.FindLast(a => a.Rect.Contains(e.Location));
      
                  if (!_isAddLink)
                  {
                      //注:說明,這里是簡化情況,因?yàn)槭莾蓚€(gè)LIST,無法判斷序號,就先判斷矩形
                      
                      //當(dāng)前沒有處理連線狀態(tài)
                      if (sp != null)
                      {
                          //設(shè)置狀態(tài)及選中矩形
                          _isMouseDown = true;
                          _lastMouseLocation = e.Location;
                          _selectedRectShape = sp;
                          _selectedEllipseShape = null;
                          _isRectMouseDown = true;
                      }
                      else if (ep != null)
                      {
                          //設(shè)置狀態(tài)及選中圓形
                          _isMouseDown = true;
                          _lastMouseLocation = e.Location;
                          _selectedRectShape = null;
                          _selectedEllipseShape = ep;
                          _isRectMouseDown = false;
                      }
                  }
                  else
                  {
                      //正在添加連線
      
                      if (_selectedStartRectShape == null && _selectedStartEllipseShape == null)
                      {
                          //證明沒有矩形和圓形被選中則設(shè)置開始形狀
                          if (sp != null)
                          {
                              //設(shè)置開始形狀是矩形
                              _selectedStartRectShape = sp;
                              _selectedStartEllipseShape = null;
                              _selectedStartIsRect = true;
                          }
                          else if (ep != null)
                          {
                              //設(shè)置開始形狀是圓形
                              _selectedStartRectShape = null;
                              _selectedStartEllipseShape = ep;
                              _selectedStartIsRect = false;
                          }
                          toolStripStatusLabel1.Text = "請點(diǎn)擊第2個(gè)形狀";
                      }
                      else
                      {
                          //判斷第2個(gè)形狀是否是第1個(gè)形狀
                          if (sp != null)
                          {
                              //證明當(dāng)前選中的是矩形
                              if (_selectedStartRectShape != null)
                              {
                                  //證明第1步選中的矩形
      
                                  //判斷當(dāng)前選中的矩形是否是第1步選中的矩形
                                  if (_selectedStartRectShape.Id == sp.Id)
                                  {
                                      toolStripStatusLabel1.Text = "不可選擇同一個(gè)形狀,請重新點(diǎn)擊第2個(gè)形狀";
                                      return;
                                  }
                              }
                          }
                          else if (ep != null)
                          {
                              //證明當(dāng)前選中的圓形
                              if (_selectedStartEllipseShape != null)
                              {
                                  //證明第1步選中的矩形
      
                                  //判斷當(dāng)前選中的矩形是否是第1步選中的矩形
                                  if (_selectedStartEllipseShape.Id == ep.Id)
                                  {
                                      toolStripStatusLabel1.Text = "不可選擇同一個(gè)形狀,請重新點(diǎn)擊第2個(gè)形狀";
                                      return;
                                  }
                              }
                          }
      
      
                          //注:文章中說明:因?yàn)樘^復(fù)雜,且不是本節(jié)重點(diǎn),但不再進(jìn)行去重判斷
      
                          if (sp != null)
                          {
                              //設(shè)置結(jié)束形狀是矩形
                              _selectedEndRectShape = sp;
                              _selectedEndEllipseShape = null;
                              _selectedEndIsRect = true;
                          }
                          else if (ep != null)
                          {
                              //設(shè)置結(jié)束形狀是圓形
                              _selectedEndRectShape = null;
                              _selectedEndEllipseShape = ep;
                              _selectedEndIsRect = false;
                          }
                          else
                          {
                              return;
                          }
      
      
                          //兩個(gè)形狀都設(shè)置了,便添加一條新連線
                          Links.Add(new LineLink()
                          {
                              Id = "連線" + (Links.Count + 1),
                              StartShapeId =_selectedStartIsRect? _selectedStartRectShape.Id:_selectedStartEllipseShape.Id,
                              EndShapeId =_selectedEndIsRect? _selectedEndRectShape.Id:_selectedEndEllipseShape.Id,
                              StartShapeIsRect=_selectedStartIsRect,
                              EndShapeIsRect=_selectedEndIsRect,
                          });
                          //兩個(gè)形狀都已選擇,結(jié)束添加連線狀態(tài)
                          _isAddLink = false;
                          toolStripStatusLabel1.Text = "";
                          //重繪以顯示連線
                          DrawAll(panel1.CreateGraphics());
      
      
                      }
      
                  }
      
              }
      
              private void panel1_MouseMove(object sender, MouseEventArgs e)
              {
                  //當(dāng)鼠標(biāo)移動(dòng)時(shí)
      
                  //如果處于添加連線時(shí),則不移動(dòng)形狀
                  if (_isAddLink) return;
      
                  if (_isMouseDown)
                  {
                      //當(dāng)且僅當(dāng):有鼠標(biāo)按下且有矩形被選中時(shí),才進(jìn)行后續(xù)操作
      
                      //改變選中矩形的位置信息,隨著鼠標(biāo)移動(dòng)而移動(dòng)
      
                      //計(jì)算鼠標(biāo)位置變化信息
                      var moveX = e.Location.X - _lastMouseLocation.X;
                      var moveY = e.Location.Y - _lastMouseLocation.Y;
      
                      //將選中形狀的位置進(jìn)行同樣的變化
                      if (_isRectMouseDown)
                      {
                          var oldXY = _selectedRectShape.Rect.Location;
                          oldXY.Offset(moveX, moveY);
                          _selectedRectShape.Rect = new Rectangle(oldXY, _selectedRectShape.Rect.Size);
      
                      }
                      else
                      {
                          var oldXY = _selectedEllipseShape.Rect.Location;
                          oldXY.Offset(moveX, moveY);
                          _selectedEllipseShape.Rect = new Rectangle(oldXY, _selectedEllipseShape.Rect.Size);
      
                      }
      
                      //記錄當(dāng)前鼠標(biāo)位置
                      _lastMouseLocation.Offset(moveX, moveY);
      
                      //重繪所有矩形
                      DrawAll(panel1.CreateGraphics());
                  }
      
              }
      
              private void panel1_MouseUp(object sender, MouseEventArgs e)
              {
                  //當(dāng)鼠標(biāo)松開時(shí)
                  if (_isMouseDown)
                  {
                      //當(dāng)且僅當(dāng):有鼠標(biāo)按下且有矩形被選中時(shí),才進(jìn)行后續(xù)操作
      
                      //重置相關(guān)記錄信息
                      _isMouseDown = false;
                      _lastMouseLocation = Point.Empty;
                      _selectedRectShape = null;
                      _selectedEllipseShape = null;
                  }
              }
      
              private void toolStripButton2_Click(object sender, EventArgs e)
              {
                  _isAddLink = true;
                  _selectedStartRectShape = null;
                  _selectedEndRectShape = null;
                  _selectedStartEllipseShape = null;
                  _selectedEndEllipseShape = null;
                  toolStripStatusLabel1.Text = "請點(diǎn)擊第1個(gè)形狀";
              }
      
              private void toolStripButton3_Click(object sender, EventArgs e)
              {
                  _isAddLink = false;
                  _selectedStartRectShape = null;
                  _selectedEndRectShape = null;
                  toolStripStatusLabel1.Text = "";
                  DrawAll(panel1.CreateGraphics());
              }
      
              private void toolStripButton4_Click(object sender, EventArgs e)
              {
                  var rs = new EllipseShape()
                  {
                      Id = "圓形" + (EllipseShapes.Count + 1),
                      Rect = new Rectangle()
                      {
                          X = 50,
                          Y = 50,
                          Width = 100,
                          Height = 100,
                      },
                  };
                  EllipseShapes.Add(rs);
      
                  //重繪所有矩形
                  DrawAll(panel1.CreateGraphics());
              }
          }
      
      
      }
      
      

      五、結(jié)語

      本節(jié)課程很簡單,是基于當(dāng)前為止的需要,簡單的解決了顯示質(zhì)量和拖動(dòng)閃爍的問題,當(dāng)然上面的代碼并不非常完善,像資源釋放、全屏顯示時(shí)仍可能出現(xiàn)拖動(dòng)不跟手等問題都沒作處理,這些不是本節(jié)重點(diǎn),我們會在后面的課程里一一解決。

      下節(jié)課程我們就來對矩形、圓形等形狀和連線做一個(gè)抽象,以解決前面課程遇到的增加一個(gè)新的形狀時(shí)代碼就要添加好多額外判斷代碼的問題,以及為后續(xù)的支持菱形、平行四邊形等任意形狀做基礎(chǔ)。當(dāng)然連線也是,后面不止有直線,還有貝塞爾曲線、正交連線等各種連線。

      感謝大家的觀看,本人水平有限,文章不足之處歡迎大家評論指正。

      -[END]-

      posted @ 2025-07-02 13:09  leslie_xin  閱讀(782)  評論(6)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产又爽又黄又刺激的视频| 精品人妻日韩中文字幕| 69精品丰满人妻无码视频a片| 国产破外女出血视频| 国产精品亚洲精品日韩已满十八小| 国产精品午夜剧场免费观看| 孙吴县| 久久精品无码一区二区三区 | 国产精品色一区二区三区| 国产超碰无码最新上传| 国产精品中文av专线| 成人性影院| 国产不卡一区二区四区| 国产精品无码无片在线观看3d| 性色在线视频精品| 亚洲aⅴ男人的天堂在线观看| 国产亚洲精品黑人粗大精选| 国产国语一级毛片| 乱色欧美激惰| 国产影片AV级毛片特别刺激| 国产区一区二区现看视频| 国产精品福利在线观看无码卡一| 亚洲成A人片在线观看无码不卡| 在线 欧美 中文 亚洲 精品| 极品无码国模国产在线观看| 亚洲成人av在线系列| 精品国产免费一区二区三区香蕉| 国产成人a∨激情视频厨房| 丰满无码人妻热妇无码区| 文安县| 视频一区二区 国产视频| 久久亚洲av午夜福利精品一区 | 各种少妇wbb撒尿| 国产l精品国产亚洲区| 亚洲一区二区三区人妻天堂| 中文国产成人久久精品小说| 国产成年女人特黄特色大片免费| 99热门精品一区二区三区无码| 亚洲第一二三区日韩国产| 又粗又硬又黄a级毛片| 中文字幕久久国产精品|