使用Graphics绘制图形

目标是做一个扫描wafer的界面,界面初始化时会根据wafer的直径和die的边长绘制下图中的样子;
单击启动,程序会开始扫描变绿。
使用Graphics绘制图形
并且窗体拉大缩小时,绘制的图形可以跟着放大缩小,(正常wafer有12寸或者8寸的,不缩小屏幕也放不下),刚开始时是计算图形所在容器的size变化倍数,然后乘上wafer的直径和die的边长,重新绘制图形。但是这样算出来的倍数会有小数,计算的时候有误差,肯定是不对的。最后想到绘制图形和放大缩小用同一个Graphics,这样在放大缩小图形时直接操作这个Graphics就可以了。效果如下图。

使用Graphics绘制图形
下面是代码:
先创建一个cell.cs类

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ISIE.COMMON
{
    public class Cell
    {
        #region Fields

        private Color _backColor;
        //private bool _IsBorder;
        private Brush _Brush;
        private bool _bSelected = false;
        private Rectangle _RectangleF;
        #endregion

        #region Property
        public Color BackColor { get { return this._backColor; } set { this._backColor = value; } }
        //public bool IsBorder { get { return this._IsBorder; } set { this._IsBorder = value; } }
        public Rectangle Rectangle { get { return this._RectangleF; } set { this._RectangleF = value; } }
        public Brush Brush { get { return this._Brush; } set { this._Brush = value; } }
        public bool Selected { get { return this._bSelected; } set { this._bSelected = value; } } 
        #endregion


        #region Method
        public Cell(Rectangle rectangle)
        {
            this._RectangleF = rectangle;
        }
        public void Draw(Graphics g)
        {
            if (_Brush == null)
            {
                _Brush = new SolidBrush(Color.Gray);
            }
            if (this.Selected)
            {
                g.FillRectangle(new SolidBrush(Color.Green), Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height);
            }
            else
            {
                g.FillRectangle(_Brush, Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height);
            }

            g.DrawRectangle(new Pen(Color.Black), Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height);

        }

        #endregion
    }
}

其次是ScannerViewer自定义控件;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ISIE.COMMON
{
    public partial class ScannerViewer : UserControl
    {
        public ScannerViewer()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw
              | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            this.DoubleBuffered = true;
        }
        private int _dieSideLength;
        private int _waferDiameter;
        private Point _startLocation;
        private Point _ellipseCenter;
        private List<Cell> cells = new List<Cell>();
        private int _currentIdx = -1;
        private bool isSelect = false;
        private int _interval;
        private double _mul = 1;
        
        public int DieSideLength { get => _dieSideLength; set => _dieSideLength = value; }
        public int WaferDiameter { get => _waferDiameter; set => _waferDiameter = value; }
        public Point StartLocation { get => _startLocation; set => _startLocation = value; }
        public Point SetEllipseCenter { set => _ellipseCenter = value; }
        public int Interval { get { return _interval <= 0 ? 1000 : _interval; } set { _interval = value <= 0 ? 1000 : value; } }
        public double Mul { get { return _mul; } set { _mul = value == 0 ? 0.1 : value; } }
        public int CellCount { get => cells.Count; }
        public int CurrentIdx { get => _currentIdx; set => _currentIdx = value; }
        public void Init()
        {
            _ellipseCenter = new Point(_waferDiameter / 2, _waferDiameter / 2);
        }
       
        private bool CellInWafer(Point die_location, Point wafer_location)
        {
        	//判断方块的四个点是否在圆内,如果在,就返回true,否则返回false。
            Point dieLeftTop = die_location;
            Point dieLeftDown = new System.Drawing.Point(die_location.X, die_location.Y + _dieSideLength);
            Point dieRightTop = new System.Drawing.Point(die_location.X + _dieSideLength, die_location.Y);
            Point dieRightDown = new System.Drawing.Point(die_location.X + _dieSideLength, die_location.Y + _dieSideLength);

            if ((float)Math.Sqrt((float)Math.Pow(wafer_location.X - dieLeftTop.X, 2) + (float)Math.Pow(wafer_location.Y - dieLeftTop.Y, 2)) <= _waferDiameter / 2)
            {
                if ((float)Math.Sqrt((float)Math.Pow(wafer_location.X - dieLeftDown.X, 2) + (float)Math.Pow(wafer_location.Y - dieLeftDown.Y, 2)) <= _waferDiameter / 2)
                {
                    if ((float)Math.Sqrt((float)Math.Pow(wafer_location.X - dieRightTop.X, 2) + (float)Math.Pow(wafer_location.Y - dieRightTop.Y, 2)) <= _waferDiameter / 2)
                    {
                        if ((float)Math.Sqrt((float)Math.Pow(wafer_location.X - dieRightDown.X, 2) + (float)Math.Pow(wafer_location.Y - dieRightDown.Y, 2)) <= _waferDiameter / 2)
                            return true;
                    }
                }
            }

            return false;
        }
        private void ScanViewer_Paint(object sender, PaintEventArgs e)
        {
            if (_waferDiameter <= 0 || _dieSideLength <= 0)
            {
                return;
            }
            cells.Clear();
            Init();
            Graphics gra = e.Graphics;
         
            Pen p = new Pen(Color.Black, 2);
            gra.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            gra.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
            //图像放大缩小
            gra.ScaleTransform((float) _mul, (float)_mul);
            gra.DrawEllipse(p, _startLocation.X, _startLocation.Y, _waferDiameter, _waferDiameter);

            int i = _startLocation.X;
            for (int j = _startLocation.Y; j < _startLocation.Y + _waferDiameter;)
            {
                Point die_PoingStart = new Point(i, j);
                //判断方块是否在圆里,如果不在就不显示。
                if (CellInWafer(die_PoingStart, _ellipseCenter))
                {
                    Rectangle rectangle = new Rectangle(die_PoingStart.X, die_PoingStart.Y, _dieSideLength, _dieSideLength);
                    Cell c = new Cell(rectangle);
                    c.Selected = isSelect;
                    cells.Add(c);
                    c.Draw(gra);

                }
                i = i + _dieSideLength;

                if (!(i < _startLocation.X + _waferDiameter))
                {
                    i = _startLocation.X;
                    j = j + _dieSideLength;
                }
            }
            //扫描当前die
            if (!(_currentIdx < 0) )
            {
                StartScan(gra);
            }
            //因为图像重绘时会覆盖前面已扫描的die,所以需要把前面覆盖的部分再覆盖回去。
            if (_currentIdx != 0)
            {
                SzieChangDraw(gra);
            }
        }
        public void StartScan(Graphics gra)
        {
            if (_currentIdx >= cells.Count)
            {
                return;
            }
            Cell cell = cells[_currentIdx];
            cell.BackColor = Color.Green;
            cell.Selected = true;
            cell.Draw(gra);
        }
        public void SzieChangDraw(Graphics gra)
        {
            for (int i = 0; i < _currentIdx; i++)
            {
                Cell cell = cells[i];
                cell.BackColor = Color.Green;
                cell.Selected = true;
                cell.Draw(gra);
            }
        }
    }
}

最后是SizeableScanViewer 容器控件

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using System.IO;

namespace ISIE.COMMON
{
    public partial class SizeableScanViewer : UserControl
    {
        Color backColor;
        private int _waferDiameter = 1;//wafer直径
        private int _dieSideLength = 1;//die的边长
        private int _interval = 1000;//默认扫描间隔1000ms
        private int cellCount = 0;//die的数量
        private int currentIdx = 0;//当前扫描die的下标
        System.Windows.Forms.Timer timer1;
        public override Color BackColor
        {
            get 
            { 
                return backColor; 
            }
            set 
            { 
                backColor = value;
            }
        }
      
        public SizeableScanViewer()
        {
            InitializeComponent();
            timer1 = new System.Windows.Forms.Timer();
            timer1.Tick += timer_Tick;
            this.BackColor = this.scannerViewer1.BackColor;
        }
        void adapt()
        {
            GetXmlParameter();
            this.timer1.Interval = _interval;
            int Maxlen = Math.Min(this.Width, this.Height);
            int x = 0, y = 0;
            double mul = Math.Floor((double)(Maxlen * 1f / _waferDiameter) * 10) / 10 - 0.1;
         
            x = (this.Width - Maxlen) / 2;
            y = (this.Height - Maxlen) / 2;
            this.scannerViewer1.Location = new Point(x, y);
            this.scannerViewer1.WaferDiameter = _waferDiameter;
            this.scannerViewer1.DieSideLength = _dieSideLength;            
            this.scannerViewer1.Mul = mul;
            this.scannerViewer1.Size = new Size((int)(_waferDiameter * mul), (int)(_waferDiameter * mul));
        }
        public void timer_Tick(object sender, EventArgs e)
        {
            if (currentIdx >= cellCount)
            {
                this.timer1.Enabled = false;
                return;
            }
            this.scannerViewer1.CurrentIdx = currentIdx;
            this.scannerViewer1.Invalidate();
            currentIdx++;

        }
        private void SizeableScanViewer_SizeChanged(object sender, EventArgs e)
        {
            if (this.Width <= 50 || this.Height <= 50)
                return;
            
            adapt();
            this.scannerViewer1.Invalidate();
           
        }
        public void startScan()
        {
            cellCount = this.scannerViewer1.CellCount;
            this.timer1.Enabled = true;

        }
        public void stopScan()
        {
            this.timer1.Enabled = false;
        }       
        //读取XML文件,获取wafer,die的信息和扫描速度
        private void GetXmlParameter()
        {
            XmlDocument doc = new XmlDocument();
            string path = System.IO.Directory.GetCurrentDirectory();
            if (File.Exists(@path + @"\MachineConfig.xml"))
            {
                doc.Load(@path + @"\MachineConfig.xml");
                XmlNode xn = doc.SelectSingleNode("Machine");
                XmlNodeList xnl = xn.ChildNodes;
                foreach (XmlNode xn1 in xnl)
                {
                    string Nodename = xn1.Name;
                    if ("WaferSize".Equals(Nodename))
                    {
                        foreach (XmlNode item in xn1)
                        {
                            XmlElement xe = (XmlElement)item;
                            switch (xe.Name)
                            {
                                case "WaferXsize":
                                    _waferDiameter = int.Parse(xe.InnerXml);
                                    break;
                                case "DieXsize":
                                    _dieSideLength = int.Parse(xe.InnerXml);
                                    break;
                                case "Speed":
                                    double speed = double.Parse(xe.InnerXml);
                                    _interval = (int)(_dieSideLength * 1000 / speed);
                                    break;
                            }
                        }
                        break;
                    }
                }
            }
                
           
        }

    }
}

最后最后在界面上实例化和调用SizeableScanViewer 的startScan()和stopScan()就可以了。
当然,代码比较粗糙。因为一直在测试,很多无用的代码也没有删掉,(⊙o⊙)…。先这样吧,
欢迎大家留言讨论。

上一篇:15.生成数据


下一篇:用python-plotly模拟掷骰子类的随机过程