기말고사 담당교수 : 단국대학교멀티미디어공학전공박경신 답은반드시답안지에기술할것. 공간이부족할경우반드시답안지몇쪽의뒤에있다고명기한후기술할것. 그외의경우의답안지뒤쪽이나연습지에기술한내용은답안으로인정안함. 답에는반드시네모를쳐서확실히표시할것. 답안지에학과, 학번, 이름외에본인의암호를기입하면성적공고시학번대신암호를사용할것임. 1. 다음문장의내용이맞으면 True, 틀리면 False를표시하시오. (20점) 1) 윈도우응용프로그램은메시지구동구조 (Message-driven Architecture) 방식으로동작한다. T 2) MFC 응용프로그램은윈도우시스템으로부터들어온마우스클릭이나키보드입력같은메시지를 switch문을사용하여처리한다. F 3) MFC의메시지맵 (Message Map) 은윈도우메시지와해당메시지핸들러 (Message Handler) 를연결시킨다. T 4) 특정위치에있는원소를참조하고자할때는리스트 (List) 를, 원소의삽입또는삭제가많은경우배열 (Array) 을사용한다. F 5) MFC 응용프로그램은 Win32 API 함수를직접호출가능하다. T 6) MFC 유틸리티클래스 (Utility Class) 인 CPoint, CRect, CSize, CTime, CTimeSpan은 CObject의파생클래스이다. F 7) MFC에서프레임윈도우 (Frame Window), 대화상자 (Dialog Boxes), 뷰 (Views), 컨트롤 (Controls) 은모두윈도우클래스 (CWnd) 의파생클래스이다. T 8) MFC에서는일반응용프로그램에서자주사용하는공통적대화상자들에대한공용대화상자 (Common Dialog Box) 를제공한다. T 9) SDI (Single Document Interface) 응용프로그램에서는하나의도큐먼트와하나의뷰객체만존재한다. F 10) MFC에서컨트롤 (Controls) 은일반적으로대화상자에많이사용되고있으며, 항상자식윈도우 (Child Window) 로만존재한다. T 2. MFC에서사용자에게입력을받거나정보를보여주는제어 (Control) 와관련된윈도우는표준컨트롤 (Standard Controls) 과공통컨트롤 (Common Controls) 로나뉜다. 표준컨트롤클래스 5개와공통컨트롤클래스 5개를나열하라. (10점) 표준컨트롤클래스 : CButton ( 푸시버튼, 체크박스, 라디오버튼, 그룹박스컨트롤 ), CStatic ( 텍스트나그림을보여주는정적컨트롤 ), CEdit ( 편집컨트롤 ), CListBox ( 리스트박스컨트롤 ), CComboBox ( 콤보박스컨트롤 ), CScrollBar ( 수평 / 수직스크롤바컨트롤 ) 1/12
공통컨트롤클래스 : CAnimateCtrl ( 간단한 AVI 클립재생을위한애니메이션컨트롤 ), CDateTimeCtrl ( 날짜시간선택기컨트롤 ), CComboBoxEx ( 확장콤보박스컨트롤 ), CListCtrl ( 리스틑컨트롤 ), CProgressCtrl ( 프로그래스컨트롤 ), CRichEditCtrl ( 다양한기능을제공하는텍스트입력컨트롤 ), CSpinButtonCtrl ( 스핀버튼컨트롤 ), CTabCtrl ( 동일한화면영역에다른페이지를표시및전환하는탭컨트롤 ), CTreeCtrl ( 트리계층적으로항목을표시하는트리컨트롤 ) 3. 윈도우응용프로그램은메시지처리주체에따라윈도우 (Window) 메시지, 통지 (Notify) 메시지, 명령 (Command) 메시지로나뉜다. 다음테이블에관련있는 메시지 를 10개찾아넣어라. (10점) 윈도우메시지 (Window Message) 통지메시지 (Notify Message) 명령메시지 (Command Message) WM_PAINT, WM_CREATE, WM_DESTROY, WM_ACTIVE, WM_INITDIALOG, WM_KEYDOWN, WM_CHAR, WM_MOUSEMOVE, WM_LBUTTONDOWN BN_CLICKED, EN_CHANGE, CBN_SELCHANGE, LBN_SELCHANGE WM_COMMAND 4. 다음보기는 CPerson 클래스에서직렬화를사용한예를보여주고있다. 직렬화에관련된부분에주석을달아라. (5점) --Person.h #if!defined( PERSON_H) #define PERSON_H class CPerson : public CObject // 직렬화를위해 CObject 클래스를상속 DECLARE_SERIAL(CPerson) // 직렬화를위해 DECLARE/IMPLEMENT_SERIAL 매크로호출 public: CString m_strname; // 다음의멤버변수를직렬화함 int m_nage; CString m_strappearance; CString m_strpersonality; public: CPerson(); CPerson(CString, int, CString, CString); CPerson(const CPerson& person); ~CPerson(); CPerson &operator=(const CPerson& person); virtual void Serialize(CArchive& ar); // 직렬화를위해 Serialize 함수를재정의 (overriding) void SetName(CString strname) m_strname = strname; void SetAge(int nage) m_nage = nage; void SetAppearance(CString strappearance) m_strappearance = strappearance; void SetPersonality(CString strpersonality) m_strpersonality = strpersonality; 2/12
; #endif const CString GetName() return m_strname; const int GetAge() return m_nage; const CString GetAppearance() return m_strappearance; const CString GetPersonality() return m_strpersonality; --Person.cpp #include "stdafx.h" #include "Person.h" IMPLEMENT_SERIAL(CPerson, CObject, 1) // 직렬화를위해 DECLARE/IMPLEMENT_SERIAL 매크로호출 CPerson::CPerson() m_strname = _T(""); m_nage = 0; m_strappearance = _T(""); m_strpersonality = _T(""); CPerson::CPerson(CString strname, int nage, CString strappearance, CString strpersonality) m_strname = strname; m_nage = nage; m_strappearance = strappearance; m_strpersonality = strpersonality; CPerson::CPerson(const CPerson& person) m_strname = person.m_strname; m_nage = person.m_nage; m_strappearance = person.m_strappearance; m_strpersonality = person.m_strpersonality; CPerson::~CPerson() CPerson &CPerson::operator=(const CPerson& person) m_strname = person.m_strname; m_nage = person.m_nage; m_strappearance = person.m_strappearance; m_strpersonality = person.m_strpersonality; return *this; void CPerson::Serialize(CArchive &ar) CObject::Serialize(ar); // 기본클래스의함수호출 if (ar.isstoring()) ar << m_strname << m_nage << m_strappearance << m_strpersonality; // 쓰기상태이면모든변수를순서대로아카이브에저장 else ar >> m_strname >> m_nage >> m_strappearance >> m_strpersonality; // 모든변수를순서대로아카이브로부터읽음 3/12
5. 다음그림은윈도우응용프로그램의출력과정을보여주고있다. GDI (Graphics Device Interface) 와 DC (Device Context) 가무엇인지출력과정에서그기능을설명하라 (5점) GDI DC 응용프로그램의요청을받아서실제출력장치에대한출력담당 응용프로그램에대한독립적인그래픽동작수행 장치에의존하지않으므로장치가변경되더라도프로그램의수정이불필요 멀티태스킹을위한분할처리를하는운영체제에서하나의응용프로그램이출력장치를독점하지못하도록운영체제를통하여장치에간접접근 GDI가생성하고관리하는데이터구조체 DC를통해멀티태스킹 ( 멀티스레딩 ) GUI 환경에서발생할수있는여러상황을고려하여출력가능 -출력영역, 원점정보, 그래픽정보 ( 글꼴, 펜, 브러시 ) 기능 응용프로그램의출력에대한허가를얻고, 그려지는영역을결정하는역할 윈도우의클리핑영역 ( 즉, 응용프로그램의출력허용영역 ) 관리 그래픽정보관리 ( 펜, 브러시, 글꼴, 비트맵, 팔레트 ) DC를얻고나면, 반드시작업완료시해제필요 6. MFC 의명령갱신핸들러 (Command Update Handler) 에대해간단히설명하라. (5 점 ) 메뉴, 툴바, 상태바등사용자인터페이스의요소상태를변경하기위해명령갱신핸들러를사용한다. 예를들어, 메뉴항목에체크표시를하거나, 메뉴항목을활성화또는비활성화하거나, 문자열변경등항목을갱신하기위해명령갱신핸들러를사용한다. UPDATE_COMMAND_UI 메시지는메뉴항목이표시되기전에보내지는메시지로, 명령갱신핸들러함수는 OnUpdate로시작한다. --ChildView.cpp BEGIN_MESSAGE_MAP(CChildView, CWnd) ON_WM_PAINT() ON_UPDATE_COMMAND_UI(ID_TEXTCOLOR_RED, &CChildView::OnUpdateTextColorRed) ON_UPDATE_COMMAND_UI(ID_TEXTCOLOR_GREEN, &CChildView::OnUpdateTextColorGreen) ON_UPDATE_COMMAND_UI(ID_TEXTCOLOR_BLUE, &CChildView::OnUpdateTextColorBlue) 4/12
END_MESSAGE_MAP() // m_textcolor 가빨간색이면이메뉴항목을체크표시 void CChildView::OnUpdateTextColorRed(CCmdUI *pcmdui) pcmdui->setcheck(m_textcolor == RGB(255, 0, 0)); // m_textcolor 가초록색이면이메뉴항목을체크표시 void CChildView::OnUpdateTextColorGreen(CCmdUI *pcmdui) pcmdui->setcheck(m_textcolor == RGB(0, 255, 0)); // m_textcolor 가파란색이면이메뉴항목을체크표시 void CChildView::OnUpdateTextColorBlue(CCmdUI *pcmdui) pcmdui->setcheck(m_textcolor == RGB(0, 0, 255)); --MainFrm.cpp BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_UPDATE_COMMAND_UI(ID_INDICATOR_POS, OnUpdateIndicatorPos) END_MESSAGE_MAP() // 상태바에서 nindex=1 의칸을활성화 void CMainFrame::OnUpdateIndicatorPos(CCmdUI* pcmdui) pcmdui->enable(); 7. 다음은 MDI (Multiple Document Interface) 응용프로그램의기본구조를간략히보여주고있다. 각클래스에서하는기능에대해간략히설명하라. (10점) CWinApp 파생클래스 (3점): 응용프로그램클래스를나타낸다 InitInstance() 함수에서응용프로그램의메인프레임윈도우를구성하고출력하는데필요한함수를호출한다내부에서 CWinApp::Run() 함수에서메시지루프를만든다 ExitInstance() 함수에서종료시 clean-up에필요한함수를호출한다 5/12
CMultiDocTemplate 클래스 (2점): 응용프로그램클래스의 InitInstance에서생성된다도큐먼트프레임윈도우, 도큐먼트, 뷰클래스정보를유지하는클래스이다 CMDIFrameWnd 파생클래스 (2점): 응용프로그램의메인프레임을관리한다 Create() 함수를호출하면실제윈도우가생성된다 CMDIChildWnd 파생클래스 (1점): 응용프로그램의도큐먼트프레임윈도우를관리한다 CView 파생클래스 (1점): 응용프로그램에서데이터를화면에표시하며사용자와의상호작용을담당한다 CDocument 파생클래스 (1점): 응용프로그램에서데이터를저장하거나읽기를담당한다데이터의변경사항이생기면뷰의화면을갱신한다 8. 다음은 MFC 도큐먼트 / 뷰구조기반의간단한텍스트파일을입출력하는 SimpleTextFile 예제프로그램의일부를보여주고있다. 파일입출력과도큐먼트 / 뷰구조의주요함수밑줄친부분에주석을달아라. (10점) --SimpleTextFileDoc.cpp //.. 생략 CSimpleTextFileDoc BEGIN_MESSAGE_MAP(CSimpleTextFileDoc, CDocument) ON_COMMAND(ID_FILE_TEXTIMPORT, &CSimpleTextFileDoc::OnFileImport) ON_COMMAND(ID_FILE_TEXTEXPORT, &CSimpleTextFileDoc::OnFileExport) END_MESSAGE_MAP() //.. 생략 BOOL CSimpleTextFileDoc::OnNewDocument() // (1) 새로운도큐먼트생성 if (!CDocument::OnNewDocument()) return FALSE; m_str = ""; return TRUE; //.. 생략 void CSimpleTextFileDoc::OnFileImport() // (2) 텍스트파일을읽어 m_str로저장하고뷰를갱신 char szfilter[] = "Text File (*.txt) *.txt All Files(*.*) *.* "; CFileDialog dlg(true, NULL, NULL, OFN_HIDEREADONLY, szfilter); if(idok == dlg.domodal()) 6/12
TRY CFile file(dlg.getpathname(), CFile::modeRead); DWORD dwlength = file.getlength(); BYTE *pbuffer = new BYTE[dwLength]; if (pbuffer) // (3) 파일을읽어들여 pbuffer로저장 if (file.read(pbuffer, dwlength) == dwlength) m_str = CString((LPCTSTR)pBuffer, dwlength); // (4) 새로운 m_str을뷰에서갱신 UpdateAllViews(NULL); delete pbuffer; CATCH(CFileException, e) e->reporterror(); END_CATCH void CSimpleTextFileDoc::OnFileExport()// (5) m_str 을텍스트파일로저장하기 char szfilter[] = "Text File (*.txt) *.txt All Files(*.*) *.* "; CFileDialog dlg(false, "txt", NULL, OFN_HIDEREADONLY, szfilter); if(idok == dlg.domodal()) CFile file; if (file.open(dlg.getpathname(), CFile::modeWrite CFile::modeCreate)!= 0) DWORD dwlength = m_str.getlength(); LPTSTR pbuffer = m_str.lockbuffer(); if (pbuffer && lstrlen(pbuffer) > 0) file.write(pbuffer, dwlength); // (6) pbuffer 를파일로쓰기 m_str.unlockbuffer(); --SimpleTextFileView.cpp //.. 생략 CSimpleTextFileView void CSimpleTextFileView::OnDraw(CDC* pdc) CSimpleTextFileDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (!pdoc) return; CRect rect; GetClientRect(&rect); pdc->drawtext(pdoc->m_str, &rect, DT_LEFT); // (7) 도큐먼트의 m_str 을뷰에서출력 //.. 생략 void CSimpleTextFileView::OnChar(UINT nchar, UINT nrepcnt, UINT nflags) CSimpleTextFileDoc* pdoc = GetDocument(); pdoc->m_str += (char) nchar; // (8) 키보드로입력된문자를도큐먼트의 m_str 으로추가 pdoc->setmodifiedflag();// (9) 도큐먼트에데이터가갱신된것을알림 Invalidate();// (10) 뷰클래스의무효화를하여 OnDraw 가불려서화면에출력하게함 CView::OnChar(nChar, nrepcnt, nflags); 7/12
9. 모드형대화상자 (Modal Dialog Box) 와비모드형대화상자 (Modeless Dialog Box) 방식을차이점을강조하여설명하고, 각방식의구현순서에대해간단히설명하라. (10점) 모드형대화상자 (2점): 대화상자가출력되어있는동안제어권을독점하고있는형태로대화상자를닫지않으면응용프로그램이더이상진행할수없다. 예 : 파일열기 / 저장대화상자모드형대화상자객체는대개지역변수로스택에생성한다. 비모드형대화상자 (2점): 대화상자가출력되어있는동안제어권을독점하고있지않은형태로대화상자를닫지않더라고응용프로그램윈도우와정보를교환할수있다. 예 : 찾기대화상자비모드형대화상자객체는대개동적으로힙에생성한다. 모드형대화상자작성순서 (3점): 1. 대화상자리소스작성 2. CDialog에파생클래스로클래스작성 3. 모드형대화상자객체생성 4. DoModal() 함수호출로대화상자가생성 5. EndDialog(int) 함수호출로대화상자종료 비모드형대화상자작성순서 (3점): 1. 대화상자리소스작성 2. CDialog에파생클래스로클래스작성 이비모드형대화상자클래스와뷰클래스에상대방객체의주소를넘겨준다 3. CDialog::Create() 함수로대화상자를동적생성 4. CWnd::ShowWindow() 함수로대화상자화면표시 5. CWnd::DestroyWindow() 함수호출로대화상자종료 10. 다음은 CTreeCtrl 클래스의활용예제를보여주고있다. 아래의네모안에이프로그램의처음실행시나타나는트리구조를그림으로나타내라. (5점) 또한, 대화상자에버튼클릭시실행결과를적어라. (5점) 마우스로트리항목을클릭 / 더블클릭했을경우실행결과를적어라. (5점) 그리고, 프로그램에서트리컨트롤관련된부분에주석을달아라. (5점) IDB_BITMAP1 8/12
IDD_SIMPLETREECTRL_DIALOG --SimpleTreeCtrlDlg.h #include "MyTreeCtrl.h" class CSimpleTreeCtrlDlg : public CDialog // Construction public: CSimpleTreeCtrlDlg(CWnd* pparent = NULL); // standard constructor // Dialog Data enum IDD = IDD_SIMPLETREECTRL_DIALOG ; CImageList m_ilsmall; CMyTreeCtrl m_tree; HTREEITEM hroot, hparent, hselected; protected: virtual void DoDataExchange(CDataExchange* pdx); // DDX/DDV support // Implementation protected: HICON m_hicon; // Generated message map functions virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nid, LPARAM lparam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedAddroot(); afx_msg void OnBnClickedAddchild(); afx_msg void OnBnClickedDelsel(); afx_msg void OnBnClickedDelall(); ; --SimpleTreeCtrlDlg.cpp #include "stdafx.h" #include "SimpleTreeCtrl.h" #include "SimpleTreeCtrlDlg.h" CSimpleTreeCtrlDlg::CSimpleTreeCtrlDlg(CWnd* pparent /*=NULL*/) : CDialog(CSimpleTreeCtrlDlg::IDD, pparent) m_hicon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); void CSimpleTreeCtrlDlg::DoDataExchange(CDataExchange* pdx) CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_TREE, m_tree); 9/12
BEGIN_MESSAGE_MAP(CSimpleTreeCtrlDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_ADDCHILD, &CSimpleTreeCtrlDlg::OnBnClickedAddchild) ON_BN_CLICKED(IDC_DELSEL, &CSimpleTreeCtrlDlg::OnBnClickedDelsel) ON_BN_CLICKED(IDC_DELALL, &CSimpleTreeCtrlDlg::OnBnClickedDelall) ON_BN_CLICKED(IDC_ADDROOT, &CSimpleTreeCtrlDlg::OnBnClickedAddroot) END_MESSAGE_MAP() // CSimpleTreeCtrlDlg message handlers BOOL CSimpleTreeCtrlDlg::OnInitDialog() CDialog::OnInitDialog(); //.. 생략 // set imagelist to tree m_ilsmall.create(idb_bitmap1,16, 2, RGB(255, 255, 255)); m_tree.setimagelist(&m_ilsmall, TVSIL_NORMAL); m_ilsmall.detach(); // tree HTREEITEM hbefore; hparent = m_tree.insertitem(text("parent"), 0, 1, NULL, TVI_ROOT); hbefore = hparent; hparent = m_tree.insertitem(text("child1"), 0, 1, hparent, TVI_LAST); hparent = m_tree.insertitem(text("child of Child1"), 0, 1, hparent, TVI_LAST); m_tree.insertitem(text("doublic Click Me"), 0, 1, hparent, TVI_LAST); hparent = m_tree.insertitem(text("child2"), 0, 1, hbefore, TVI_LAST); m_tree.insertitem(text("parent2"), 0, 1, NULL, TVI_LAST); return TRUE; // return TRUE unless you set the focus to a control //.. 생략 void CSimpleTreeCtrlDlg::OnBnClickedAddroot() hparent = m_tree.insertitem(text("parent Added"), 0, 1, NULL, TVI_ROOT); void CSimpleTreeCtrlDlg::OnBnClickedAddchild() hselected = m_tree.getselecteditem(); if (hselected!= NULL) m_tree.insertitem(text("child Added"), 0, 1, hselected, TVI_LAST); void CSimpleTreeCtrlDlg::OnBnClickedDelsel() hselected = m_tree.getselecteditem(); if (hselected!= NULL) m_tree.deleteitem(hselected); void CSimpleTreeCtrlDlg::OnBnClickedDelall() m_tree.deleteallitems(); --MyTreeCtrl.h class CMyTreeCtrl : public CTreeCtrl DECLARE_DYNAMIC(CMyTreeCtrl) 10/12
public: CMyTreeCtrl(); virtual ~CMyTreeCtrl(); protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnNMDblclk(NMHDR *pnmhdr, LRESULT *presult); afx_msg void OnTvnSelchanged(NMHDR *pnmhdr, LRESULT *presult); ; --MyTreeCtrl.cpp #include "stdafx.h" #include "SimpleTreeCtrl.h" #include "MyTreeCtrl.h" IMPLEMENT_DYNAMIC(CMyTreeCtrl, CTreeCtrl) CMyTreeCtrl::CMyTreeCtrl() CMyTreeCtrl::~CMyTreeCtrl() BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl) ON_NOTIFY_REFLECT(NM_DBLCLK, &CMyTreeCtrl::OnNMDblclk) ON_NOTIFY_REFLECT(TVN_SELCHANGED, &CMyTreeCtrl::OnTvnSelchanged) END_MESSAGE_MAP() // CMyTreeCtrl message handlers void CMyTreeCtrl::OnNMDblclk(NMHDR *pnmhdr, LRESULT *presult) // TODO: Add your control notification handler code here HTREEITEM hselected = GetSelectedItem(); if(hselected == NULL) MessageBox("No Items in TreeView","Error",MB_OK MB_ICONINFORMATION); EnsureVisible(hSelected); MessageBox("Press OK to delete me!","example",mb_ok MB_ICONINFORMATION); if (hselected!= NULL) DeleteItem(hSelected); *presult = 0; void CMyTreeCtrl::OnTvnSelchanged(NMHDR *pnmhdr, LRESULT *presult) LPNMTREEVIEW pnmtreeview = reinterpret_cast<lpnmtreeview>(pnmhdr); HTREEITEM hselected = GetSelectedItem(); CString stritemtext = GetItemText(hSelected); MessageBox(strItemText); *presult = 0; 11/12
CSimpleTreeCtrlDlg::OnInitDialog - 처음프로그램시나타나는트리구조단국대학교멀티미디어공학 HCI 프로그래밍 II 기말고사 (2007년가을학기 ) 2007년 12월 14일학과학번이름 CMyTreeCtrl::OnTvnSelchanged - 마우스로트리항목 Child1을선택했을경우메시지박스가뜬다 CMyTreeCtrl::OnNMDblclk - 마우스로트리항목을더블클릭했을경우메시지박스가뜨고그선택된항목을지운다 CSimpleTreeCtrlDlg::OnBnClickedAddroot 루트추가 버튼을클릭했을경우루트의마지막에 Parent Added 가추가된다 CSimpleTreeCtrlDlg::OnBnClickedAddchild 자식추가 버튼을클릭했을경우현재재선택된항목의자식으로 Child Added 가추가된다 CSimpleTreeCtrlDlg::OnBnClickedDelsel 선택지우기 버튼을클릭했을경우현재선택된항목을지운다 CSimpleTreeCtrlDlg::OnBnClickedDelall 모두지우기 버튼을클릭했을경우모든트리항목을지운다 - 끝 - 12/12