프로그래밍 기술/Windows Form 응용 프로그램

4. 4 폼 구현 [Windows Forms 응용 프로그램]

언제나휴일 2016. 4. 6. 13:09
반응형

4. 4 폼 구현

 

 이제 사용자와 상호작용하는 폼을 구현합시다.

 

4.4.1 RegForm

 

 프로젝트에 RegForm을 추가하고 자식 컨트롤을 배치합니다.

 

 정보를 표시하는 Label 컨트롤을 제외하고 9개의 컨트롤을 배치합니다. 일련 번호를 표시할 Label, 제목과 내용을 입력할 TextBox, 제출과 취소와 이미지 선택을 위한 버튼, 선택한 이미지를 표시할 PictureBox, 날짜를 선택하는 DateTimePickerMonthCalendar입니다.


등록 폼 자식 컨트롤 배치

 

[그림 4.6] RegForm 자식 컨트롤 배치

 

 

No

Name

컨트롤 형식

설명

1

lb_no

Label

도서 일련 번호

2

tbox_title

TextBox

제목

3

tbox_description

TextBox

설명

4

btn_submit

Button

도서 등록

5

btn_cancel

Button

취소

6

pb_image

PictureBox

이미지 (SizeMode: StretchImage)

7

btn_image

Button

이미지 선택

8

dtp_date

DateTimePicker

날짜 선택 및 표시

9

mc_date

MonthCalendar

날짜 선택 및 표시

[4.1] RegForm 의 자식 컨트롤

 

 디폴트로 표시할 이미지를 리소스에 추가하세요. 여기에서는 default.jpg 파일명의 이미지를 리소스에 추가하였습니다.

 

 이미지 개체를 위해 멤버 필드를 선언합니다.

Image bm;

 도서 관리자 개체를 참조하기 쉽게 속성을 정의합니다.

BookManager BM

{

    get

    {

 BookManager 클래스의 정적 멤버 BM 그대로 By Pass 합니다.

        return BookManager.BM;

    }

}

 이미지 이름을 위해 멤버 필드를 선언합니다.

string imagename;

 속성 창을 이용해서 RegForm Load 이벤트 핸들러를 등록하세요.

private void RegForm_Load(object sender, EventArgs e)

{

 디폴트 이미지로 PictureBox 이미지를 설정합니다.

        pb_image.ImageLocation = @"Resources\default.jpg";

 디폴트 이미지를 bm 설정합니다.

    bm = pb_image.Image;

 도서 관리자 개체를 통해 추가할 사용할 일련 번호를 구하여 일련 번호를 표시할 Label Text 속성을 설정합니다.

    int no = BM.NextBSNo();

    lb_no.Text = no.ToString();

}

 

 이미지 버튼의 클릭 이벤트 핸들러를 등록합니다. 앞으로 컨트롤의 이벤트 핸들러를 등록하는 것은 속성 창을 이용하세요. 단순히 코드를 따라 친다고 동작하지 않습니다.

private void btn_image_Click(object sender, EventArgs e)

{

 파일을 선택할 있게 파일 열기 대화 상자를 만들어 ShowDialog 메서드를 호출합니다.

    OpenFileDialog ofd = new OpenFileDialog();

    ofd.Filter = "jpeg파일(*.jpg)|*.jpg|모든파일|*";

    if (ofd.ShowDialog() == DialogResult.OK)

    {

 선택한 파일 이름으로 pb_image 컨트롤의 ImageLocation 속성을 설정합니다.

        imagename = ofd.FileName;

        pb_image.ImageLocation = imagename;

    }

}


 제출 버튼의 클릭 이벤트 핸들러를 등록합니다.

private void btn_submit_Click(object sender, EventArgs e)

{

 입력한 정보를 얻어옵니다.

    string title = tbox_title.Text;

    string description = tbox_description.Text;

    int no = int.Parse(lb_no.Text);

    DateTime dt = dtp_date.Value;

 도서 관리자 개체의 AddBook 메서드를 호출합니다.

    if (BM.AddBook(title, description, no, imagename, dt) == false)

    {

 만약 추가 실패하면 메시지 창을 띄워 사용자에게 알려줍니다.

        MessageBox.Show("이미 존재합니다.");

    }

 도서 관리자 개체에게 다음에 추가할 도서 일련 번호를 확인하여 일련 번호를 표시할 Label 컨트롤의 Text 속성을 설정합니다.

    no = BM.NextBSNo();

    lb_no.Text = no.ToString();

 다른 속성을 리셋합니다.

    tbox_title.Text = tbox_description.Text = string.Empty;

    pb_image.Image = bm;

}


 MonthCalendar 컨트롤의 DateChanged 이벤트 핸들러를 등록합니다.

private void mc_date_DateChanged(object sender, DateRangeEventArgs e)

{

 인자로 받은 값의 Start 속성으로 DateTimePicker 컨트롤의 Value 속성을 설정합니다.

    dtp_date.Value = e.Start;

}


DateTimePicker 컨트롤의 ValueChanged 이벤트 핸들러를 등록합니다.

private void dtp_date_ValueChanged(object sender, EventArgs e)

{

 MonthCalendar 컨트롤의 SetData 메서드를 호출하여 날짜를 설정합니다.

    mc_date.SetDate(dtp_date.Value);

}

 

using System;

using System.Collections.Generic;

using System.Drawing;

using System.Windows.Forms;

namespace MyReadingStory

{

    /// <summary>

    /// 등록

    /// </summary>

    public partial class RegForm : Form

    {

        Image bm;

        BookManager BM

        {

            get

            {

                return BookManager.BM;

            }

        }

        string imagename;       

        /// <summary>

        /// 생성자

        /// </summary>

        public RegForm()

        {

            InitializeComponent();

        }

        private void RegForm_Load(object sender, EventArgs e)

        {           

            pb_image.ImageLocation = @"Resources\default.jpg";

            bm = pb_image.Image;

            int no = BM.NextBSNo();

            lb_no.Text = no.ToString();

        }

        private void btn_image_Click(object sender, EventArgs e)

        {

            OpenFileDialog ofd = new OpenFileDialog();

            ofd.Filter = "jpeg파일(*.jpg)|*.jpg|모든파일|*";

            if (ofd.ShowDialog() == DialogResult.OK)

            {

                imagename = ofd.FileName;

                pb_image.ImageLocation = imagename;

            }

        }

        private void btn_submit_Click(object sender, EventArgs e)

        {

            string title = tbox_title.Text;

            string description = tbox_description.Text;

            int no = int.Parse(lb_no.Text);

            DateTime dt = dtp_date.Value;

            if (BM.AddBook(title, description, no, imagename, dt) == false)

            {

                MessageBox.Show("이미 존재합니다.");

            }

            no = BM.NextBSNo();

            lb_no.Text = no.ToString();

            tbox_title.Text = tbox_description.Text = string.Empty;           

            pb_image.Image = bm;

        }

        private void mc_date_DateChanged(object sender, DateRangeEventArgs e)

        {

            dtp_date.Value = e.Start;

        }

        private void dtp_date_ValueChanged(object sender, EventArgs e)

        {

            mc_date.SetDate(dtp_date.Value);

        }

    }

}

 

4.4.2 ModifyForm

 

 프로젝트에 ModifyForm 추가하고 자식 컨트롤을 배치합니다. ModifyForm에는 도서 목록을 항목으로 표시하는 ListView 컨트롤과 선택한 도서의 정보를 표시할 컨트롤로 PictureBox 컨트롤, DateTimePicker 컨트롤 TextBox 컨트롤을 배치합니다. 그리고 이미지를 변경할 때와 변경 취소할 사용할 Button 컨트롤을 배치합니다.


수정 폼 자식 컨트롤 배치 

[그림 4.7] ModifyForm 자식 컨트롤 배치

 

 

No

Name

컨트롤 형식

설명

1

lv_diary

ListView

도서 목록(View: Details)

2

pb_image

PictureBox

이미지(SizeMode: StretchImage)

3

btn_iamge

Button

이미지 선택

4

dtp_date

DateTimePicker

날짜 선택 및 표시

5

tbox_description

TextBox

설명

6

btn_submit

Button

변경 요청

7

btn_cancel

Button

취소 요청

[4.2] ModifyForm 의 자식 컨트롤

 

 디폴트 이미지 파일명을 상수로 정의하세요.

const string def_imagename = @"Resources\default.jpg";

 이미지 이름 멤버를 선언하고 디폴트 이미지 이름으로 초기화합니다.

string imagename = def_imagename;

 

 도서 관리자 단일체를 사용하기 편하게 속성을 정의합니다.

BookManager BM

{

    get

    {

 BookManager 클래스의 정적 멤버 BM 그대로 By Pass 합니다.

        return BookManager.BM;

    }

}

 

 ModifyForm Load 이벤트 핸들러를 등록합니다.

private void ModifyForm_Load(object sender, EventArgs e)

{

 pb_image ImageLocation 속성을 디폴트 이미지 파일명으로 설정합니다.

    pb_image.ImageLocation = def_imagename;

 도서 관리자 개체에게 도서 목록을 요청합니다.

    List<BookStory> bsl = BM.GetBSCollection();

 

    foreach (BookStory bs in bsl)

    {

 도서 일련 번호와 제목으로 문자열 배열을 만들고 이를 인자로 ListViewItem 개체를 생성합니다.

        string[] subitems = new string[] { bs.No.ToString(), bs.Title };

        ListViewItem lvi = new ListViewItem(subitems);

 리스트 항목으로 생성한 ListViewItem 개체를 추가합니다.

        lv_diary.Items.Add(lvi);

 항목을 선택했을 도서 개체를 쉽게 참조할 있게 ListViewItem 개체의 Tag 속성에 설정합니다.

        lvi.Tag = bs;

    }

}

 

 이미지 버튼의 클릭 이벤트 핸들러를 등록합니다.

private void btn_image_Click(object sender, EventArgs e)

{

 파일 열기 대화 상자를 열거 선택한 이미지로 설정합니다. 부분은 RegForm에서 했던 작업과 일치합니다.

    OpenFileDialog ofd = new OpenFileDialog();

    ofd.Filter = "jpec 파일|*.jpg";

    if (ofd.ShowDialog() == DialogResult.OK)

    {

        imagename = ofd.FileName;

        pb_image.ImageLocation = imagename;

    }

}

 

 리스트 뷰의 SelectedIndexChanged 이벤트 핸들러를 등록합니다.

private void lv_diary_SelectedIndexChanged(object sender, EventArgs e)

{

 선택 항목의 개수가 0이면 이벤트 핸들러를 종료합니다.

    if (lv_diary.SelectedItems.Count == 0)

    {

        return;

    }

 선택한 ListViewItem Tag 속성을 BookStory 형식 개체를 참조합니다.

    BookStory bs = lv_diary.SelectedItems[0].Tag as BookStory;

 선택한 도서 개체로 컨트롤의 속성을 설정합니다.

    tbox_description.Text =bs.Description;

    pb_image.ImageLocation = bs.ImageName;

    dtp_date.Value = bs.DT;

}


 제출 버튼의 Click 이벤트 핸들러를 등록하세요.

private void btn_submit_Click(object sender, EventArgs e)

{

 선택 항목의 개수가 0이면 이벤트 핸들러를 종료합니다.

    if (lv_diary.SelectedItems.Count == 0)

    {

        return;

    }

 선택한 ListViewItem Tag 속성을 BookStory 형식 개체를 참조합니다.

    BookStory bs = lv_diary.SelectedItems[0].Tag as BookStory;

 도서 정보에 관한 컨트롤의 속성을 얻어와서 도서 관리자 개체에게 정보 변경을 요청합니다.

    string description = tbox_description.Text;

    DateTime dt = dtp_date.Value;

    BM.ModifyBS(bs.No, description,imagename,dt);

}

 

using System;

using System.Collections.Generic;

using System.Windows.Forms;

 

namespace MyReadingStory

{

    /// <summary>

    /// 변경하기

    /// </summary>

    public partial class ModifyForm : Form

    {

        const string def_imagename = @"Resources\default.jpg";

        string imagename = def_imagename;

 

        BookManager BM

        {

            get

            {

                return BookManager.BM;

            }

        }

 

        /// <summary>

        /// 생성자

        /// </summary>

        public ModifyForm()

        {

            InitializeComponent();

        }

 

 

        private void ModifyForm_Load(object sender, EventArgs e)

        {

            pb_image.ImageLocation = def_imagename;

            List<BookStory> bsl = BM.GetBSCollection();

 

            foreach (BookStory bs in bsl)

            {

                string[] subitems = new string[] { bs.No.ToString(), bs.Title };

                ListViewItem lvi = new ListViewItem(subitems);

                lv_diary.Items.Add(lvi);

                lvi.Tag = bs;

            }

        }

 

        private void btn_image_Click(object sender, EventArgs e)

        {

            OpenFileDialog ofd = new OpenFileDialog();

            ofd.Filter = "jpec 파일|*.jpg";

 

            if (ofd.ShowDialog() == DialogResult.OK)

            {

                imagename = ofd.FileName;

                pb_image.ImageLocation = imagename;

            }

        }

        private void lv_diary_SelectedIndexChanged(object sender, EventArgs e)

        {

            if (lv_diary.SelectedItems.Count == 0)

            {

                return;

            }

            BookStory bs = lv_diary.SelectedItems[0].Tag as BookStory;

            tbox_description.Text =bs.Description;

            pb_image.ImageLocation = bs.ImageName;

            dtp_date.Value = bs.DT;           

        }

 

        private void btn_submit_Click(object sender, EventArgs e)

        {

            if (lv_diary.SelectedItems.Count == 0)

            {

                return;

            }

 

            BookStory bs = lv_diary.SelectedItems[0].Tag as BookStory;

            string description = tbox_description.Text;

            DateTime dt = dtp_date.Value;

            BM.ModifyBS(bs.No, description,imagename,dt);

        }

    }

}

 

 

 

4.4.3 MainForm

 

 프로젝트 생성할 디폴트로 만들어주는 Form1 이름을 MainForm으로 변경하세요. 솔루션 탐색기에서 변경하면 마법사에서 클래스 이름을 자동으로 변경합니다.

 

 MainForm에는 도서 목록을 표시할 ListView 컨트롤과 등록, 자세히 보기, 삭제, 변경할 사용할 Button 컨트롤을 추가하세요.


메인 폼 자식 컨트롤 배치

[그림 4.8] MainForm 자식 컨트롤 배치

 

 

 

No

Name

컨트롤 형식

설명

1

lv_diary

ListView

도서 목록(View: Details)

2

btn_reg

Button

등록

3

btn_verify

Button

자세히보기

4

btn_remove

Button

삭제

5

btn_modify

Button x

변경

[4.3] MainForm 의 자식 컨트롤

 

 MainForm에서 세 개의 폼을 띄우는 작업을 수행합니다. 이 때 각각의 폼은 하나씩만 뜨게 구현할 것입니다. 이를 위해 멤버를 선언합시다.

RegForm rf = null;

VerifyForm vf = null;

ModifyForm mf = null;

 

 도서 관리자 개체를 쉽게 사용할 있게 속성을 정의합시다.

BookManager BM

{

    get

    {

        return BookManager.BM;

    }

}

 

MainForm Load  이벤트 핸들러를 등록하세요.

private void MainForm_Load(object sender, EventArgs e)

{

 도서 관리자 개체에 도서 추가/삭제, 변경 이벤트 핸들러를 등록합니다.

    BM.OnAddBS += new AddEventHandler(BM_OnAddBS);

    BM.OnModifyBS += new ModifyEventHandler(BM_OnModifyBS);

}

 

void BM_OnModifyBS(object sender, ModifyEventArgs e)

{

 도서 변경 이벤트 핸들러에서는 도서 목록에서 이벤트 인자로 받은 일련번호와 같은 항목을 찾습니다.

    foreach (ListViewItem lvi in lv_diary.Items)

    {

        if (lvi.Text == e.No.ToString())

        {

 날짜 항목을 이벤트 인자로 받은 값으로 설정합니다.

            lvi.SubItems[2].Text = e.DT.ToShortDateString();

            return;

        }

    }

}

 

void BM_OnAddBS(object sender, AddEventArgs e)

{

    if (e.IsAdded)

    {

 이벤트 인자의 IsAdded 속성이 참이면 도서를 추가했다는 통보입니다. 이벤트 인자의 일련번호, 제목, 날짜로 문자열 배열 개체를 생성합니다. 그리고 생성한 배열 개체를 입력 인자로 ListViewItem 개체를 만들어 ListView 항목에 추가합니다.

        string[] strs = new string[3]

                           {e.No.ToString(), e.Title,e.DT.ToShortDateString()};

        ListViewItem lvi = new ListViewItem(strs);

        lv_diary.Items.Add(lvi);

    }

    else

    {

 이벤트 인자의 IsAdded 속성이 거짓이면 도서를 삭제했다는 통보입니다.

        foreach (ListViewItem lvi in lv_diary.Items)

        {

            if (lvi.Text == e.No.ToString())

            {

 리스트 뷰에서 일련 번호가 같은 항목을 찾아 제거합니다.

                lv_diary.Items.Remove(lvi);

                return;

            }

        }

 만약 목록에 없는 도서 삭제 이벤트를 통보 받았다면 프로그램에 버그가 있는 것입니다. 버그를 빨리 발견할 있게 예외를 던집니다.

        throw new ApplicationException("목록에 없는 삭제 이벤트를 통보 받음");

    }

}

 

 등록 버튼의 Click 이벤트 핸들러를 등록합니다.

private void btn_reg_Click(object sender, EventArgs e)

{

    if (rf == null)

    {

 RegForm 개체가 없을 때만 생성합니다.

        rf = new RegForm();

 RegForm 닫힐 때를 알아야 하므로 FormClosed 이벤트 핸들러를 등록합니다.

        rf.FormClosed += new FormClosedEventHandler(Sub_FormClosed);

        rf.Show();

    }

}

 

void Sub_FormClosed(object sender, FormClosedEventArgs e)

{

 이벤트 게시자를 Form 형식 개체로 참조합니다.

    Form form = sender as Form;

 폼이 누구인지를 확인하여 해당 멤버를 null 설정합니다.

    if (form.Equals(rf))

    {

        rf = null;

    }

    if (form.Equals(vf))

    {

        vf = null;

    }

    if (form.Equals(mf))

    {

        mf = null;

    }

}

 

 자세히 버튼과 변경 버튼에도 클릭 이벤트 핸들러를 등록하세요. 해야 작업은 등록 버튼의 클릭 이벤트 핸들러와 논리가 같습니다.

private void btn_verify_Click(object sender, EventArgs e)

{

    if (vf == null)

    {

        vf = new VerifyForm();

        vf.FormClosed += new FormClosedEventHandler(Sub_FormClosed);

        vf.Show();

    }

}

private void btn_modify_Click(object sender, EventArgs e)

{

    if (mf == null)

    {

        mf = new ModifyForm();

        mf.FormClosed += new FormClosedEventHandler(Sub_FormClosed);

        mf.Show();

    }

}

 

 도서 목록 리스트 뷰의 SelectedIndexChanged 이벤트 핸들러를 등록하세요.

private void lv_diary_SelectedIndexChanged(object sender, EventArgs e)

{

 만약 선택항목이 없으면 삭제 버튼을 비활성화하고 있으면 활성화합니다.

    btn_remove.Enabled = (lv_diary.SelectedItems.Count != 0);

}

 

 삭제 버튼의 Click 이벤트 핸들러를 등록하세요.

private void btn_remove_Click(object sender, EventArgs e)

{

    if (lv_diary.SelectedItems.Count == 0)

    {

 선택 항목이 없는데 삭제 이벤트를 통보받았다면 프로그램 버그입니다. 예외를 던져 빠르게 버그를 발견할 있게 합시다.

        throw new ApplicationException(

                          "선택 항목이 없는데 삭제 요청");

    }

 선택 항목의 일련 번호를 구합니다.

    ListViewItem lvi = lv_diary.SelectedItems[0];

    int no = int.Parse(lvi.Text);

 도서 관리자 개체의 RemoveBS 메서드를 호출하여 도서를 삭제 요청합니다.

    BM.RemoveBS(no);

}

반응형