Visual C++ Programming Document/View Architecture 3 Department of Digital Contents Sang Il Park
Splitter Window
분할 윈도우 (1/4) 동적 분할 윈도우 같은 뷰 클래스를 기반으로 여러 개의 뷰를 생성 총 네 개의 구획(Pane) 생성 가능
분할 윈도우 (2/4) 동적 분할 윈도우 구현
분할 윈도우 (2/4) 동적 분할 윈도우로 다양한 내용 출력하기: 현재의 뷰가 어떠한 어떤 pane에 속하는지 판단 bool CSpliterWnd::IsChildPane ( CWnd * wnd, int * row, int * col ) if (col == 0) { … } Else if (col == 1) { …,
분할 윈도우 (3/4) 정적 분할 윈도우 서로 다른 뷰 클래스를 기반으로 여러 개의 뷰를 생성 총 256개의 구획 생성 가능
분할 윈도우 (4/4) 정적 분할 윈도우 구현 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext) { m_wndSplitter.CreateStatic(this, 2, 1); m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CFirstView), CSize(300, 200), pContext); m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CSecondView), return TRUE; }
MDI 응용 프로그램 구조 (1/8) MDI 응용 프로그램 기본 구조 응용 프로그램 (CWinApp) 도큐먼트 템플릿 (CMultiDocTemplate) 도큐먼트 (CDocument) 뷰 (CView) 도큐먼트 프레임 윈도우 (CMDIChildWnd) 메인 윈도우 (CMDIFrameWnd)
MDI 응용 프로그램 구조 (2/8) MDI 응용 프로그램 일반 구조 1 응용 프로그램 객체 도큐먼트 템플릿 도큐먼트 객체 2 뷰 객체 2 도큐먼트 객체 1 뷰 객체 1 도큐먼트 객체 3 뷰 객체 3
MDI 응용 프로그램 만들기 프로젝트에서 Multiple Document Interface 를 설정하여 프로젝트를 생성해 보자
MDI 응용 프로그램 구조 (3/8) SDI와 MDI 응용 프로그램 비교 도큐먼트 템플릿으로 CSingleDocTemplate 클래스 대신 CMultiDocTemplate 클래스 사용 SDI 응용 프로그램과 달리 MDI 응용 프로그램은 도큐먼트 객체를 재사용하지 않고 매번 새로 생성 MDI 응용 프로그램에서는 메인 윈도우와 도큐먼트 프레임 윈도우가 별개이며 각각 CMDIFrameWnd, CMDIChildWnd 클래스 사용
MDI 응용 프로그램 구조 (4/8) InitInstance() 함수 BOOL CExMDIApp::InitInstance() { ... CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_EXMDITYPE, RUNTIME_CLASS(CExMDIDoc), RUNTIME_CLASS(CChildFrame), // 도큐먼트 프레임 윈도우 RUNTIME_CLASS(CExMDIView)); AddDocTemplate(pDocTemplate); CMainFrame* pMainFrame = new CMainFrame; // 메인 윈도우 if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; }
MDI 응용 프로그램 구조 (5/8) 주요 객체 사이의 참조 AfxGetMainWnd AfxGetApp GetFirstViewPosition & GetNextView GetDocument GetActiveDocument GetActiveView GetParentFrame 도큐먼트 프레임 윈도우 응용 프로그램 메인 윈도우 뷰 템플릿 GetFirstDocTemplatePosition & GetNextDocTemplate GetDocTemplate m_pMainWnd GetFirstDocPosition & GetNextDoc MDIGetActive 또는 GetActiveFrame
MDI 응용 프로그램 구조 (6/8) 함수 요약 View에서 Document를 얻고 싶을 때: GetDocument() Document에서 view를 얻고 싶을 때: GetFirstViewPosition / GetNextView 함수 사용 POSITION pos = GetFirstViewPosition(); while (pos != NULL) { CView* pView = GetNextView(pos); pView->DoSomething(); }
MDI 응용 프로그램 구조 (7/8) MDI 응용 프로그램 특징 [파일]->[새 파일] 메뉴 항목을 선택하면 새로운 도큐먼트, 도큐먼트 프레임 윈도우, 뷰 객체가 생성 [창]->[다음 창] 메뉴 항목을 선택하면 활성 도큐먼트에 대한 뷰를 추가로 생성 가능 최소 두 개의 메뉴 사용
MDI 응용 프로그램 구조 (8/8) MDI 응용 프로그램 일반 구조 2 응용 프로그램 객체 도큐먼트 템플릿 도큐먼트 객체 2 뷰 객체 2 도큐먼트 객체 1 뷰 객체 1 도큐먼트 객체 3 뷰 객체 3 뷰 객체 4
MDI Multi-View 프로그래밍 연습 다음과 같은 프로그램을 만들어 보자 새 창을 열 때 마다 창의 번호를 붙여주는 프로그램 GetFirstViewPosition / GetNextView 함수 사용
다양한 도큐먼트 타입 지원 (1/2) MDI 응용 프로그램 일반 구조 3 두 개 이상의 도큐먼트 타입 지원 응용 프로그램 객체 도큐먼트 템플릿 1 도큐먼트 객체 2 뷰 객체 2 도큐먼트 객체 1 뷰 객체 1 도큐먼트 객체 3 뷰 객체 3 도큐먼트 템플릿 2 도큐먼트 객체 4 뷰 객체 4 뷰 객체 5
다양한 도큐먼트 타입 지원 (1/2)
다양한 View Classes
다양한 View Class? View Class에는 많은 종류가 있다
다양한 View Class? Project 생성 시 Setting:
FormView Dialog Box와 비슷한 역할을 하는 View Class
Common Controls
공통 컨트롤 기초 (1/5) 컨트롤 툴바 표준 컨트롤 공통 컨트롤
공통 컨트롤 기초 (2/5) 공통 컨트롤 종류
공통 컨트롤 기초 (3/5) 공통 컨트롤 종류 (cont'd)
리스트 컨트롤 (1/3) 리스트 컨트롤 = 리스트 뷰 컨트롤 표시 방법 이미지와 텍스트를 이용하여 다양한 형태로 정보를 표시하는 용도로 사용 표시 방법 아이콘 보기 32*32 크기의 아이콘과 텍스트로 항목 표시 작은 아이콘 보기 16*16 크기의 아이콘과 텍스트로 항목 표시 목록 보기
리스트 컨트롤 (2/3) 표시 방법 (cont'd) 보고서 보기 헤더 컨트롤 항목 서브 항목 16*16 크기의 아이콘과 텍스트로 항목 표시 서브 항목으로 부가적인 정보 표시 헤더 컨트롤로 각 열의 폭 조절과 항목 정렬 가능 헤더 컨트롤 항목 서브 항목
리스트 컨트롤 (3/3) 리스트 컨트롤 스타일
리스트 컨트롤 클래스 (1/17) 리스트 컨트롤 생성과 초기화 CListCtrl 객체 선언 후 CListCtrl::Create()로 리스트 컨트롤 생성 CListCtrl::InsertColumn()으로 보고서 보기에서 표시할 헤더 초기화 CListCtrl::InsertItem()으로 항목 추가 CListCtrl::SetItemText()로 하위 항목 초기화
리스트 컨트롤 클래스 (2/17) 예제 코드 // ① CListCtrl 객체 선언과 리스트 컨트롤 생성 CListCtrl m_list; m_list.Create(WS_CHILD|WS_VISIBLE|WS_BORDER|LVS_REPORT, CRect(0, 0, 300, 100), this, IDC_LIST1); // ② 헤더 초기화 m_list.InsertColumn(0, "이름", LVCFMT_LEFT, 100); m_list.InsertColumn(1, "성적", LVCFMT_LEFT, 100); m_list.InsertColumn(2, "학점", LVCFMT_LEFT, 100);
리스트 컨트롤 클래스 (4/17) 예제 코드 (cont'd) // ③ 항목 추가 m_list.InsertItem(0, "김철수", 0); m_list.InsertItem(1, "이영희", 0); m_list.InsertItem(2, "박선아", 0); // ④ 하위 항목 추가 m_list.SetItemText(0, 1, "90"); m_list.SetItemText(0, 2, "A"); m_list.SetItemText(1, 1, "95"); m_list.SetItemText(1, 2, "A+"); m_list.SetItemText(2, 1, "70"); m_list.SetItemText(2, 2, "B0");
리스트 컨트롤 클래스 (5/17) 주요 함수 dwStyle: 컨트롤 스타일을 지정. 일반 윈도우 스타일(WS_*)과 리스트 컨트롤 스타일(LVS_*)의 조합을 사용 rect: 컨트롤의 크기와 위치 pParentWnd: 부모 윈도우 nID: 컨트롤 ID BOOL CListCtrl::Create (DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
리스트 컨트롤 클래스 (7/17) 주요 함수 (cont'd) nCol: 열 번호를 나타내며 0부터 시작 lpszColumnHeading: 헤더 컨트롤에 표시할 텍스트 nFormat: 헤더 컨트롤에 표시할 텍스트의 정렬 방식을 나타내며 LVCFMT_LEFT(왼쪽), LVCFMT_RIGHT(오른쪽), LVCFMT_CENTER(가운데) 중 하나를 선택 nWidth: 열의 폭(픽셀 단위) nSubItem: 연관된 하위 항목의 인덱스를 나타내며, 보통 nCol과 같은 값을 사용 int CListCtrl::InsertColumn (int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1);
리스트 컨트롤 클래스 (8/17) 주요 함수 (cont'd) nItem: 항목 인덱스이며 0부터 시작 lpszItem: 항목에 표시할 텍스트 nImage: 항목에 표시할 이미지로서 이미지 리스트에서의 인덱스 값을 사용 int CListCtrl::InsertItem (int nItem, LPCTSTR lpszItem, int nImage);
리스트 컨트롤 클래스 (9/17) 주요 함수 (cont'd) nItem: 항목 인덱스이며 0부터 시작 nSubItem: 하위 항목 인덱스이며 1부터 시작. 0을 사용하면 항목 텍스트 변경 가능 lpszText: 하위 항목(nSubItem>0) 또는 항목(nSubItem=0)에 표시할 텍스트 BOOL CListCtrl::SetItemText (int nItem, int nSubItem, LPCTSTR lpszText);
리스트 컨트롤 클래스 (10/17) 표준 스타일(LVS_*) 변경하기 dwRemove: 제거할 스타일 dwAdd: 추가할 스타일 nFlags: 기본값 사용 BOOL CWnd::ModifyStyle (DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0); // 아이콘 보기로 변경한다. m_list.ModifyStyle(LVS_TYPEMASK, LVS_ICON); // 레이블 편집을 가능하게 한다. m_list.ModifyStyle(0, LVS_EDITLABELS);
리스트 컨트롤 클래스 (11/17) 확장 스타일(LVS_EX_*) 변경하기 dwNewStyle : 새로 적용할 확장 스타일 DWORD CListCtrl::SetExtendedStyle (DWORD dwNewStyle); // 보고서 보기에서 격자 무늬를 표시한다. m_list.SetExtendedStyle(m_list.GetExtendedStyle()| LVS_EX_GRIDLINES); // 보고서 보기에서 항목을 선택하면 줄 전체가 선택되도록 한다. m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT);
리스트 컨트롤 클래스 (12/17) 선택 항목 알아내기 - 마우스 또는 키보드로 새로운 항목을 선택한 경우 메시지 맵을 통해 메시지를 받고, 메시지 핸들러를 통해 내용을 구현 // 메시지맵 ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnItemchangedList1) // 메시지 핸들러 모양 void CExListCtrlView::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult) {…}
리스트 컨트롤 클래스 (14/17) 선택 항목 알아내기 – NMLISTVIEW 구조체 typedef struct tagNMLISTVIEW { NMHDR hdr; // information about message int iItem; // 이벤트를 발생시킨 아이템번호 int iSubItem; // 이벤트를 발생시킨 서브아이템 UINT uNewState; // 발생한 변화 (LVIS_SELECTED) UINT uOldState; // 이전의 상태 UINT uChanged; // 변화된 대상 (LVIF_STATE) POINT ptAction; // 이벤트가 일어난 장소 LPARAM lParam; } NMLISTVIEW, *LPNMLISTVIEW;
리스트 컨트롤 클래스 (13/17) 선택 항목 알아내기 – 메시지 핸들러 void CExListCtrlView::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult) { NMLISTVIEW* pNMLV = (NMLISTVIEW*) pNMHDR; if(pNMLV->uChanged & LVIF_STATE) { if(pNMLV->uNewState & (LVIS_SELECTED|LVIS_FOCUSED)) { CString str = m_list.GetItemText(pNMLV->iItem, 0); AfxGetMainWnd()->SetWindowText(str); } *pResult = 0;
리스트 컨트롤 클래스 (16/17) 선택 항목 알아내기 - 선택된 다수 개의 항목을 조사하는 경우 void CExListCtrlView::PrintSelectedItemIndex() { POSITION pos = m_list.GetFirstSelectedItemPosition(); if(pos != NULL) { while(pos) { int nItem = m_list.GetNextSelectedItem(pos); TRACE("항목 %d번이 선택되었습니다.\n", nItem); }
리스트 컨트롤 클래스 (17/17) 항목 추가와 삭제 항목 추가 항목 삭제 CListCtrl::InsertItem() 하나의 항목을 삭제하려면 CListCtrl::DeleteItem(), 모든 항목을 삭제하려면 CListCtrl::DeleteAllItems() 사용 // 첫 번째 항목 삭제 m_list.DeleteItem(0); // 모든 항목 삭제 m_list.DeleteAllItems();
리스트 뷰 (1/3) CListView 클래스 리스트 컨트롤을 이용한 사용자 인터페이스 제공 리스트 컨트롤
리스트 뷰 (2/3) CListView 클래스 사용 예 // 리스트 컨트롤 객체에 대한 참조값(CListCtrl 타입)을 얻는다. CListCtrl& list = GetListCtrl(); // 참조 변수를 이용하여 리스트 컨트롤을 다룬다. list.SetImageList(...); list.InsertColumn(...); ...
리스트 뷰 (3/3) MFC 클래스 계층도
Tree Control
트리 컨트롤 (1/2) 트리 컨트롤 = 트리 뷰 컨트롤 이미지와 텍스트를 이용하여 계층적인 형태로 정보를 표시하는 용도로 사용
트리 컨트롤 (2/2) 용어 항목 부모 항목 자식 항목 루트 항목 트리 컨트롤에 표시되는 하나의 정보 하나 이상의 하위 항목을 가진 항목 자식 항목 부모 항목에 딸린 하위 항목 루트 항목 계층 구조에서 최상위 항목 루트 항목은 부모 항목을 가지지 않음
그 동안 배운 것들 MFC 구조 MFC로 그림 그리기(GDI, DC) 마우스와 키보드 타이머 메뉴와 툴바/상태바 FILE Input/Output Controls Dialog Box Document/View Architecture (SDI/MDI)
한 학기 동안 수고하셨습니다. 기말고사: 6월16일 수업시간/수업장소 점수(학점)공고: 6월17일 23:59(홈페이지) 이의신청기간: 6월20일(월)~6월21일(화) 연구실로 찾아 올 것