Study - Programming/C#2008. 11. 16. 14:46

※이 글은 본인의 지극히 얄팍한 지식과 경험을 통해서 생각한 주관적인 글입니다. 이 포스팅의 기술적인 내용은 본인의 지식에서 나온 것이라 실제와 다를 가능성도 있습니다. 이에 대한 수정과 비판은 환영이나 비난은 자제해 주시면 감사하겠습니다.


  내가 처음 프로그래밍이란 것을 접한건 초등학교 3학년때 Visual Basic 5.0을 통해서였다. 일반적으로 프로그래밍을 배울 때는 C같은 언어를 통해서 변수,루프,함수 같은 기본 문법을 배우고 거기서 세세한 사항 및 기술 등을 배우고 다른 언어로 넘어가던지 윈도우 프로그래밍 같은걸 배우던지 할텐데, 난 바로 윈도우 프로그래밍부터 시작하다 보니 기본적인 문법 같은것도 대충 대충배우고 그랬었다.(C를 조금 하긴 했었지만 그때도 포인터나 구조체같은건 신경도 안썼다. 결정적으로 그런 개념들에 대한 중요성을 인식하지 못했었다. 독학이다 보니.) 실제로 함수 등의 문법 사항을 이해하기 시작한건 본격적으로 C를 공부하기 시작한 대학 1학년때 미친듯이 프로그래밍 공부 할 때였다.
  아무튼 이런식으로 약간 역순(말은 이렇지만 역순이라고는 생각하지 않는다. 대세가 위의 방식이지 내 방식이 정석이 아니다 뭐다 그런건 없다는 것이 본인의 생각이다.)으로 배우다 보니 편리한 RAD방식에서 딱딱한 콘솔 기반의 프로그래밍 그리고 거기서 윈도우 프로그래밍으로 넘어갈 때는 정말 힘들었었다. 그리고 좀더 편리한 방식이 없나 종종 생각하기도 했다. VB의 편리함은 충분히 좋은 장점이지만 그에 비해 언어적 약점이 많이 아쉬웠다. 그리고 C나 C++, JAVA같은 언어는 강력한 언어적 지원과 갈수록 좋은 개발환경을 제공해 주었지만 역시 VB의 편리함과 비교해서는 아쉬운 점이 많았다.
  그러다 접한 것이 C#이다. C#은 위 두가지의 장단점을 잘 조합한 좋은 언어라고 생각한다. 엄청나게 강력한 언어적 기능 그리고 윈폼을 활용한 강력한 개발 환경. 분명 기존 언어들과 비교해서 한발자국 나가긴 나간 언어이다. 예전에 RAD툴 관련 글들을 보면서 현재는 VB 등의 RAD툴이 강력한 생산성에도 불구하고 부실한 언어적 기능 때문에 빛을 못받고 있지만 갈수록 RAD툴은 대세가 될 것이라는 글을 많이 봤다. C#은 이 말이 실현되고 있음을 보여 주는 한가지 예라고 할 수 있다. 
  그러나 이 C#도 치명적인 약점이 있다. 바로 .NET Framework라는 것. 조그마한 프로그램을 만들었는데도 20MB 가까이 되는 .NET Framework 을 설치해야 한다는 것과 이것이 현재 닷넷의 큰 약점 중의 하나라는 것은 잘 알려진 사실이다.  .NET Framework위에서 돌아가는 방식은 분명 장점도 있겠지만 현재는 이 배보다 배꼽이 큰 문제가 심각할 수밖에 없다. Windows XP가 보급되기 전에 이 .NET Framework가 좀더 기반을 다지고 Windows XP에 .NET Framework가 함께 나왔다면 어떻게 되었을지 모르겠지만 현재로서는 아무리 Windows Vista에 이것을 넣고 Windows Update에 추가하고 하더라도 충분히 보급되기까지는 상당한 시간이 걸릴 것이다.
  그리고 Microsoft에서 만들다 보니 강력한 기능에도 불구하고 .NET Framework가 Windows기반에서만 돌아갈 수 있는 불상사(?)가 발생하여 JAVA와 비교해 아직은 부족하다.(Mono가 있지만 이것이 완전한 .NET Framwork라고 할 수 있을까?)
  이런 C#의 약점을 가지고 있지 않은 다른 언어는 없을까? 최근에 2009버전이 나온 Delphi가 있겠다. 어떠한 프레임워크 위에서 돌아가지 않으면서도 엄청나게 편리한 개발 환경과 최근 2009버전에서도 나타나는 강력한 언어적 기능 그리고 C,C++같은 어느 특정한 곳에서 독점하지 않는 것이 아니라 한 기업에서 독자적으로 밀고 있는 방식이라 그 발전 가능성과 발전 속도도 상당히 높다고 할 수 있다. 그러나 이 Delphi도 왠지 모를 비인기(상대적인 이야기이다.)와 처음 접하는 개발자는 좀 거북할 수 있는 문법 그리고 Windows개발쪽에서만 나타나는 강력함에서 완전하다고는 이야기 할 수 없다.
  아직까지는 RAD툴이 개발 방식의 대세라고는 이야기 할 수 없겠다. 그러나 언젠가는 이런 방식이 주류가 될 것이라고 난 믿는다. 완전하지는 않지만 분명 변화는 일고 있다. 강력한 언어 위의 강력한 개발 환경. 그런 변화가 언제쯤이면 일어날까 기대하며 이 글을 마친다.
Posted by 머리
Study - Programming/C#2007. 12. 25. 22:31

검색할 파일과 경로를 입력받아서 하위디렉토리까지 포함해서 경로를 검색하는 프로그램이다.

책에 있던 파일 찾기 예제를 조금 수정했다. 원래 예제는 하위 디렉토리는 검색하지 못해서 재귀를 이용해서 만들어 보았다.

사용자 삽입 이미지

다음은 가장 핵심인 FindFile() 메서드이다. 파라미터의 str은 찾을 파일(또는 형식)이고 dir은 경로이다.

        void FindFile(string str,string dir)
        {
            string tdir = dir.Trim();

            if (dir == "")
            {
                MessageBox.Show("검색할 디렉토리를 입력하세요");
                return;
            }

            string[] files_list;
            try
            {
                DirectoryInfo dinfo = new DirectoryInfo(tdir);
                DirectoryInfo[] subdir = dinfo.GetDirectories();


                files_list = Directory.GetFiles(tdir, str);

                for (int i = 0; i < files_list.Length; i++)
                {
                    ListViewItem item1 = new ListViewItem(files_list[i], 0);

                    FileInfo finfo = new FileInfo(files_list[i]);

                    item1.SubItems.Add(finfo.Length.ToString() + "Byte");
                    item1.SubItems.Add(finfo.CreationTime.ToString());

                    lst_View.Items.Add(item1);
                }

                foreach (DirectoryInfo d in subdir)
                {
                    tdir = d.FullName;
                    if((d.Attributes & FileAttributes.System) <= 0)
                    {
                        FindFile(str,tdir);

                        files_list = Directory.GetFiles(tdir, str);

                        for (int i = 0; i < files_list.Length; i++)
                        {
                            ListViewItem item1 = new ListViewItem(files_list[i], 0);

                            FileInfo finfo = new FileInfo(files_list[i]);

                            item1.SubItems.Add(finfo.Length.ToString() + "Byte");
                            item1.SubItems.Add(finfo.CreationTime.ToString());

                            lst_View.Items.Add(item1);
                        }
                    }

                }


            }
            catch(Exception e)
            {
               
                Console.WriteLine("파일 검색 중 예외 발생");
                Console.WriteLine(e.Message);
                Console.WriteLine(e.ToString());
                Console.WriteLine(tdir);
            }
        }

처음에 자꾸 예외가 발생해서 애를 많이 먹었다. 보니 System Volume Information부분에 권한도 없이 자꾸 접근해서 프로그램이 꺼지는 것이다. 그래서 데브피아에 알아봐서

if((d.Attributes & FileAttributes.System) <= 0)

이렇게 해서 System 관련 디렉토리는 접근하지 않게 해 놓았다.

FileSystem 클래스에 이놈도 넣어 놔야지.

Posted by 머리
Study - Programming/C#2007. 12. 25. 13:06

다음주에 작은아버지께 드릴 프로그램을 위해서 만들어 본 클래스이다.

백업 프로그램인데, 모든 파일을 경로와 파일명 그대로 다른 드라이브로 옮겨 주기 위해서 만들어 클래스들

그런데 이거 참 클래스 이름 짓기가 참 난감했다. 이걸 뭐라고 해줘야 하나..
그래서 그냥 어울리지는 않지만 FileSystem이라고 이름지엇다.

class FileSystem
{
    /*CopyAll : 특정 디렉토리의 모든 폴더와 파일을 다른 드라이브로 옮기는 메서드
     * args : 원본의 경로
     * drive : 옮길 드라이브
     */
    public void CopyAll(string args,string drive)
    {
        DirectoryInfo dinfo = new DirectoryInfo(args);
        string dest;
       
        if (dinfo.Exists)
        {
            DirectoryInfo[] dir = dinfo.GetDirectories();
           
            foreach (DirectoryInfo d in dir)
            {
                CopyAll(d.FullName,drive);
            }

            FileInfo []fs = dinfo.GetFiles();

            foreach (FileInfo f in fs)
            {
                dest = f.Directory.FullName;
                dest = dest.Remove(0, 1);
                dest = dest.Insert(0, drive);
                Console.WriteLine("Copy " + f.Name + " to " + dest);
                FileCopy(f.FullName, dest, 0);
            }
        }
    }
    /* MakeDir : 디렉토리를 만드는 메서드
     * dir : 만들 디렉토리의 경로
     */
    public void MakeDir(string dir)
    {
        DirectoryInfo dinfo = new DirectoryInfo(dir);

        if (dinfo.Exists == false)
        {
            dinfo.Create();
        }
    }


    /* FileCopy : 파일을 복사하는 함수
     * src : 복사할 파일의 경로 및 파일 이름
     * dest : 복사할 목적지
     * mode : 파일을 복사할것인지, 이동할것인지 설정
     */

    public void FileCopy(string src,string dest,int mode)
    {
        FileInfo finfo = new FileInfo(src);
        FileInfo fsrc;
        if (finfo.Exists == true)
        {
            MakeDir(dest);
            dest = dest + "\\" + finfo.Name;
            switch (mode)
            {
                case 0:
                      fsrc = finfo.CopyTo(dest, true);
                    break;
                case 1:
                    finfo.MoveTo(dest);
                    break;
            }
        }
    }  
}

Posted by 머리
Study - Programming/C#2007. 12. 22. 03:04

사용자 삽입 이미지

요즘 생각해보고 있는 프로그램중에 문자열 토큰 관련 기능이 필요해서 한번 책 예제를 따라해 봤다. 간단하다 텍스트 박스의 내용 중 #이랑 &을 가지고 토큰을 나눠주는 기능이다.

간단하니 버튼의 이벤트 핸들러만 소스를 올린다.

            string msg = txt_MSG.Text;
            string[] token = msg.Split('#');

            for (int i = 0; i < token.Length; i++)
            {
                if (token[i].IndexOf("&") > 0)
                {
                    txt_Info.AppendText("\r\n" + token[i]);
                    string[] subtoken = token[i].Split('&');
                    for (int j = 0; j < subtoken.Length; j++)
                    {
                        txt_Info.AppendText("\r\n=>" + subtoken[j]);
                    }
                }
                else
                {
                    txt_Info.AppendText("\r\n" + token[i]);
                }
            }

그리고 이것은 텍스트 박스 안의 내용

"S_S_FILE#검색서버IP#파일개수#파일이름&파일사이즈&파일생성일"

토큰으로 나누면 스크린샷과 같은 모습으로 출력된다.

기가막힌건.. C같았으면 토큰 저런거 저장할때 별 짓을 다해야 할텐데 여기서는
 string[] token = msg.Split('#');
이거 하나로 그냥 해결해 버렸다. 보고 기가 막혀서 웃음을 터뜨렸었다. 이렇게 간단하게 해결이 될 줄이야.. 역시 제공되는게 많다.

Posted by 머리
Study - Programming/C#2007. 12. 21. 13:52

처음으로 만들어본 C# 프로그램이다.

뭐 별건 없고 그냥 간단한 사칙 연산이 되는 계산기를 만들어 봤다.

일단 소스


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;


namespace Calculator
{
    class Program : Form
    {
        const int BTNSIZE = 40;
        const int CLRBTN = 10;
        const int ANSBTN = 11;

        const int BLK = 0;
        const int PLUS = 1;
        const int MIN = 2;
        const int MUL = 3;
        const int DIV = 4;

        int result = 0;
        int op = 0;

        bool answered = false;

        Button[] btn = new Button[16];
        Label lbl_display;

        int iButtonSize = 50;

        public Program()
        {
            int i = 0;
            int zero_x = 0;
            int zero_y = 0;
            char []name  = new char[4]{'+','-','*','/'};

            this.Text = "간단한 계산기";

            this.SetBounds(0, 0, BTNSIZE * 4 + 40, BTNSIZE * 5 + 50);
            lbl_display = new Label();
            lbl_display.Text = "0";
            lbl_display.BackColor = Color.White;
            lbl_display.SetBounds(15,10,160,20);


            this.Controls.Add(lbl_display);
            zero_y = 0;

            //'1~9'버튼

            for (i = 1; i <= 9; i++)
            {
                if (i % 3 == 1)
                {
                    zero_x = 15;
                    zero_y += BTNSIZE;
                }
                else
                {
                    zero_x += BTNSIZE;
                }
                    btn[i] = new Button();
                    btn[i].Text = i.ToString();
                    btn[i].SetBounds(zero_x, zero_y, BTNSIZE, BTNSIZE);
                    btn[i].Click += new EventHandler(BtnNumber_OnClick);
                this.Controls.Add(btn[i]);
            }

            //0버튼
            zero_x = 15;
            zero_y += BTNSIZE;
            btn[0] = new Button();
            btn[0].Text = "0";
            btn[0].SetBounds(zero_x, zero_y, BTNSIZE, BTNSIZE);
            btn[0].Click += new EventHandler(BtnNumber_OnClick);
            this.Controls.Add(btn[0]);

            //'Clear'버튼
            zero_x += BTNSIZE;
            btn[CLRBTN] = new Button();
            btn[CLRBTN].Text = "CLR";
            btn[CLRBTN].SetBounds(zero_x, zero_y, BTNSIZE, BTNSIZE);
            btn[CLRBTN].Click += new EventHandler(BtnCLR_OnClick);
            this.Controls.Add(btn[CLRBTN]);

            //'Answer'버튼
            zero_x += BTNSIZE;
            btn[ANSBTN] = new Button();
            btn[ANSBTN].Text = "=";
            btn[ANSBTN].SetBounds(zero_x, zero_y, BTNSIZE, BTNSIZE);
            btn[ANSBTN].Click += new EventHandler(BtnANS_OnClick);
            this.Controls.Add(btn[ANSBTN]);


            //연산자 버튼
            zero_x += BTNSIZE;
            zero_y = 0;
            for (i = 12; i < 16; i++)
            {
                zero_y += BTNSIZE;
                btn[i] = new Button();
                btn[i].Text = name[i - 12].ToString();
                btn[i].SetBounds(zero_x, zero_y, BTNSIZE, BTNSIZE);
                btn[i].Click += new EventHandler(BtnOp_OnClick);
                this.Controls.Add(btn[i]);
            }
           

        }
        private void BtnNumber_OnClick(object sender, EventArgs arg)
        {
            Button obj = (Button)sender;
            if (answered == true)
            {
                lbl_display.Text = "0";
                answered = false;
            }

            if (lbl_display.Text != "0")
            {
                lbl_display.Text += obj.Text;
            }
            else
            {
                lbl_display.Text = obj.Text;
            }

        }

        private void BtnCLR_OnClick(object sender, EventArgs arg)
        {
            result = 0;
            op = BLK;
            lbl_display.Text = "0";
        }

        private void BtnANS_OnClick(object sender, EventArgs arg)
        {
            switch (op)
            {
                case BLK:
                    return;
                    break;
                case PLUS:
                    result += Int32.Parse(lbl_display.Text);
                    break;
                case MIN:
                    result -= Int32.Parse(lbl_display.Text);
                    break;
                case MUL:
                    result *= Int32.Parse(lbl_display.Text);
                    break;
                case DIV:
                    if (result != 0)
                        result /= Int32.Parse(lbl_display.Text);
                    else
                    {
                        lbl_display.Text = "Error!";
                    }
                    break;

            }
            answered = true;
            lbl_display.Text = result.ToString();
        }
        private void BtnOp_OnClick(object sender, EventArgs arg)
        {
            Button obj = (Button)sender;
            switch (obj.Text)
            {
                case "+":
                    op = PLUS;
                    break;
                case "-":
                    op = MIN;
                    break;
                case "*":
                    op = MUL;
                    break;
                case "/":
                    op = DIV;
                    break;
            }
            result = Int32.Parse(lbl_display.Text);
            Console.WriteLine(op);
            lbl_display.Text = "0";
        }
        static void Main(string[] args)
        {
            Application.Run(new Program());
        }
    }
}

사용자 삽입 이미지


생각해 보니까 이벤트 관련 함수 안에 모든 내용을 다 넣어 버렸다. 그리 좋지 않은 방식인데.. 윈도우 프로그래밍쪽만 신경쓰다 보니 계산기의 클래스화도 제대로 신경 못쓰고 그러다보니 어떤 오류가 날지도 제대로 모르겠다. 다음에는 신경써서 만들어 보아야 겠다.

Posted by 머리
Study - Programming/C#2007. 12. 13. 11:26

using System;
using System.Windows.Forms;
using System.Drawing;


class Program : Form
{
    Button btn = null;
    ListBox lstbox = null;
    Image image = null;
    public Program()
    {
        this.Text = "Graphics 개체 얻기";
        btn = new Button();
        btn.Text = "버튼 위에 GDI+ 출력";
        btn.SetBounds(10, 10, 200, 100);
        btn.Click += new EventHandler(btn_Click);
        this.Controls.Add(btn);

        lstbox = new ListBox();
        lstbox.SetBounds(210, 110, 410, 310);
        lstbox.Items.Add("사과");
        lstbox.Items.Add("포도");
        lstbox.Items.Add("수박");
        lstbox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(lstbox_DrawItem);
        lstbox.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(lstbox_MeasureItem);

        this.Load += new EventHandler(On_Load);
        this.Controls.Add(lstbox);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics grfx = e.Graphics;
        if (image != null)
            grfx.DrawImage(image, 0, 0);
    }

    static void Main(string[] args)
    {
        Application.Run(new Program());
    }

    public void btn_Click(object sender, EventArgs e)
    {
        Graphics grfx = btn.CreateGraphics();
        grfx.FillRectangle(new SolidBrush(Color.Blue), btn.ClientRectangle);
        grfx.Dispose();

        Image imageFile = Image.FromFile("C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\그림 샘플\\겨울.jpg");
        grfx =  Graphics.FromImage(imageFile);

        Font font = new Font("돋음",20);
        Brush brush = Brushes.Pink;

        grfx.DrawString("이미지에 글자 쓰기", font, brush, 10, 10);
        grfx.Dispose();

        imageFile.Save("sample.gif");
        this.image = Image.FromFile("sample.gif");
        this.Invalidate(this.ClientRectangle);
  
    }

    private void On_Load(object sender, EventArgs e)
    {
        lstbox.DrawMode = DrawMode.OwnerDrawFixed;
    }

    private void lstbox_MeasureItem(object sender, MeasureItemEventArgs e)
    {
        Graphics g = e.Graphics;
        Console.WriteLine("{0} : MeasureItem 이벤트 실행", e.ToString());
    }

    private void lstbox_DrawItem(object sender, DrawItemEventArgs e)
    {
        Graphics g = e.Graphics;
        Brush brush = Brushes.Black;

        switch(e.Index)
        {
            case 0:
                brush = Brushes.Red;
                break;
            case 1:
                brush = Brushes.Violet;
                break;
                case 2:
                brush = Brushes.Green;
                break;
        }

        g.DrawString(lstbox.Items[e.Index].ToString(), e.Font, brush, e.Bounds, StringFormat.GenericDefault);

        Console.WriteLine("{0} : DrawItem 이벤트 실행", e.ToString());
    }
}

소스가 좀 많다. 이외에도 몇가지가 있는데, 한 소스에 담기가 좀 번거로워서 한번에 담을 수 있는것만 해 놓았다.

주석이 없어서 소스 분석이 좀 어렵겠다. 주석 습관 들여야 하는데..

사용한 방법은 다음과 같다.

1. Control Class의 CreateGraphics메서드 이용
2. ListBox 등의 컨트롤에서 제공하는 MeasureItem이나 DrawItem 이벤트 등을 이용한 방법
3. Graphics.FromImage() 메서드 이용
4. OnPaint()메서드 override 해서 사용


이외에도 Paint이벤트 상속받기, PrintPage이벤트 핸들러,Win33API 사용하기 등의 방법이 있다.

Posted by 머리
Study - Programming/C#2007. 11. 26. 01:10

using System;
using System.Windows.Forms;

class Program : Form
{
    public Program(string strText)
    {
        this.Text = strText;
        this.Load += new System.EventHandler(this.Form_Load);
        this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Form_Closed);
        this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Form_Click);
        this.MouseEnter += new System.EventHandler(this.Form_MouseEnter);
        this.Show();
    }

    public static void Main(string[] args)
    {
        Application.Run(new Program("이벤트!"));
    }

    private void Form_Load(object sender, System.EventArgs e)
    {
        Console.WriteLine("윈도우가 Load됩니다.");
    }
    private void Form_Closed(object sender, System.EventArgs e)
    {
        Console.WriteLine("윈도우가 Closed됩니다.");
    }

    private void Form_Click(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        Console.WriteLine(e.Button);
    }

    private void Form_MouseEnter(object sender, System.EventArgs e)
    {
        Console.WriteLine("Mouse Entered!!");
    }

   
}

  실제 실행 결과는 여기서 이벤트가 발생하면 콘솔에 그에 대한 내용이 출력된다. 대표적으로 Load와 Closed이벤트가 있겠다. MouseEnter은 마우스가 폼에 진입했을때 발생하는 이벤트인데, 상당히 흥미로운 이벤트였다. 직접 구현했으면 복잡했을 것을 이렇게 간단히 지원해주니 좋을 따름.
 
  Click이벤트를 보면 두번째 인자가 좀 다른것을 볼 수 있다. System.Windows.Forms.MouseEventArgs인자의 Button속성은 누른 마우스 버튼이 무엇인지를 알려 준다.

  각 이벤트마다 등록해줘야 할 이벤트 등록 클래스가 각각 다르다. 그러므로 중요한것은 따로 암기해 두고, 필요할때는 MSDN 등을 통해 검색해 보고 사용해야 할 것이다. 예를 들면 Load와 FormClosed이벤트의 등록 클래스의 형태는 다르다.

  이벤트의 등록 방법은 다음과 같다.

[이벤트 이름] +- new System.EventHandler(메서드);

  이벤트의 제거는 -=를 이용해 주면 되고, 메서드는 알아서 만들어서 넣어 주면 되지만 그 형태는 다음과 같다.

private void 메서드이름(object sender,System.EventArgs e){}

물론 EventArgs는 MouseClick이벤트를 보듯이 다를 수도 있지만 대개 저런 형태이다.

sender를 다룰때는 어떤 특정한 컨트롤일 경우에는 그 컨트롤로 캐스팅을 시켜주는 경우가 많다. 예를 들어 앞 글에서 버튼을 다룰때 이런식의 코드가 있었다.

(button)sender

이렇게 object를 button으로 캐스팅을 하고 사용해 줘야 한다.

Posted by 머리
Study - Programming/C#2007. 11. 26. 01:00

사용자 삽입 이미지


using System;
using System.Windows.Forms;

class MyClass : Form
{
    Button[] btn = new Button[4];
    Form[] newMDICHild = new Form[10];
    string[] strData = { "수평", "수직", "계단식", "아이콘" };

    public MyClass(string strText)
    {
        this.Text = strText;
        this.IsMdiContainer = true;
        this.Load += new EventHandler(this.Form_Load);
        this.Closed += new EventHandler(this.Form_Closed);

        for (int i = 0; i < 4; i++)
        {
            btn[i] = new Button();
            btn[i].Text = strData[i];
            btn[i].SetBounds(50 * i, 10, 50, 50);
            btn[i].Click += new EventHandler(this.Btn_Click);
            this.Controls.Add(btn[i]);
        }

        this.Show();
    }

    public static void Main(string[] args)
    {
        Application.Run(new MyClass("MDI"));
    }

    private void Form_Load(object sender, System.EventArgs e)
    {
        Console.WriteLine("윈도우에 자식창을 생성");
        Form[] newMDIChild = new Form[10];
        for(int i = 0 ;i < 10 ; i++)
        {
            newMDIChild[i] = new Form();
            newMDIChild[i].Text = i + "번째 자식창";
            newMDIChild[i].MdiParent=this;
            newMDIChild[i].Closed += new System.EventHandler(this.Form_Closed);

            newMDIChild[i].Show();
        }
    }
    private void Form_Closed(object sender, System.EventArgs e)
    {
        Console.WriteLine(((Form)sender).Text + "윈도우가 Closed됩니다.");
    }

    private void Btn_Click(object sender, System.EventArgs e)
    {
        if ((Button)sender == btn[0])
        {
            this.LayoutMdi(MdiLayout.TileHorizontal);
            this.Text = "수평 바둑판 정렬";
        }
        else if ((Button)sender == btn[1])
        {
            this.LayoutMdi(MdiLayout.TileVertical);
            this.Text = "수직 바둑판 정렬";
        }
        else if ((Button)sender == btn[2])
        {
            this.LayoutMdi(MdiLayout.Cascade);
            this.Text = "계단식 정렬";
        }
        else if ((Button)sender == btn[3])
        {
            this.LayoutMdi(MdiLayout.ArrangeIcons);
            this.Text = "아이콘 정렬";
        }
    }
}

  후.. 요즘 윈도우 프로그래밍에 맛들여서.. 이런거 공부해 보는게 마냥 재미있네. 어쨋든 슬럼프였는데 갈길을 찾아서 다행이다. 시험 기간 제대로 돌입하기전에는 열심히 해봐야지.

  C#문법을 조금만 아는 사람이라면 금방 파악할 수 있을 것이다. 그만큼 쉽고 편리하게 구현하는게 가능하다. 실제 윈폼 구현은 다 IDE를 이용해서 하지만 콘솔로도 이렇게 간단하게 할 수가 있다. 특히 이벤트 구현을 저렇게 쉽게 해줄 수 있다니.. MFC/API를 사용할때와 비교해서 이렇게 차이가 난다. VB를 해보았다면 그때의 기억을 살리면서 신나게 해볼 수 있을 것이다. 아 앞으로 배울 것들이 엄청 기대된다.

Posted by 머리
Study - Programming/C#2007. 9. 23. 22:18

다음 그림을 한번 보자.

사용자 삽입 이미지

위 그림의 코드를 보면 Chile 클래스는 Parent 클래스를 상속받아 있다. 그리고 Child는 Parent의 Show() 메서드를 오버라이드 했고, 추가로 Func()라는 메소드를 가지고 있다.

그럼 이젠 Main() 함수를 보자. 처음에는 Parent 형으로 obj라는 객체를 만들고 Parent 인스턴스를 만들어 참조했다.  물론 이 상태에서 Show를 하면 Parent의 Show()가 실행된다.
그럼 다음 줄로 넘어가 obj를 Child인스턴스에 참조시켜 보자. 물론 Show()메서드는 Child의 Show()가 실행된다. 그런데 그 다음줄로 넘어가 Func()를 실행시키려 시도해 보자. 일단 위 그림에서 자동완성의 목록에는 Func()가 없다. 그냥 무시하고 Func()를 타이핑해서 빌드 해 보자.
사용자 삽입 이미지
  위 그림을 보면 오류가 나온다. 간단히 테스트의 목적으로 만든 코드인데 한번 자세히 알아보자.

  우선 obj라는 객체는 Parent형으로 되어 있다. 즉 Parent의 틀을 가지고 있다는 것이다. 그러므로 obj = new Parent();로 해 놓으면 당연히 Parent의 모든 메서드를 사용하는 것이 가능하다.
  그러나 obj = new Child();로 해 놓으면 어떨까? obj의 '틀'은 Parent이다. 그런데 참조한 인스턴스는 Child이다. Child는 어떻게 되어 있는가? Parent를 상속받아 놓고 거기다 Show()를 오버라이드 한 다음 Child만의 Func()를 포함하고 있다. 즉 Parent라는 '틀'은 Child가 상속받고 있는 Parent관련 멤버들 및 오버라이드 함수만 레퍼런스 할 수 있고, Child만의 멤버인 Func는 사용할 수 없다는 이야기이다.
  솔직히 이게 무엇을 의미하는지 결론적으로는 잘 모르겠다. 다만 이런 식의 코드를 많이 보아 왔었는데 이게 어떻게 성립하는지 이해가 안되었다가 이해를 할 수 있게 되었다.
  폴리모피즘은 OOP에서도 어려운 개념이라고 들었다. 나도 다른 개념은 충분히 사용해 보면서 할 수 있겠는데 이 부분은 영 난해해서 힘들다. 공부를 더 해봐야 겠다.
Posted by 머리
Study - Programming/C#2007. 8. 29. 01:30

using System;
using System.Threading;

public class ThreadExam1
{
    public static void Print1()
    {
        Console.WriteLine("첫 번째 Thread **");
    }

    public void Print2()
    {
        Console.WriteLine("두 번째 Thread **");
    }

    public static void Main()
    {
        Thread thread = new Thread(new ThreadStart(Print1));
        thread.Start();
        thread = new Thread(new ThreadStart((new ThreadExam1()).Print2));
        thread.Start();

        Console.WriteLine("세 번째 Thread");
    }
}


솔직히 말해 모르겠다 이거 뭐하는건지.. 스레드의 정의 자체는 알겠는데 이게 어떤 의미인지를 잘 모르겠다;; 일단 델리게이트 부분부터 다시 봐서 이 코드가 어떻게 돌아가는지부터 다시 공부해 봐야지..

Posted by 머리