4. WaferLine 예광탄 – 4.4 라이브러리로 만들기 [Wafer 코팅 시뮬레이션]

안녕하세요. 언제나휴일입니다.

이번 실습은 WaferLine 예광탄에서 정의한 WaferLine 클래스와 시각화하는 부분을 라이브러리로 만드는 실습입니다.

1. WaferLine 클래스 만들기

Wafer관련 라이브러리

WaferLineLib 프로젝트에 WaferLine 이름으로 클래스를 추가합니다.

WaferLine.cs 소스 코드는 WaferLine 예광탄에서 작성했던 것을 그대로 사용합니다.

using System;
using System.Collections;
using System.Collections.Generic;

namespace WaferLineLib
{
    public class WaferLine : IEnumerable<Wafer>
    {
        public int No { get; }
        public int Spin
        {
            get;
            set;
        }
        public int Drop
        {
            get;
            set;
        }
        public WaferLine(int no)
        {
            No = no;
            Spin = 1000;
            Drop = 20;
        }
        List<Wafer> bwafers = new List<Wafer>();
        List<Wafer> awafers = new List<Wafer>();
        public Wafer LastWafer
        {
            get
            {
                if (awafers.Count == 0)
                {
                    return null;
                }
                return awafers[awafers.Count - 1];
            }
        }
        public void EndCoating(int bwcnt, int awcnt)
        {
            while (bwafers.Count > bwcnt)
            {
                bwafers.RemoveAt(0);
            }
            while (awafers.Count < awcnt)
            {
                awafers.Add(null);
            }
        }
        Wafer nwafer;
        int nowp;//1병은 1000쉘을 코팅할 수 있다.
        public Wafer Now { get { return nwafer; } }
        public int BWCnt
        {
            get { return bwafers.Count; }
        }
        public int InWafer(int wcnt)
        {
            int avail = 200 - BWCnt;
            if (wcnt > avail)
            {
                wcnt = avail;
            }
            for (int i = 0; i < wcnt; i++)
            {
                bwafers.Add(new Wafer());
            }
            return bwafers.Count;
        }
        public int AWCnt
        {
            get { return awafers.Count; }
        }
        public int PCnt { get; set; }
        public int NPcnt { get { return nowp; } }
        public int InPr(int pcnt)
        {
            int avail = 20 - PCnt;
            if (pcnt > avail)
            {
                pcnt = avail;
            }
            PCnt += pcnt;
            return PCnt;
        }
        public void SetSpin(int spin)
        {
            Spin = spin;
        }
        public void SetDrop(int drop)
        {
            Drop = drop;
        }
        Random rand = new Random();
        public bool Coating()
        {
            if (nowp == 0)
            {
                if (PCnt == 0)
                {
                    return false;
                }
                nowp = 1000;
                PCnt--;
            }
            if (nwafer == null)
            {
                if (bwafers.Count == 0)
                {
                    return false;
                }
                nwafer = bwafers[0];
                bwafers.RemoveAt(0);
            }
            nwafer.Coating(rand.Next(70, 100));
            nowp--;
            if (nwafer.Increment() == false)
            {
                awafers.Add(nwafer);
                nwafer = null;
            }
            return true;
        }
        public override string ToString()
        {
            return string.Format("WaferLine No:{0}", No);
        }

        public IEnumerator<Wafer> GetEnumerator()
        {
            return awafers.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return awafers.GetEnumerator();
        }
    }
}

2. WaferLineControl 만들기

WaferLineControlLib에 있었던 UserControl1.cs를 WaferLineControl.cs로 이름을 변경하세요.

그리고 WaferLine 예광탄에 배치했던 컨트롤을 복사해서 WaferLineControl에 붙여넣기 합니다.

WaferLine 예광탄에서 했던 것처럼 네 개의 TrackBar의 Scroll 이벤트 핸들러 및 세 개의 버튼 클릭 이벤트 핸들러, 세 개의 패널의 Paint 이벤트 핸들러 및 ComboBox의 선택 항목 변경 이벤트 핸들러를 추가합니다.

그리고 WaferLine 예광탄의 Form1.cs에서 소스 코드를 복사해서 붙여넣기 합니다.

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using WaferLineLib;

namespace WaferLineControlLib
{
    public partial class WaferLineControl : UserControl
    {
        WaferLine wl = null;
        public WaferLine Line
        {
            get
            {
                return wl;
            }
            set
            {
                wl = value;
            }
        }
        public WaferLineControl()
        {
            InitializeComponent();
        }


        private void tbar_wafer_Scroll(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            lb_wafer.Text = tbar_wafer.Value.ToString();
        }

        private void tbar_pr_Scroll(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            lb_pr.Text = tbar_pr.Value.ToString();

        }

        private void btn_wafer_Click(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            int bwcnt = tbar_wafer.Value;
            if (bwcnt > (tbar_wafer.Maximum - wl.BWCnt))
            {
                bwcnt = tbar_wafer.Maximum - wl.BWCnt;
            }
            wl.InWafer(bwcnt);
            tbar_wafer.Value = 0;
            lb_wafer.Text = "0";
            pn_wafer.Invalidate();
            ts_lb.Text = string.Format("Wafer {0}개 투입, 현재:{1}개", bwcnt, wl.BWCnt);
            lb_wcnt.Text = wl.BWCnt.ToString();
        }

        private void btn_pr_Click(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            int pcnt = tbar_pr.Value;
            if (pcnt > (tbar_pr.Maximum - wl.PCnt))
            {
                pcnt = tbar_pr.Maximum - wl.PCnt;
            }
            wl.InPr(pcnt);
            tbar_pr.Value = 0;
            lb_pr.Text = "0";
            pn_pr.Invalidate();
            ts_lb.Text = string.Format("코팅액 {0}병 투입, 현재:{1}병", pcnt, wl.PCnt);
            lb_pcnt.Text = wl.PCnt.ToString();
        }

        private void tbar_spin_Scroll(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            lb_spin.Text = tbar_spin.Value.ToString();
            wl.SetSpin(tbar_spin.Value);
            ChangeInterval();
        }

        private void ChangeInterval()
        {
            if (wl == null) { return; }
            tm_coating.Interval = 6000000 / (wl.Spin * wl.Drop);
        }

        private void tbar_drop_Scroll(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            lb_drop.Text = tbar_drop.Value.ToString();
            wl.SetDrop(tbar_drop.Value);
            ChangeInterval();
        }

        private void btn_start_Click(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            if (tm_coating.Enabled)
            {
                tm_coating.Enabled = false;
                btn_start.Text = "시작";
            }
            else
            {
                tm_coating.Enabled = true;
                btn_start.Text = "멈춤";
            }
        }

        private void cb_awafer_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            pn_awafer.Wafer = wl.LastWafer;
            pn_awafer.Invalidate();
        }

        private void tm_coating_Tick(object sender, EventArgs e)
        {
            if (wl == null) { return; }
            if (wl.Coating() == false)
            {
                tm_coating.Enabled = false;
                btn_start.Text = "시작";
            }
            Wafer wafer = wl.Now;
            pn_nwafer.Wafer = wafer;
            if (wafer != null)
            {
                int ccount = wafer.Now;
                if (ccount == 1)
                {
                    Wafer lwafer = wl.LastWafer;
                    if (lwafer != null)
                    {
                        cb_awafer.Items.Add(lwafer);
                        lb_awcnt.Text = wl.AWCnt.ToString();
                        ts_lb.Text = string.Format("코팅 완료:{0}", lwafer);
                    }
                    lb_wcnt.Text = wl.BWCnt.ToString();
                }
            }
            if (wl.NPcnt == 999)
            {
                lb_pcnt.Text = wl.PCnt.ToString();
                ts_lb.Text = string.Format("코팅액 교체: 남은 코팅액:{0}병", wl.PCnt);
            }
            Invalidate(true);
        }

        private void pn_wafer_Paint(object sender, PaintEventArgs e)
        {
            if (wl == null) { return; }
            Graphics graphics = e.Graphics;
            Pen pen = new Pen(Color.DarkGray, 1);
            pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            int xu = pn_wafer.Width / 10;
            int yu = pn_wafer.Height / 20;
            int wcnt = wl.BWCnt;
            for (int x = 1; x < 10; x++)
            {
                graphics.DrawLine(pen, new Point(x * xu, 0), new Point(x * xu, pn_wafer.Height));
            }
            for (int y = 1; y < 20; y++)
            {
                graphics.DrawLine(pen, new Point(0, y * yu), new Point(pn_wafer.Width, y * yu));
            }
            for (int i = 0, ri = 200; i < 200; i++, ri--)
            {
                Brush brush;
                if (ri <= wcnt)
                {
                    brush = new HatchBrush(HatchStyle.DiagonalCross, Color.Goldenrod);
                }
                else
                {
                    brush = new SolidBrush(pn_wafer.BackColor);
                }
                int x = i % 10;
                int y = i / 10;
                graphics.FillRectangle(brush, new Rectangle(x * xu + 1, y * yu + 1, xu - 1, yu - 1));
            }
        }

        private void pn_pr_Paint(object sender, PaintEventArgs e)
        {
            if (wl == null) { return; }
            Graphics graphics = e.Graphics;
            Pen pen = new Pen(Color.DarkGray, 1);
            pen.DashStyle = DashStyle.Dot;
            int yu = pn_pr.Height / 20;
            for (int y = 1; y < 20; y++)
            {
                graphics.DrawLine(pen, new Point(0, y * yu), new Point(pn_pr.Width, y * yu));
            }
            int pcnt = wl.PCnt;
            for (int i = 0, ri = 20; i < 20; i++, ri--)
            {
                Color color = pn_pr.BackColor;
                if (ri <= pcnt)
                {
                    color = Color.DarkCyan;
                }
                Brush brush = new SolidBrush(color);
                graphics.FillRectangle(brush, new Rectangle(0, i * yu + 1, pn_pr.Width, yu - 1));
            }
        }

        private void pn_npr_Paint(object sender, PaintEventArgs e)
        {
            if (wl == null) { return; }
            Graphics graphics = e.Graphics;
            int npcnt = wl.NPcnt;
            for (int x = 0; x < 50; x++)
            {
                for (int y = 0; y < 20; y++)
                {
                    if (npcnt < (1000 - y * 50 + x))
                    {
                        graphics.DrawLine(Pens.White, new Point(x, y), new Point(x + 1, y));
                    }
                    else
                    {
                        graphics.DrawLine(Pens.DarkCyan, new Point(x, y), new Point(x + 1, y));
                    }
                }
            }
        }
    }
}

3. 테스트

정상적으로 만든 것인지 확인하려면 WaferLine 예광탄에 정의한 WaferLine.cs 파일을 먼저 삭제합니다.

그리고 WaferLine 예광탄에 컨트롤 배치한 것도 모두 제거합니다.

대신 WaferLineControl을 하나 배치합니다.

그리고 Form1의 Load 이벤트 핸들러를 추가한 후에 다음처럼 소스 코드를 변경하여 테스트합니다.

using System;
using System.Windows.Forms;
using WaferLineLib;

namespace WaferLine_예광탄
{
    public partial class Form1 : Form
    {        
        public Form1()
        {
            InitializeComponent();            
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            waferLineControl1.Line = new WaferLine(1);
        }
    }
}