7 장. 대화상자컨트롤 (2) 1
1. 버튼컨트롤 2 학습목표버튼컨트롤들을포함한다이얼로그박스를만들어본다 소스 : "07-1 Ctrl1.zip" 다이얼로그박스만들기 1 Ctrl1 라는이름의 Dialog based 프로젝트를생성한다 2 IDD_CTRL1_DIALOG 다이얼로그박스리소스수정
3 3 컨트롤아이디지정컨트롤 ID 컨트롤유형 캡션 IDC_STATIC Static control Number IDC_RADIO_ZERO Radio Button &Zero IDC_RADIO_ONE Radio ONE &One IDC_CHECK_TWO Checkbox &Two IDC_BUTTON_THREE Pushbutton T&hree 3 Radio 버튼그룹에서선두 Radio 버튼만 Group 프로퍼티값이세팅되어있어야한다. 탭순서지정 다이얼로그박스에서탭키를누르면포커스가다른컨트롤로이동한다. 이이동순서를탭순서라고부른다. 메뉴의 Layout Tab Order 선택하고, 컨트롤들을순서대로클릭한다.
4 멤버변수와컨트롤연결 1 ClassWizard의 Member Variables 페이지에서컨트롤마다멤버변수 를추가한다 Control ID Name Category Type IDC_RADIO_ZERO m_vzero Value int IDC_RADIO_ZERO m_czero Control CButton IDC_CHECK_TWO m_vtwo Value BOOL IDC_CHECK_TWO m_ctwo Control CButton IDC_BUTTON_THREE m_cthree Control CButton
5 Radio 버튼은그룹의선두버튼만 ClassWizard의 Member Variable 페이지에서볼수있다. 따라서 IDC_ONE Radio 버튼은 ClassWizard의 Member Variable 페이지에서볼수없다. Radio 버튼과 Check Box 버튼각각에대하여멤버변수 2개를연결하였다. 하나는값, 하나는 C++ 클래스이다. 단지값만알고자할때는값으로연결된멤버변수를읽으면되므로편하다. 컨트롤에게어떤명령을내릴때는 C++ 클래스를이용하면편하다.
6 다이얼로그클래스에버튼이벤트첨가 버튼이눌릴때어떤반응이일어나게하려면, 다이얼로그클래스에메시지처리함수를첨가해주어야한다. 1 ClassWizard의 Message Maps 페이지에서 Class Name: CCtrl1Dlg Object ID: IDC_BUTTON_THREE Message: BN_CLICKED 2 Add Function 버튼을누르고 OnButtonThree 함수이름을확인 3 다음과같이입력하고실행해보자
void CCtrl1Dlg::OnButtonThree() CString name; m_cthree.getwindowtext(name); if (name == "T&hree") m_czero.setwindowtext("&zero"); m_ctwo.setwindowtext("&two"); m_cthree.setwindowtext("t&hree"); SetWindowText("DIALOG"); GetDlgItem(IDOK)->SetWindowText("OK"); GetDlgItem(IDCANCEL)->SetWindowText("CANCEL"); GetDlgItem(IDC_RADIO_ONE)->SetWindowText("&ONE"); else m_czero.setwindowtext("&zero"); m_ctwo.setwindowtext("&two"); m_cthree.setwindowtext("t&hree"); SetWindowText("Dialog"); GetDlgItem(IDOK)->SetWindowText("Ok"); GetDlgItem(IDCANCEL)->SetWindowText("Cancel"); GetDlgItem(IDC_RADIO_ONE)->SetWindowText("&One"); 7
8 컨트롤들도기본적으로윈도우이다. MFC 클래스라이브러리측면에서얘기하자면컨트롤클래스들은 CWnd 클래스의하위클래스이다. 따라서 CWnd 클래스의멤버함수인 SetWindowText나 GetWindowText를사용할수있다. SetWindowText 멤버함수를호출하여컨트롤의캡션을변경하여보았다. CWnd 클래스의멤버함수인 GetDlgItem(ID) 는파라미터로컨트롤의 ID를주면그컨트롤에대한포인터를리턴한다.
9 4 다음과같이입력하고실행해보자 void CCtrl1Dlg::OnButtonThree() if (m_czero.iswindowenabled()) m_czero.enablewindow(false); m_ctwo.enablewindow(false); GetDlgItem(IDOK)->EnableWindow(FALSE); GetDlgItem(IDCANCEL)->EnableWindow(FALSE); GetDlgItem(IDC_RADIO_ONE)->EnableWindow(FALSE); else m_czero.enablewindow(true); m_ctwo.enablewindow(true); GetDlgItem(IDOK)->EnableWindow(TRUE); GetDlgItem(IDCANCEL)->EnableWindow(TRUE); GetDlgItem(IDC_RADIO_ONE)->EnableWindow(TRUE); CWnd 클래스의멤버함수인 EnableWindow() 를사용하여컨트롤을활성화, 비활성화시킬수있다.
10 5 다음과같이입력하고실행해보자 void CCtrl1Dlg::OnButtonThree() if (m_czero.iswindowvisible()) m_czero.showwindow(sw_hide); m_ctwo.showwindow(sw_hide); GetDlgItem(IDOK)->ShowWindow(SW_HIDE); GetDlgItem(IDCANCEL)->ShowWindow(SW_HIDE); GetDlgItem(IDC_RADIO_ONE)->ShowWindow(SW_HIDE); else m_czero.showwindow(sw_show); m_ctwo.showwindow(sw_show); GetDlgItem(IDOK)->ShowWindow(SW_SHOW); GetDlgItem(IDCANCEL)->ShowWindow(SW_SHOW); GetDlgItem(IDC_RADIO_ONE)->ShowWindow(SW_SHOW); CWnd 클래스의멤버함수인 ShowWindow() 를사용하여컨트롤을보이게또는안보이게할수있다.
11 void CCtrl1Dlg::OnButtonThree() UpdateData(TRUE); CString str; str.format(" m_vzero = %d\n\n m_vtwo AfxMessageBox(str); = %d", m_vzero, m_vtwo); 단순히사용자가입력한값만알고자할때는값으로연결된멤버변수가편리하다.
2. 리스트박스컨트롤 12 학습목표버튼컨트롤들을포함한다이얼로그박스를만들어본다 소스 : "07-2 Ctrl2.zip" 다이얼로그박스만들기 1 Ctrl2 라는이름의 Dialog based 프로젝트를생성한다 2 IDD_CTRL2_DIALOG 다이얼로그박스리소스수정
13 3 컨트롤아이디지정컨트롤 ID 컨트롤유형 캡션 IDC_LIST1 List Box IDC_BUTTON1 Pushbutton << IDC_EDIT1 Edit Box 멤버변수와컨트롤연결 1 ClassWizard의 Member Variables 페이지에서컨트롤마다멤버변수 를추가한다 Control ID Name Category Type IDC_LIST1 m_list Control CListBox IDC_EDIT1 m_edit Value CString
14 다이얼로그클래스에버튼이벤트첨가 1 ClassWizard의 Message Maps 페이지에서 Class Name: CCtrl2Dlg Object ID: IDC_BUTTON1 Message: BN_CLICKED 2 Add Function 버튼을누르고 OnButton1 함수이름을확인 3 ClassWizard의 Message Maps 페이지에서 Class Name: CCtrl2Dlg Object ID: IDC_LIST1 Message: LBN_DBLCLK 4 Add Function 버튼을누르고 OnDblclkList1 함수이름을확인
15 5 다음과같이입력하고실행해보자 void CCtrl2Dlg::OnButton1() UpdateData(TRUE); m_list.addstring(m_edit); void CCtrl2Dlg::OnDblclkList1() m_list.deletestring( m_list.getcursel() );
3. 콤보박스컨트롤 16 학습목표콤보박스컨트롤들을포함한다이얼로그박스를만들어본다 소스 : "07-3 Ctrl3.zip" 다이얼로그박스만들기 1 Ctrl3 라는이름의 Dialog based 프로젝트를생성한다 2 IDD_CTRL3_DIALOG 다이얼로그박스리소스수정
17 3 컨트롤아이디와프러퍼티 지정 컨트롤 ID 컨트롤유형 Type IDC_LIST1 List Box IDC_COMBO1 Combo Box Simple IDC_COMBO2 Combo Box Drop down IDC_COMBO3 Combo Box Drop list IDC_BUTTON1 Pushbotton 4 Sort 프러퍼티를전부 clear 한다
18 멤버변수와컨트롤연결 1 ClassWizard의 Member Variables 페이지에서컨트롤마다멤버변수 를추가한다 Control ID Name Category Type IDC_LIST1 m_list1 Value CString IDC_COMBO1 m_combo1 Value CString IDC_COMBO2 m_combo2 Value CString IDC_COMBO3 m_combo3 Value CString
19 콤보박스컨트롤에항목입력 1 IDC_COMBO1 콤보박스컨트롤을더블클릭하여프로퍼티다이얼로그를열고 2 Enter listbox Items: 아래그림과같이입력 3 줄바꾸는키는 Ctrl-Enter 이다.
20 다이얼로그클래스에버튼이벤트첨가 1 ClassWizard의 Message Maps 페이지에서 Class Name: CCtrl3Dlg Object ID: IDC_BUTTON1 Message: BN_CLICKED 2 Add Function 버튼을누르고 OnButton1 함수이름을확인
21 다음과같이입력 BOOL CCtrl3Dlg::OnInitDialog() // 중간생략... // TODO: Add extra initialization here CComboBox* p = (CComboBox*)GetDlgItem(IDC_COMBO1); for (int i=0; i < p->getcount(); ++i) CString s; p->getlbtext(i,s); ((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString(s); ((CComboBox*)GetDlgItem(IDC_COMBO3))->AddString(s); ((CListBox*)GetDlgItem(IDC_LIST1))->AddString(s); return TRUE; // return TRUE unless you set the focus to a control
22 void CCtrl3Dlg::OnButton1() CString s; UpdateData(TRUE); s.format(" LIST1 = %s\n COMBO1 = %s\n COMBO2 = %s\n COMBO3 = %s", m_list1, m_combo1, m_combo2, m_combo3); AfxMessageBox(s);
4. 프로그래스컨트롤, 슬라이더컨트롤 23 소스 : "07-4 Ctrl4.zip" 다이얼로그박스만들기 1 Ctrl4 라는이름의 Dialog based 프로젝트를생성한다 2 IDD_CTRL4_DIALOG 다이얼로그박스리소스수정 3 컨트롤아이디와프러퍼티지정컨트롤 ID 컨트롤유형 IDC_PROGRESS1 Progress IDC_SLIDER1 Slider
24 멤버변수와컨트롤연결 1 ClassWizard의 Member Variables 페이지에서컨트롤마다멤버변수를추가한다 Control ID Name Category Type IDC_PROGRESS1 m_progress Control CProgressCtrl IDC_SLIDER1 m_slider Control CSliderCtrl 다이얼로그클래스에버튼이벤트첨가 1 ClassWizard의 Message Maps 페이지에서 Class Name: CCtrl4Dlg Object ID: CCtrl4Dlg Message: WM_HSCROLL 2 Add Function 버튼을누르고 OnHScroll 함수이름을확인
25 다음과같이입력 BOOL CCtrl4Dlg::OnInitDialog() // 중간생략.. // TODO: Add extra initialization here m_slider.setrange(0,100); m_progress.setrange(0,100); return TRUE; // return TRUE unless you set the focus to a control void CCtrl4Dlg::OnHScroll(UINT nsbcode, UINT npos, CScrollBar* pscrollbar) m_progress.setpos( m_slider.getpos() );
26 슬라이더컨트롤은스크롤바와유사한기능을제공하며좀더간편하게사용할수있다. 슬라이더컨트롤은 WM_HSCROLL이나 WM_VSCROLL 메시지를부모윈도우에게보낸다. 프로그래스컨트롤은작업진행상황을표시하는데사용된다.
5. 트리뷰 (Tree View) 27 학습목표트리뷰를메인뷰로갖는어플리케이션을생성한다. 소스 : "07-5 TreeView.zip" 트리뷰만들기 1 AppWizard를이용하여 TreeView란이름의 Dialog-based 어플리케이션생성 2 CTreeView 클래스를상속받아어플리케이션의메인뷰를정의한다.
28 3 다음입력후실행 void CTreeViewView::OnInitialUpdate() CTreeView::OnInitialUpdate(); CTreeCtrl& tree = GetTreeCtrl(); HTREEITEM h = tree.insertitem( "One"); tree.insertitem( "Two", h ); tree.insertitem( "Three", h ); tree.insertitem( "Four", h ); h = tree.insertitem( "Five"); tree.insertitem( "Six", h ); tree.insertitem( "Seven", h ); tree.insertitem( "Eight", h ); BOOL CTreeViewView::PreCreateWindow(CREATESTRUCT& cs) cs.style = (TVS_HASLINES TVS_LINESATROOT TVS_HASBUTTONS); return CTreeView::PreCreateWindow(cs);
29 CTreeView에항목채우기 CTreeView 클래스는 CView 클래스의하위클래스이고트리뷰컨트롤을포함하고있다. CTreeView::GetTreeCtrl() 멤버함수는트리뷰컨트롤의레퍼런스를리턴한다. 트리뷰컨트롤의멤버함수를호출하여컨트롤에아이템을추가한다. 트리뷰컨트롤의 InsertItem() 멤버함수를이용하여항목을추가한다. 첫파라미터는추가할항목이고두번째파라미터는추가되는항목이위치할부모노드핸들이다. 트리뷰의몇몇스타일을설정하기위해 CTreeViewView::PreCreateWindow 함수를오버라이드하여구현하였다.
30 트리뷰윈도우스타일 TVS_HASLINES 부모아이템과자식아이템간을라인으로연결한다. TVS_LINESATROOT 트리컨트롤의루트아이템들을위한라인을제공한다. TVS_HASLINES 속성이같이있어야효과가있다. TVS_HASBUTTONS 는아이템앞에플러스나마이너스기호버튼을제공한다. TVS_EDITLABELS 사용자가트리뷰아이템라벨을편집할수있게한다.
6. 트리컨트롤 (Tree Control) 31 학습목표대화상자에트리콘트롤을포함시켜보자 소스 : "07-6 TreeCtrl.zip" 트리컨트롤만들기 1 AppWizard를이용하여 TreeCtrl란이름의 SDI 어플리케이션생성 2 IDB_BITMAP1 이라는이름의 14 x 28 비트맵을작성한다.
32 3 아래와같이다이얼로그박스에트리컨트롤을포함시킨다 트리컨트롤의 ID 는 IDC_TREE 프로퍼티설정은 Has Lines, Line at Root, Has Buttons 4 ClassWizard 를이용하여 IDC_TREE 와연결된멤버변수추가 IDC_TREE CTreeCtrl m_treectrl 5 CTreeCtrlDlg 클래스의 protected 영역에멤버변수추가 CImageList m_imagelist;
33 5 다음입력 BOOL CTreeCtrlDlg::OnInitDialog() CDialog::OnInitDialog(); // 중간생략... // TODO: Add extra initialization here m_imagelist.create( IDB_BITMAP1, 14, 1, RGB(255,255,255)); m_treectrl.setimagelist( &m_imagelist, TVSIL_NORMAL ); HTREEITEM h; h = m_treectrl.insertitem( "One", 0, 0 ); m_treectrl.insertitem( "Two", 1, 1, h ); m_treectrl.insertitem( "Three", 1, 1, h ); m_treectrl.insertitem( "Five", 1, 1, h ); h = m_treectrl.insertitem( "Six", 0, 0 ); m_treectrl.insertitem( "Seven", 1, 1, h ); m_treectrl.insertitem( "Eight", 1, 1, h ); m_treectrl.insertitem( "Nine", 1, 1, h ); return TRUE; // return TRUE unless you set the focus to a control
34 트리뷰컨트롤의프러퍼티 Has Buttons : 컨트롤에버튼을포함시킨다. 하위레벨을확장할수있는항목의왼쪽에버튼이그려진다. Has Lines : 컨트롤에항목들을연결하는선을포함시킨다. Line at Root : 컨트롤의첫번째단계의항목들을연결하는선을포함시킨다. Edit Labels : 사용자가컨트롤에있는레이블을변경할수있게한다. Disable Drag Drop : 트리컨트롤에포함된항목의드래그-드롭을막는다 Show Selection Always : 선택된항목을하이라이트하여표시한다.
35 항목추가 m_treectrl.insertitem( One, 1, 1, h ); 첫번째파라미터는추가되는함목의레이블이다. 두번째파라미터는선택되지않은경우표시되는아이콘 세번째파라미터는선택된경우표시되는아이콘 마지막파리미터는부모항목의핸들
7. 트리컨트롤에서드래그드롭 36 학습목표앞에서만든트리콘트롤에드래그드롭 (drag drop) 기능을추가 소스 : "07-6 TreeCtrl.zip" 메시지처리함수추가 1 ClassWizard를이용하여다음객체의메시지처리함수작성 Object ID Message Function IDC_TREE TVN_BEGINDRAG OnBegindragTree CTreeCtrlDlg WM_MOUSEMOVE OnMouseMove CTreeCtrlDlg WM_LBUTTONUP OnLButtonUp 2 CTreeCtrlDlg 클래스의 protected 영역에멤버변수추가 HTREEITEM m_dragitem;
37 3 다음입력 void CTreeCtrlDlg::OnBegindragTree(NMHDR* pnmhdr, LRESULT* presult) NM_TREEVIEW* pnm = (NM_TREEVIEW*)pNMHDR; m_dragitem = pnm->itemnew.hitem; if (m_treectrl.getparentitem(m_dragitem)!= NULL) CImageList* pimg = m_treectrl.createdragimage( m_dragitem ); m_treectrl.selectitem( m_dragitem ); pimg->begindrag(0, CPoint(0,0)); pimg->dragenter( &m_treectrl, pnm->ptdrag ); SetCapture(); *presult = 0;
void CTreeCtrlDlg::OnMouseMove(UINT nflags, CPoint point) if (GetCapture() == this) MapWindowPoints( &m_treectrl, &point, 1 ); CImageList::DragMove( point ); 38
void CTreeCtrlDlg::OnLButtonUp(UINT nflags, CPoint point) if (GetCapture() == this) ReleaseCapture(); CImageList::DragLeave(&m_treeCtrl); CImageList::EndDrag(); UINT uhittest = TVHT_ONITEM; HTREEITEM target = m_treectrl.hittest( point, &uhittest); if (target!= NULL) HTREEITEM h; h = m_treectrl.getparentitem(target); CString szlabel = m_treectrl.getitemtext( m_dragitem ); if (h!= NULL) m_treectrl.insertitem( szlabel, 1, 1, h, target ); else m_treectrl.insertitem( szlabel, 1, 1, target, TVI_FIRST); m_treectrl.deleteitem(m_dragitem ); 39
40 드래그가시작되면트리컨트롤은부모윈도우에게 TVN_BEGINDRAG 메시지를보낸다. 이메시지를 CTreeCtrlDlg::OnBeginDragTree 멤버함수에서받아처리한다. 드래그항목의핸들을 m_dragitem에저장한다. GetParentItem 함수를호출하여부모항목핸들을얻는다. NULL 이면루트항목이라는뜻이고위예제에서는루트항목의드래그는처리하지않는다. CreateDragImage 함수를호출하여드래그이미지리스트를만든다. 드래그의시작은 BeginDrag, 이동은 DragMove, 종료는 EndDrag 이다. DragEnter는윈도우에락을설정하여윈도우가갱신되지못하게하고드래그이미지가표시될수있게한다. DragLeave는락을해제한다. 드래그하는동안 WM_MOUSEMOVE 메시지가부모윈도우로보내지고사용자가마우스버튼을놓으면 WM_MOUSEUP 메시지가보내진다. 새위치에항목을삽입하고이전항목은제거하여드롭의효과를얻는다. CTreeCtrl::HitTest를호출하여마우스포인터가어느항목을가리키고있는지조사한다.
8. Graphs 수정 - Update Hint 41 목표화면에그리는기능을좀더효율적으로최적화한다. 소스 : "07-7 Graphs.zip"
42 UpdateAllViews 개선 CRectangle* CGraphsDoc::AddRect(CRect rect) CRectangle r(rect, m_width, m_pencolor, m_brushcolor); m_rects.add(r); UpdateAllViews(NULL); SetModifiedFlag(TRUE); return &m_rects[m_rects.getsize()-1]; void CGraphsView::OnLButtonUp(UINT nflags, CPoint point) if (GetCapture() == this) CGraphsDoc* pdoc = (CGraphsDoc*)GetDocument(); ReleaseCapture(); CRectangle* r = pdoc->addrect(makerect(m_point1,m_point2)); m_point1 = m_point2 = CPoint(0,0); pdoc->updateallviews(this, 0, r);
44 도큐먼트내용이변경되었을때 CDocument::UpdateAllViews() 를호출하여연결된모든뷰에게이사실을통보한다. 이때각뷰의OnUpdate() 멤버함수가호출된다. UpdateAllviews() 의파라미터가그대로 OnUpdate() 에전달되는데세번째파라미터는다시그리는작업을최소화할수있기위한정보를전달하는것이목적이다. 아무런정보를얻을수없다면전체를다시그릴수밖에없다. 위에서는추가된선에대한포인터를전달하여그부분만다시그릴수있도록하였다.
9. 스크롤뷰 (ScrollView) 45 학습목표 Graphs 뷰에스크롤기능을추가한다 ScrollView를상속하여구현한다. 소스 : "07-8 Graphs.zip" CScrollView 클래스를상속 1 CLine1View 클래스의상위클래스변경 class CGraphsView : public CScrollView IMPLEMENT_DYNCREATE(CGraphsView, CScrollView) BEGIN_MESSAGE_MAP(CGraphsView, CScrollView)
46 2 ClassWizard 에서 CGraphsView 클래스의 OnInitialUpdate() MFC 버추얼메소드작성 void CGraphsView::OnInitialUpdate() SetScrollSizes( MM_TEXT, CSize(2000, 2000)); 실행시켜본다 스크롤바를움직여서화면의다른쪽으로움직인다음화면안쪽에서바깥쪽으로선을그리면선이끊어져보인다. 좌표계변화을해주어야한다.
47 좌표계변환 1 다음과같이수정한다. void CGraphsView::OnLButtonDown(UINT nflags, CPoint point) CClientDC dc(this); OnPrepareDC(&dc); dc.dptolp(&point); m_point1 = point; m_point2 = point; SetCapture(); void CGraphsView::OnLButtonUp(UINT nflags, CPoint point) if (GetCapture() == this) CClientDC dc(this); OnPrepareDC(&dc); dc.dptolp(&point); CGraphsDoc* pdoc = (CGraphsDoc*)GetDocument(); ReleaseCapture(); CRectangle* r = pdoc->addrect(makerect(m_point1,m_point2)); m_point1 = m_point2 = CPoint(0,0); pdoc->updateallviews(this, 0, r);
void CGraphsView::OnMouseMove(UINT nflags, CPoint point) CClientDC dc(this); OnPrepareDC(&dc); dc.dptolp(&point); CGraphsDoc* pdoc = (CGraphsDoc*)GetDocument(); if (GetCapture() == this) int w = pdoc->m_width; CRect r = MakeRect(m_point1,m_point2); r.inflaterect(w,w,w,w); dc.lptodp(&r); InvalidateRect(r); m_point2 = point; r = MakeRect(m_point1,m_point2); r.inflaterect(w,w,w,w); dc.lptodp(&r); InvalidateRect(r); 48
for (int i = pdoc->m_rects.getsize()-1; i>=0; --i) CRectangle* r = &pdoc->m_rects[i]; if (r->ptinobject(point)) if (r!= m_ptinrect) if (m_ptinrect!= NULL) CRect rect = m_ptinrect->boundrect(); dc.lptodp(&rect); InvalidateRect(rect); m_ptinrect = r; CRect rect = m_ptinrect->boundrect(); dc.lptodp(&rect); InvalidateRect(rect); return; if (m_ptinrect!= NULL) CRect rect = m_ptinrect->boundrect(); dc.lptodp(&rect); InvalidateRect(rect); m_ptinrect = NULL; 49
void CGraphsView::OnUpdate(CView* psender, LPARAM lhint, CObject* phint) if (phint!= NULL) if (phint->iskindof(runtime_class(crectangle))) CRectangle* r = (CRectangle*)pHint; CRect rect = r->boundrect(); CClientDC dc(this); OnPrepareDC(&dc); dc.lptodp(&rect); InvalidateRect(rect); return; Invalidate(); 50
51 CScrollView 스크롤바때문에 OnDraw 멤버함수를변경해야할필요는없다. 논리좌표계의원점 (0,0) 을변경시켜서 Scroll 효과를주기때문이다. MFC에서원점변경은 OnPrepareDC() 에서수행하는것이적당하다. OnPrepareDC() CView 클래스의멤버함수이다. OnDraw() 가호출되기전 Device Context를초기화하기위해서호출된다. CScrollView 클래스의 OnPrepareDC() 는좌표계의원점을설정한다.
52 좌표변환의필요성 GDI 함수 (CDC 클래스의메소드 ) 들은논리좌표계를사용하고아니면물리좌표계를사용한다. 예를들면 WM_LBUTTONDOWN과같은마우스메시지도마우스포인터의위치를에물리좌표계로전달한다 마우스포인터좌표를입력받아선을그릴때 CDC 메소드를사용하므로논리좌표계를사용하게된다. 이경우논리좌표계와물리좌표계사이에변환의필요성이발생한다. 무효화메소드 CWin::InvalidateRect() 는 CDC 메소드가아니므로물리좌표계를사용해야한다. CDC 클래스의좌표변환멤버함수는 LPtoDP(CPoint*) 논리좌표를물리좌표로변환 DPtoLP(CPoint*) 물리좌표를논리좌표로변환
10. Splitter 윈도우 53 학습목표 Graphs 의윈도우에 Splitter 윈도우를추가한다 소스 : "07-9 Graphs.zip" Splitter 윈도우 Splitter 윈도우는크기조정가능한여러창으로구성되어있다. 각창은내부에뷰를포함한다. Static Splitter의각창은다른뷰클래스일수있고창의수는미리결정되어고정된다 Dynamic Splitter의각창은동일한뷰클래스만을포함해야하지만창의수에는제한이없다 AppWizard 로어플리케이션의골격을자동생산할때 "Use Splitter Option" 을선택하면 Splitter 생성코드가저절로만들어진다
54 Splitter 윈도우추가 1 CChildFrame클래스에멤버변수추가 Add Member Variable 대화상자에서 Variable Type: CSplitterWnd Name: m_wndsplitter Access Area: Protected 2 WizardBar 나 ClassWizard 에서 CChildFrame 클래스의 OnCreateClient 멤버함수를추가 BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pcontext) return m_wndsplitter.create(this, 2, 2, CSize(10, 10), pcontext);
55 CChildFrame::OnCreateClient() 는윈도우가생성될때호출된다. CSplitterWnd::Create() 의 2 번째 3 번째파라미터는 Splitter 윈도우갖을수있는최대행과열수, 4 번째파라미터는 Pane 의최소크기, 5 번째파라미터는 CCreateContext 구조체이고 Pane 에생성할뷰클래스를지정한다.
11. Spin 컨트롤 56 학습목표 Spin 컨트롤을사용하여 Graphs 의다이얼로그박스를개선한다 소스 : "07-10 Graphs.zip" 다이얼로그박스수정 1 Graphs 프로젝트를연다 2 IDD_LINE_WIDTH 다이얼로그박스를아래와같이수정탭순서를아래와같이설정해야한다
57 3 Spin 컨트롤의프로퍼티를다음과같이설정 4 ClassWizard를사용하여 Spin 컨트롤을멤버변수로연결 Control ID : IDC_SPIN1 Type : CSpinButtonCtrl Member : m_spin
58 5 ClassWizard를사용하여 IDD_LINE_WIDTH 다이얼로그박스에멤버함수작성 Object ID : CLineWidthDlg Message : WM_INITDIALOG Member Function : OnInitDialog 6 다음입력후실행 BOOL CLineWidthDlg::OnInitDialog() CDialog::OnInitDialog(); m_spin.setrange(1,30); return TRUE;
59 Spin 컨트롤의프로퍼티 Orientation : Spin 컨트롤이수직인가또는수평인가를나타낸다. 디폴트는수직이다. Alignment : 버디컨트롤과 Spin 컨트롤이서로어떻게결합될것인가를지정한다. 즉 Right를선택하면버디컨트롤의오른쪽에 Spin 컨트롤이붙어있게된다. Auto Buddy : 이프로퍼티를설정하면탭순서에서 spin 컨트롤바로앞에있는컨트롤을버디컨트롤로사용한다. Set Buddy Integer : 버디컨트롤의값이정수라면, 이프로퍼티를설정한경우 Spin 컨트롤이버디컨트롤의값을저절로변경해줄수있다. No Thousands : 1000 자리구분콤마사용여부지정 Arrow Key : 화살표키를이용하여값을바꿀수있는지여부지정