fdd62877661a954149bbc75de3523ddd.ppt
- Количество слайдов: 151
Chap. 8 Advanced Document/View
Contents v v v CDocument Internal CView Printing CView Print Preview CScroll. View CCtrl. View
CDocument Internal v CDocument에서의 file작업 Ø Ø MFC 4. 0 Get. File(), Release. File() 함수를 이용 BOOL CDocument: : On. Open. Document(LPCTSTR lpsz. Path. Name) { CFile* p. File = Get. File(lpsz. Path. Name, CFile: : mode. Read|CFile: : share. Deny. Write, &fe); Delete. Contents(); Set. Modified. Flag(); // dirty during de-serialize Carchive load. Archive (p. File, CArchive: : load|CArchive: : b. No. Flush. On. Delete); Serialize(load. Archive); // load me load. Archive. Close(); Release. File(p. File, FALSE); Set. Modified. Flag(FALSE); // start off with unmodified return TRUE; }
CDocument Internal (cont’d) BOOL CDocument: : On. Save. Document(LPCTSTR lpsz. Path. Name) { CFile* p. File = NULL; p. File = Get. File(lpsz. Path. Name, CFile: : mode. Create | CFile: : mode. Read. Write | CFile: : share. Exclusive, &fe); CArchive save. Archive (p. File, CArchive: : store | CArchive: : b. No. Flush. On. Delete); Serialize(save. Archive); // save me save. Archive. Close(); Release. File(p. File, FALSE); Set. Modified. Flag(FALSE); // back to unmodified return TRUE; } // success
CDocument Internal (cont’d) CFile* CDocument: : Get. File(LPCTSTR lpsz. File. Name, UINT n. Open. Flags, CFile. Exception* p. Error) { CMirror. File* p. File = new CMirror. File; if (!p. File->Open(lpsz. File. Name, n. Open. Flags, p. Error)) { delete p. File; p. File = NULL; } return p. File; }
CMirror. File v v 왜 CFile을 쓰지 않고 CMirror. File을? CMirror. File class Ø Declaration(AFXPRIV. H) class CMirror. File : public CFile { // Implementation public: virtual void Abort(); virtual void Close(); virtual BOOL Open(LPCTSTR lpsz. File. Name, UINT n. Open. Flags, CFile. Exception* p. Error = NULL); static CString Get. Temp. Name(LPCTSTR pstr. Original. File, BOOL b. Create); protected: CString m_str. Mirror. Name; };
CMirror. File (cont’d) v CMirror. File: : Open()(DOCCORE. CPP) Ø Ø Read인 경우에는 원래 파일 open Write나 truncate인 경우에는 ü File 명으로 준 파일이 아닌 다른 임시파일을 open함(Mirror file)
CMirror. File (cont’d) BOOL CMirror. File: : Open(LPCTSTR lpsz. File. Name, UINT n. Open. Flags, CFile. Exception* p. Error) { m_str. Mirror. Name. Empty(); if (n. Open. Flags & CFile: : mode. Create) { if (CFile: : Get. Status(lpsz. File. Name, status)) { Afx. Get. Root(lpsz. File. Name, str. Root); if (Get. Disk. Free. Space(str. Root, &dw. Sec. Per. Clus, &dw. Bytes. Per. Sec, &dw. Free. Clus, &dw. Total. Clus)) { n. Bytes=dw. Free. Clus*dw. Sec. Per. Clus* dw. Bytes. Per. Sec; } if (n. Bytes > 2 * DWORD(status. m_size)) { m_str. Mirror. Name = Get. Temp. Name(lpsz. File. Name, TRUE); } } }
CMirror. File (cont’d) if (!m_str. Mirror. Name. Is. Empty() && CFile: : Open(m_str. Mirror. Name, n. Open. Flags, p. Error)) { m_str. File. Name = lpsz. File. Name; FILETIME ft. Create, ft. Access, ft. Modify; if (: : Get. File. Time((HANDLE)m_h. File, &ft. Create, &ft. Access, &ft. Modify)) { Afx. Time. To. File. Time(status. m_ctime, &ft. Create); Set. File. Time((HANDLE)m_h. File, &ft. Create, &ft. Access, &ft. Modify); } DWORD dw. Length = 0; PSECURITY_DESCRIPTOR p. Security. Descriptor = NULL;
CMirror. File (cont’d) if(Get. File. Security(lpsz. File. Name, DACL_SECURITY_INFORMATION, NULL, dw. Length, &dw. Length)) { p. Security. Descriptor = (PSECURITY_DESCRIPTOR) new BYTE[dw. Length]; if (: : Get. File. Security(lpsz. File. Name, DACL_SECURITY_INFORMATION, p. Security. Descriptor, dw. Length, &dw. Length)) { Set. File. Security(m_str. Mirror. Name, DACL_SECURITY_INFORMATION, p. Security. Descriptor); } delete[] (BYTE*)p. Security. Descriptor; } return TRUE; } m_str. Mirror. Name. Empty(); return CFile: : Open(lpsz. File. Name, n. Open. Flags, p. Error); }
CMirror. File(contd. ) Ø CMirror. File: : Close()(DOCCORE. CPP) ü Ø Mirror file을 실제 file로 copy CMirror. File의 이러한 기능이 마음에 들지 않으면 ü CDocument: : Get. File()함수를 override하면 됨
CMirror. File(contd. ) void CMirror. File: : Close() { CString m_str. Name = m_str. File. Name; //file close empties string CFile: : Close(); if (!m_str. Mirror. Name. Is. Empty()) { CFile: : Remove(m_str. Name); CFile: : Rename(m_str. Mirror. Name, m_str. Name); } }
CMirror. File(contd. ) v 결론 Ø CMirror. File의 역할 ü ü ü 원래의 파일을 보관 새로운 mirror file을 생성하고 여기에 작업 모든 작업이 잘 끝날때 까지 원래 파일을 보존하는 효과
CView Printing v Printing overview Ø 작업에 관련된 virtual function ü On. Prepare. Printing() Ø Ø ü Print가 시작되기 전에 호출 CPrint. Info structure가 argument 쪽수와 전체 범위 지정 Document의 print할 페이지를 지정하는데 쓰임 On. Begin. Printing() Ø Print가 시작되면 호출
Printing Overview Ø Ø Ø ü Printer device context의 pointer와 CPrint. Info structure의 pointer가 argument 특별한 GDI resource의 할당 Printer device context에 의존적인 작업을 할 때 이용 On. Print() Ø Ø Document의 특정 section을 print할 때 호출 화면에 보이는 모습과 print되는 모습을 다르게 하고자 할 때 예 : Title page의 추가 Printer device context가 argument
Printing Overview (cont’d) ü On. End. Printing() Ø Ø ü On. Prepare. DC() Ø Ø ü Print가 끝난후 호출 Clean up any resource 특별한 device context의 준비 mapping mode 의 전환 미리 document의 끝인지를 검사 프린터 부가 기능 제공 CView: : Do. Prepare. Printing() Ø Ø Print dialog box를 보여줌 Dialog box에서 선택된 printer의 device context의 생성
Printing Overview (cont’d) Ø CPrint. Info structure ü ü ü Declaration(AFXEXT. H) CPrint. Dialog instance와 정보를 가져오는 함수 CPrint. Dialog의 instance Print인지 print preview인지에 대한 정보 현재 print하는 page정보
Printing Overview (cont’d) struct CPrint. Info // Printing information structure { CPrint. Dialog* m_p. PD; // pointer to print dialog BOOL m_b. Doc. Object; // TRUE if printing by IPrint interface BOOL m_b. Preview; // TRUE if in preview mode BOOL m_b. Direct; // TRUE if bypassing Print Dialog BOOL m_b. Continue. Printing; // set to FALSE to prematurely end printing UINT m_n. Cur. Page; // Current page UINT m_n. Num. Preview. Pages; // Desired number of preview pages CString m_str. Page. Desc; // Format string for page number display LPVOID m_lp. User. Data; // pointer to user created struct CRect m_rect. Draw; // rectangle defining current usable page area void Set. Min. Page(UINT n. Min. Page); void Set. Max. Page(UINT n. Max. Page); UINT Get. Min. Page() const; UINT Get. Max. Page() const; UINT Get. From. Page() const; UINT Get. To. Page() const; UINT Get. Offset. Page() const; };
CView Printing Internals v Printing steps “View. Prnt. cpp” ON_COMMAND(ID_FILE_PRINT, Cview: : On. File. Print) // built-in
CView Printing Internals (cont’d) void CView: : On. File. Print() { CPrint. Info print. Info; if (On. Prepare. Printing(&print. Info)) { // (did you remember to call Do. Prepare. Printing? ) ASSERT(print. Info. m_p. PD->m_pd. h. DC != NULL); CString str. Title; CDocument* p. Doc = Get. Document(); str. Title = p. Doc->Get. Title(); DOCINFO doc. Info; doc. Info. lpsz. Doc. Name = str. Title; // setup the printing DC CDC dc. Print; dc. Print. Attach(print. Info. m_p. PD->m_pd. h. DC); dc. Print. m_b. Printing = TRUE; On. Begin. Printing(&dc. Print, &print. Info); dc. Print. Set. Abort. Proc(_Afx. Abort. Proc);
CView Printing Internals (cont’d) Afx. Get. Main. Wnd()->Enable. Window(FALSE); CPrinting. Dialog dlg. Print. Status(this); dlg. Print. Status. Show. Window(SW_SHOW); dlg. Print. Status. Update. Window(); // start document printing process dc. Print. Start. Doc(&doc. Info); int n. Step = (n. End. Page >= n. Start. Page) ? 1 : -1; n. End. Page = (n. End. Page == 0 xffff) ? 0 xffff : n. End. Page + n. Step; // begin page printing loop for (print. Info. m_n. Cur. Page = n. Start. Page; print. Info. m_n. Cur. Page != n. End. Page; print. Info. m_n. Cur. Page += n. Step) { On. Prepare. DC(&dc. Print, &print. Info); // check for end of print if (!print. Info. m_b. Continue. Printing) break;
CView Printing Internals (cont’d) // write current page TCHAR sz. Buf[80]; wsprintf(sz. Buf, str. Temp, print. Info. m_n. Cur. Page); dlg. Print. Status. Set. Dlg. Item. Text( AFX_IDC_PRINT_PAGENUM, sz. Buf); print. Info. m_rect. Draw. Set. Rect(0, 0, dc. Print. Get. Device. Caps(HORZRES), dc. Print. Get. Device. Caps(VERTRES)); dc. Print. DPto. LP(&print. Info. m_rect. Draw); // attempt to start the current page if (dc. Print. Start. Page() < 0) { b. Error = TRUE; break; } On. Print(&dc. Print, &print. Info); if (dc. Print. End. Page() < 0 || !_Afx. Abort. Proc(dc. Print. m_h. DC, 0)) { b. Error = TRUE; break; } } }
CView Printing Internals (cont’d) // cleanup document printing process if (!print. Info. m_b. Doc. Object) { if (!b. Error) dc. Print. End. Doc(); else dc. Print. Abort. Doc(); } Afx. Get. Main. Wnd()->Enable. Window(); // enable main window On. End. Printing(&dc. Print, &print. Info); // clean up after printing dlg. Print. Status. Destroy. Window(); dc. Print. Detach(); // will be cleaned up by CPrint. Info destructor } }
CView Printing Internals (cont’d) CPrint. Info: : CPrint. Info() { m_p. PD = new CPrint. Dialog(FALSE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOSELECTION); Set. Min. Page(1); // one based page numbers Set. Max. Page(0 xffff); // unknown how many pages m_n. Cur. Page = 1; m_lp. User. Data = NULL; // Initialize to no user data m_b. Preview = FALSE; // initialize to not preview m_b. Direct = FALSE; // initialize to not direct m_b. Doc. Object = FALSE; // initialize to not IPrint m_b. Continue. Printing = TRUE; // Assume it is OK to print m_dw. Flags = 0; m_n. Offset. Page = 0; }
CView Printing Internals (cont’d) BOOL CView: : Do. Prepare. Printing(CPrint. Info* p. Info) { CWin. App* p. App = Afx. Get. App(); if (p. Info->m_b. Preview || p. Info->m_b. Direct || (p. Info->m_b. Doc. Object && !(p. Info->m_dw. Flags & PRINTFLAG_PROMPTUSER))) { if (p. Info->m_p. PD->m_pd. h. DC == NULL) { // if no printer set then, get default printer DC and // create DC without calling print dialog. … } } else { // otherwise, bring up the print dialog and allow user to //change things preset From-To range same as Min-Max range
CView Printing Internals (cont’d) p. Info->m_p. PD->m_pd. n. From. Page = (WORD)p. Info->Get. Min. Page(); p. Info->m_p. PD->m_pd. n. To. Page = (WORD)p. Info->Get. Max. Page(); if (p. App->Do. Print. Dialog(p. Info->m_p. PD) != IDOK) return FALSE; // do not print } ASSERT(p. Info->m_p. PD != NULL); ASSERT(p. Info->m_p. PD->m_pd. h. DC != NULL); if (p. Info->m_p. PD->m_pd. h. DC == NULL) return FALSE; p. Info->m_n. Num. Preview. Pages = p. App->m_n. Num. Preview. Pages; VERIFY(p. Info->m_str. Page. Desc. Load. String(AFX_IDS_PREVIEWPAGEDESC)); return TRUE; }
CView Printing Internals (cont’d) v 관련 함수 Ø CView: : On. File. Print()(VIEWPRNT. CPP) ü CPrint. Info instance생성 Ø Ø ü Print dialog 를 할당한 후 m_p. PD변수에 assign 기타 여러 변수의 값을 채움 On. Prepare. Printing()함수 호출 Ø Virtual function이기 때문에 CMy. View: : On. Prepare. Printing() 을 호출하게 되고 내부에서 다시 CView: : Do. Prepare. Printing() 호출
CView Printing Internals (cont’d) ü Do. Prepare. Printing() Ø ü ü ü Document title을 가져오고 DOCINFO structure를 생성 Local DC를 만들고 Do. Prepare. Printing()과정에서 만들어진 DC handle에 attach함 On. Begin. Printing() Ø ü Print dialog를 보여주고, print DC를 생성 DC의 수정을 가하고자 하면 override _Afx. Abort. Proc()의 설정 Ø Print도중 사용자가 cancel버튼을 누르는지 감시
CView Printing Internals (cont’d) ü ü ü Main window를 disable시키고 print 진행 상황 dialog를 보여 줌 Start. Doc()호출 Printing Loop의 시작 Ø Ø ü ü On. Prepare. DC() Start. Page() On. Print() On. Draw()함수의 호출 End. Page() End. Doc()호출 Main window를 enable시키고 On. End. Printing()
CView Printing Internals (cont’d) CView: : On. File. Print() CView: : On. Begin. Printing() CView: : On. Prepare. DC() CView: : Do. Prepare. Printing() CView: : On. Print() CPrint. Dialog: : Do. Modal() CView: : On. Draw() Yes Another Page? No CView: : On. End. Printing()
CView Printing Internals (cont’d)
Customizing Printing v Standard printing Ø Ø Ø v End. Page()가 호출될 때, Windows가 한 page를 프린트 하는 데 필요한 physical band를 그린다. Abort를 자주 체크한다. 프린트 작업이 느려진다. Efficient printing Ø Ø Band 를 줄인다. 즉, 한 페이지당 여러 번 프린트한다. 오버로딩 CMy. View: : On. File. Print()
CView Print Preview v Question Ø Ø Normal window에서 print preview window로의 변환 방법 Page outline의 표시 방법 Printer output을 화면에 표시하는 과정 Toolbar는 어디에서 온건지
Print Preview Internal v Print preview steps “View. Prev. cpp” ON_COMMAND(ID_FILE_PRINT_PREVIEW, Cview: : On. File. Print. Preview) // built-in
Print Preview Internal (cont’d) void CView: : On. File. Print. Preview() { CPrint. Preview. State* p. State = new CPrint. Preview. State; if (!Do. Print. Preview(AFX_IDD_PREVIEW_TOOLBAR, this, RUNTIME_CLASS(CPreview. View), p. State)) { delete p. State; // preview failed to initialize, delete State now } }
Print Preview Internal (cont’d) BOOL CView: : Do. Print. Preview(UINT n. IDResource, CView* p. Print. View, CRuntime. Class* p. Preview. View. Class, CPrint. Preview. State* p. State) { CFrame. Wnd* p. Parent = Afx. Get. Main. Wnd(); CCreate. Context context; context. m_p. Current. Frame = p. Parent; context. m_p. Current. Doc = Get. Document(); context. m_p. Last. View = this; // Create the preview object CPreview. View* p. View = (CPreview. View*)p. Preview. View. Class->Create. Object(); p. View->m_p. Preview. State = p. State; // save pointer p. Parent->On. Set. Preview. Mode(TRUE, p. State);
Print Preview Internal (cont’d) // Create the toolbar from the dialog resource p. View->m_p. Tool. Bar = new CDialog. Bar; if (!p. View->m_p. Tool. Bar->Create(p. Parent, MAKEINTRESOURCE(n. IDResource), CBRS_TOP, AFX_IDW_PREVIEW_BAR)) { p. Parent->On. Set. Preview. Mode(FALSE, p. State); delete p. View->m_p. Tool. Bar; // not autodestruct yet return FALSE; } if (!p. View->Create(NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), p. Parent, AFX_IDW_PANE_FIRST, &context)) { p. Parent->On. Set. Preview. Mode(FALSE, p. State); p. View ->m_p. Preview. State = NULL; delete p. View; return FALSE; }
Print Preview Internal (cont’d) // Preview window shown now p. State->p. View. Active. Old = p. Parent->Get. Active. View(); CView* p. Active. View = p. Parent->Get. Active. Frame()->Get. Active. View(); if (p. Active. View != NULL) p. Active. View->On. Activate. View(FALSE, p. Active. View); if (!p. View->Set. Print. View(p. Print. View)) { p. View->On. Preview. Close(); return TRUE; } p. Parent->Set. Active. View(p. View); // update toolbar and redraw everything p. View->m_p. Tool. Bar->Send. Message(WM_IDLEUPDATECMDUI, (WPARAM)TRUE); p. Parent->Recalc. Layout(); // position and size everything p. Parent->Update. Window(); return TRUE; }
Print Preview Internal (cont’d) v CPreview. View class Ø AFXPRIV. H class CPreview. View : public CScroll. View { DECLARE_DYNCREATE(CPreview. View) CPreview. View(); BOOL Set. Print. View(CView* p. Print. View); protected: CView* m_p. Orig. View; CView* m_p. Print. View; CPreview. DC* m_p. Preview. DC; // Output and attrib DCs Set, not created CDC m_dc. Print; // Actual printer DC public: virtual void On. Prepare. DC(CDC* p. DC, CPrint. Info* p. Info = NULL); protected: CPrint. Preview. State* m_p. Preview. State; // State to restore CDialog. Bar* m_p. Tool. Bar; // Toolbar for preview
Print Preview Internal (cont’d) struct PAGE_INFO { PAGE_INFO(); CRect rect. Screen; // screen rect (screen device units) CSize size. Unscaled; // unscaled screen rect (screen device units) CSize size. Scale. Ratio; // scale ratio (cx/cy) CSize size. Zoom. Out. Ratio; // scale ratio when zoomed out (cx/cy) }; PAGE_INFO* m_p. Page. Info; // Array of page info structures PAGE_INFO m_page. Info. Array[2]; // Embedded array for the default BOOL m_b. Page. Num. Displayed; // Flags whether or not page number has yet UINT m_n. Zoom. Out. Pages; // number of pages when zoomed out UINT m_n. Zoom. State; UINT m_n. Max. Pages; // for sanity checks UINT m_n. Current. Page; UINT m_n. Pages; int m_n. Second. Page. Offset; // used to shift second page position HCURSOR m_h. Magnify. Cursor; CSize m_size. Printer. PPI; // printer pixels per inch CPoint m_pt. Center. Point; CPrint. Info* m_p. Preview. Info; };
Print Preview Internal (cont’d) BOOL CPreview. View: : Set. Print. View(CView* p. Print. View) { m_p. Print. View = p. Print. View; m_p. Preview. Info = new CPrint. Info; m_p. Preview. Info->m_p. PD->Set. Help. ID(AFX_IDD_PRINTSETUP); m_p. Preview. Info->m_p. PD->m_pd. Flags |= PD_PRINTSETUP; m_p. Preview. Info->m_p. PD->m_pd. Flags &= ~PD_RETURNDC; m_p. Preview. Info->m_b. Preview = TRUE; // signal that this is preview m_p. Preview. DC = new CPreview. DC; // must be created before any if (!m_p. Print. View->On. Prepare. Printing(m_p. Preview. Info)) return FALSE; m_dc. Print. Attach(m_p. Preview. Info->m_p. PD->m_pd. h. DC); m_p. Preview. DC->Set. Attrib. DC(m_p. Preview. Info->m_p. PD->m_pd. h. DC); m_p. Preview. DC->m_b. Printing = TRUE; m_dc. Print. Save. DC(); // Save pristine state of DC HDC h. DC = : : Get. DC(m_h. Wnd); m_p. Preview. DC->Set. Output. DC(h. DC); m_p. Print. View->On. Begin. Printing(m_p. Preview. DC, m_p. Preview. Info); m_p. Preview. DC->Release. Output. DC(); : : Release. DC(m_h. Wnd, h. DC); m_dc. Print. Restore. DC(-1); // restore to untouched state
Print Preview Internal (cont’d) // Get Pixels per inch from Printer m_size. Printer. PPI. cx = m_dc. Print. Get. Device. Caps(LOGPIXELSX); m_size. Printer. PPI. cy = m_dc. Print. Get. Device. Caps(LOGPIXELSY); m_n. Pages = m_p. Preview. Info->m_n. Num. Preview. Pages; if (m_n. Pages == 0) m_n. Pages = 1; else if (m_n. Pages > m_n. Max. Pages) m_n. Pages = m_n. Max. Pages; m_n. Zoom. Out. Pages = m_n. Pages; Set. Scroll. Sizes(MM_TEXT, CSize(1, 1)); // initialize mapping mode only if (m_p. Preview. Info->Get. Max. Page() < 0 x 8000 && m_p. Preview. Info->Get. Max. Page() - m_p. Preview. Info->Get. Min. Page() <= 32767 U) { SCROLLINFO info; info. f. Mask = SIF_PAGE|SIF_RANGE; info. n. Min = m_p. Preview. Info->Get. Min. Page(); info. n. Max = m_p. Preview. Info->Get. Max. Page(); info. n. Page = 1; if (!Set. Scroll. Info(SB_VERT, &info, FALSE)) Set. Scroll. Range(SB_VERT, info. n. Min, info. n. Max, FALSE); } else Show. Scroll. Bar(SB_VERT, FALSE); // if no range specified, or too Set. Current. Page(m_p. Preview. Info->m_n. Cur. Page, TRUE); return TRUE; }
Print Preview Internal (cont’d) void CPreview. View: : On. Draw(CDC* p. DC) { rect. Pen. Create. Pen(PS_SOLID, 2, Get. Sys. Color(COLOR_WINDOWFRAME)); shadow. Pen. Create. Pen(PS_SOLID, 3, Get. Sys. Color(COLOR_BTNSHADOW)); for (UINT n. Page = 0; n. Page < m_n. Pages; n. Page++) { p. DC->Select. Object(&shadow. Pen); p. DC->Move. To(p. Rect->right + 1, p. Rect->top + 3); p. DC->Line. To(p. Rect->right + 1, p. Rect->bottom + 1); p. DC->Move. To(p. Rect->left + 3, p. Rect->bottom + 1); p. DC->Line. To(p. Rect->right + 1, p. Rect->bottom + 1); : : Fill. Rect(p. DC->m_h. DC, rect. Fill, (HBRUSH)Get. Stock. Object(WHITE_BRUSH)); // Display page number On. Display. Page. Number(m_n. Current. Page, n. Page + 1); m_p. Print. View->On. Print(m_p. Preview. DC, m_p. Preview. Info); … }
Print Preview Internal (cont’d) v CView: : On. File. Print. Preview() Ø Ø VIEWPREV. CPP CPrint. Preview. State structure ü Ø Preview를 위한 정보 저장 Do. Print. Preview() 호출
Print Preview Internal (cont’d) Ø CView: : Do. Print. Preview() ü ü VIEWPREV. CPP CPreview. View instance를 생성(AFXPRIV. H) Ø ü ü 내부적으로 CPreview. DC를 사용 CFrame. Wnd: : On. Set. Preview. Mode()함수 이용 Ø ü 미리보기 했을 때 나오는 view임 Normal window에서 print preview mode로 전환 원래 view의 Update. Window()호출 Ø 실제 rendering작업
Print Preview Internal (cont’d) Ø CPreview. View: : Set. Print. View() ü ü ü VIEWPREV. CPP Device context의 준비 CDC의 두 멤버 변수 Ø Ø Ø m_h. DC Screen에 대한 device context m_h. Attrib. DC Printer에 대한 device context CPreview. View: : On. Draw() ü ü VIEWPREV. CPP 각 페이지의 outline을 그리고 실제 rendering
CScroll. View v 사용 과정 Ø Ø v CScroll. View에서 view를 상속받음 Set. Scroll. Size()를 이용하여 setting CScroll. View class Ø Ø Declaration(AFXWIN. H) Implementation(VIEWSCRL. CPP)
CScroll. View (cont’d) class CScroll. View : public CView { DECLARE_DYNAMIC(CScroll. View) protected: int m_n. Map. Mode; CSize m_total. Log; // total size in logical units (no rounding) CSize m_total. Dev; // total size in device units CSize m_page. Dev; // per page scroll size in device units CSize m_line. Dev; // per line scroll size in device units BOOL m_b. Center; // Center output if larger than total size BOOL m_b. Inside. Update; // internal state for On. Size callback void Center. On. Point(CPoint pt. Center); void Scroll. To. Device. Position(POINT pt. Dev); // explicit scrolling no checking protected: void Update. Bars(); // adjust scrollbars etc BOOL Get. True. Client. Size(CSize& size, CSize& size. Sb); void Get. Scroll. Bar. Sizes(CSize& size. Sb); void Get. Scroll. Bar. State(CSize size. Client, CSize& need. Sb, CSize& size. Range, CPoint& pt. Move, BOOL b. Inside. Client);
CScroll. View (cont’d) public: virtual void Calc. Window. Rect(LPRECT lp. Client. Rect, UINT n. Adjust. Type = adjust. Border); virtual void On. Prepare. DC(CDC* p. DC, CPrint. Info* p. Info = NULL); virtual BOOL On. Scroll(UINT n. Scroll. Code, UINT n. Pos, BOOL b. Do. Scroll = TRUE); virtual BOOL On. Scroll. By(CSize size. Scroll, BOOL b. Do. Scroll = TRUE); //{{AFX_MSG(CScroll. View) afx_msg void On. Size(UINT n. Type, int cx, int cy); afx_msg void On. HScroll(UINT n. SBCode, UINT n. Pos, CScroll. Bar* p. Scroll. Bar); afx_msg void On. VScroll(UINT n. SBCode, UINT n. Pos, CScroll. Bar* p. Scroll. Bar); afx_msg BOOL On. Mouse. Wheel(UINT f. Flags, short z. Delta, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() };
CScroll. View (cont’d) v CScroll. View: : Set. Scroll. Sizes() Ø Ø v CScroll. View: : On. Prepare. DC() Ø v Mapping mode설정 Document의 scroll size설정 Scroll bar설치를 위해 Update. Bars()함수 호출 Mapping mode가 변경되었으면 Invalidate()함수 호출 화면 새로 그림 주어진 mapping mode에 따른 DC관련 준비작업 실제 scroll에 관련된 함수 Ø Ø On. Scroll. By(), Scroll. To. Device. Position() 내부적으로 Scroll. Window()함수를 이용함
CScroll. View (cont’d) void CMy. View: : On. Initial. Update() { // The Get. Doc. Size( ) member function is implemented in // your document class. The return type is CSize. Set. Scroll. Sizes(MM_TEXT, Get. Document( )->Get. Doc. Size( ) ); CScroll. View: : On. Initial. Update(); }
CScroll. View (cont’d) void CScroll. View: : Set. Scroll. Sizes(int n. Map. Mode, SIZE size. Total, const SIZE& size. Page, const SIZE& size. Line) { int n. Old. Map. Mode = m_n. Map. Mode; m_n. Map. Mode = n. Map. Mode; m_total. Log = size. Total; //BLOCK: convert logical coordinate space to device coordinates { CWindow. DC dc(NULL); dc. Set. Map. Mode(m_n. Map. Mode); m_total. Dev = m_total. Log; dc. LPto. DP((LPPOINT)&m_total. Dev); m_page. Dev = size. Page; dc. LPto. DP((LPPOINT)&m_page. Dev); m_line. Dev = size. Line; dc. LPto. DP((LPPOINT)&m_line. Dev); if (m_total. Dev. cy < 0) m_total. Dev. cy = -m_total. Dev. cy; if (m_page. Dev. cy < 0) m_page. Dev. cy = -m_page. Dev. cy; if (m_line. Dev. cy < 0) m_line. Dev. cy = -m_line. Dev. cy; } // release DC here
CScroll. View (cont’d) if if (m_page. Dev. cx == 0) m_page. Dev. cx = m_total. Dev. cx / 10; (m_page. Dev. cy == 0) m_page. Dev. cy = m_total. Dev. cy / 10; (m_line. Dev. cx == 0) m_line. Dev. cx = m_page. Dev. cx / 10; (m_line. Dev. cy == 0) m_line. Dev. cy = m_page. Dev. cy / 10; if (m_h. Wnd != NULL) { // window has been created, invalidate now Update. Bars(); if (n. Old. Map. Mode != m_n. Map. Mode) Invalidate(TRUE); } }
CScroll. View (cont’d) void CScroll. View: : On. Prepare. DC(CDC* p. DC, CPrint. Info* p. Info) { switch (m_n. Map. Mode) { case MM_SCALETOFIT: p. DC->Set. Map. Mode(MM_ANISOTROPIC); p. DC->Set. Window. Ext(m_total. Log); // window is in logical coordinates p. DC->Set. Viewport. Ext(m_total. Dev); break; default: p. DC->Set. Map. Mode(m_n. Map. Mode); break; } CPoint pt. Vp. Org(0, 0); // assume no shift for printing if (!p. DC->Is. Printing()) { pt. Vp. Org = -Get. Device. Scroll. Position(); p. DC->Set. Viewport. Org(pt. Vp. Org); CView: : On. Prepare. DC(p. DC, p. Info); // For default Printing behavior }
CForm. View v CForm. View class Ø Ø Dialog의 편리함과 document/view의 기능을 같이 쓸 수 있게 해줌 자동 printing, print preview기능은 제공하지 않음 Declaration(AFXEXT. H) Implementation(VIEWFORM. CPP) ü CForm. View: : Create()
CCtrl. View v 특징 Ø Ø Windows control을 view가 되게 함 종류 ü Ø Ø Ø CEdit. View, CList. View, CTree. View, CRich. Edit. View CCtrl. View는 base class임 Declaration(AFXWIN. H) Implementation(VIEWCORE. CPP)
CCtrl. View (cont’d) class CCtrl. View : public CView { DECLARE_DYNCREATE(CCtrl. View) public: CCtrl. View(LPCTSTR lpsz. Class, DWORD dw. Style); // Attributes protected: CString m_str. Class; DWORD m_dw. Default. Style; // Overrides virtual void On. Draw(CDC*); virtual BOOL Pre. Create. Window(CREATESTRUCT& cs); // Implementation protected: afx_msg void On. Paint(); DECLARE_MESSAGE_MAP() };
CCtrl. View (cont’d) v 멤버 Ø Ø m_strclass : 해당 control에 대한 window class의 이름 m_dw. Default. Style : view class에 대한 default style On. Draw() : 절대 호출되지 않는 함수 On. Paint() : Defaul() 호출. 이는 control들이 스스로 paint 할 수 있기 때문
CTree. View v CTree. View class Ø Ø Declaration(AFXCVIEW. H) Implementation ü ü ü VIEWCMN. CPP AFXCVIEW. INL CTree. View: : CTree. View() CTree. View: : Pre. Create. Window() CTree. View: : Get. Tree. Ctrl()
Control Classes v 선언 및 구현 파일 Ø CEdit. View ü Ø CList. View ü Ø AFXEXT. H, AFXEXT. INL/VIEWEDIT. CPP AFXCVIEW. H, AFXCVIEW. INL/VIEWCMN. CPP CRich. Edit. View ü AFXRICH. H, AFXRICH. INL/VIEWRICH. CPP
Chap. 9 Enhanced User-Interface Classes
Contents v v Splitter Windows CControl. Bar Architecture CMini. Frame. Wnd MRU File List
Introduction v 일반 user interface Ø Ø v Win 32 API 에 존재하는 구조 CWnd, CDialog, control, … Enhanced user interface Ø Ø MFC 에 존재하는 구조 splitter window, control bar, …
MFC Splitter Windows pane 1 Splitter bar pane 2 Splitter border Split box
Splitter Window v 특징 Ø Panes ü 일반적으로 CView Ø ü Document내용이 변하면 Update. All. Views()로 반영가능 모든 CWnd derivative가 가능 Ø Document내용이 변하면 수동으로 변화를 반영시켜야 함
Splitter Window (cont’d) Ø 두가지 type ü Dynamic splitter window Ø Ø Ø ü 2 X 2로 제한 Create()함수 이용 Document template에 정보 추가 view 가 동일한 성질 예 : VC++ code editor Static splitter window Ø Ø Ø 2 X 2의 제한 없음(16 X 16) Create. Static()함수 이용 Create. View()함수로 각 pane에 view를 생성 view가 서로 다른 성질 예 : 탐색기
Splitter Window (cont’d) BOOL CChild. Frame: : On. Create. Client(LPCREATESTRUCT lpcs, CCreate. Context* p. Context) { if (!m_wnd. Splitter. Create(this, 2, 2, CSize(10, 10), p. Context)) { TRACE 0("Failed to create splitter bar "); return FALSE; // failed to create } return TRUE; }
Splitter Window (cont’d) BOOL CChild. Frame: : On. Create. Client(LPCREATESTRUCT lpcs, CCreate. Context* p. Context) { int n. Row, n. Col; if (!m_wnd. Splitter. Create. Static(this, 4, 4) ) return FALSE; for ( n. Row = 0; n. Row<4; n. Row++ ) for ( n. Col=0; n. Col<4; n. Col+= ) m_wnd. Splitter. Create. View(n. Row, n. Col, RUNTIME_CLASS(CMy. View), Csize(10, 10), p. Context); return TRUE; }
CSplitter. Wnd v CSplitter. Wnd class Ø Declaration(AFXEXT. H) class CSplitter. Wnd : public CWnd { DECLARE_DYNAMIC(CSplitter. Wnd) // Construction public: CSplitter. Wnd(); // Create a single view type splitter with multiple splits BOOL Create(); BOOL Create. Static(); virtual BOOL Create. View(); // Attributes public: int Id. From. Row. Col(int row, int col) const; virtual void Recalc. Layout(); // call after changing sizes
CSplitter. Wnd (cont’d) // Overridables protected: enum ESplit. Type { split. Box, split. Bar, split. Intersection, split. Border }; virtual void On. Draw. Splitter(CDC* p. DC, ESplit. Type n. Type, const CRect& rect); virtual void On. Invert. Tracker(const CRect& rect); public: // for customizing DYNAMIC_SPLIT behavior virtual void Delete. View(int row, int col); virtual BOOL Split. Row(int cy. Before); virtual BOOL Split. Column(int cx. Before); virtual void Delete. Row(int row. Delete); virtual void Delete. Column(int col. Delete); // determining active pane from focus or active view in frame virtual CWnd* Get. Active. Pane(int* p. Row = NULL, int* p. Col = NULL); virtual void Set. Active. Pane(int row, int col, CWnd* p. Wnd = NULL); protected: CWnd* Get. Active. Pane(int& row, int& col); // obsolete
CSplitter. Wnd (cont’d) public: struct CRow. Col. Info { int n. Min. Size; // below that try not to show int n. Ideal. Size; // user set size // variable depending on the available size layout int n. Cur. Size; // 0 => invisible, -1 => nonexistant }; protected: CRuntime. Class* m_p. Dynamic. View. Class; int m_n. Max. Rows, m_n. Max. Cols; // current state information int m_n. Rows, m_n. Cols; BOOL m_b. Has. HScroll, m_b. Has. VScroll; CRow. Col. Info* m_p. Col. Info; CRow. Col. Info* m_p. Row. Info;
CSplitter. Wnd (cont’d) // Tracking info - only valid when 'm_b. Tracking' is set BOOL m_b. Tracking, m_b. Tracking 2; CPoint m_pt. Track. Offset; CRect m_rect. Limit; CRect m_rect. Tracker, m_rect. Tracker 2; int m_ht. Track; BOOL Create. Common(CWnd* p. Parent. Wnd, SIZE size. Min, DWORD dw. Style, UINT n. ID); virtual int Hit. Test(CPoint pt) const; virtual void Get. Inside. Rect(CRect& rect) const; virtual void Get. Hit. Rect(int ht, CRect& rect); virtual void Track. Row. Size(int y, int row); virtual void Track. Column. Size(int x, int col); virtual void Draw. All. Split. Bars(CDC* p. DC, int cx. Inside, int cy. Inside); virtual void Set. Split. Cursor(int ht); CWnd* Get. Sizing. Parent(); // starting and stopping tracking virtual void Start. Tracking(int ht); virtual void Stop. Tracking(BOOL b. Accept);
CSplitter. Wnd (cont’d) // special command routing to frame virtual BOOL On. Command(WPARAM w. Param, LPARAM l. Param); virtual BOOL On. Notify(WPARAM w. Param, LPARAM l. Param, LRESULT* p. Result); afx_msg BOOL On. Set. Cursor(CWnd* p. Wnd, UINT n. Hit. Test, UINT message); afx_msg void On. Mouse. Move(UINT n. Flags, CPoint pt); afx_msg void On. Paint(); afx_msg void On. LButton. Down(UINT n. Flags, CPoint pt); afx_msg void On. LButton. Dbl. Clk(UINT n. Flags, CPoint pt); afx_msg void On. LButton. Up(UINT n. Flags, CPoint pt); afx_msg void On. Cancel. Mode(); afx_msg void On. Key. Down(UINT n. Char, UINT n. Rep. Cnt, UINT n. Flags); afx_msg void On. Size(UINT n. Type, int cx, int cy); afx_msg BOOL On. Mouse. Wheel(UINT n. Flags, short z. Delta, CPoint pt); afx_msg BOOL On. Nc. Create(LPCREATESTRUCT lpcs); afx_msg void On. Sys. Command(UINT n. ID, LPARAM l. Param); afx_msg void On. Display. Change(); };
CSplitter. Wnd v 멤버 data type Ø ESplit. Type ü Ø Defines type of splitter to be drawn CRow. Col. Info ü Mininum, ideal, current size of a row or column(row이면 높이 , column이면 넓이)
CSplitter. Wnd (cont’d) v 멤버 변수 Ø m_p. Dynamic. View. Class ü Ø m_p. Col. Info ü Ø Array of CRow. Col. Info m_p. Row. Info ü v Dynamic하게 생성된 view의 CRuntime. Class에 대한 pointer Array of CRow. Col. Info 멤버 함수 Ø Recalc. Layout() ü 모든 splitter window component에 대한 위치 조절 작업
CSplitter. Wnd (cont’d) Ø On. Display. Change() ü v Monitor resolution을 바꾸면 호출됨 이외 수많은 멤버 변수와 함수
Initialization v Create함수 Ø v Create()나 Create. Static() 둘 다 내부적으로 Create. Common()함수를 호출 CSplitter. Wnd: : Create()(WINSPLIT. CPP) Ø Ø 최고 2 X 2인지 확인 현재 row와 col의 수를 1로 초기화(dynamic) Create. Common()함수 호출 Create. View()함수 호출
Initialization (cont’d) v CSplitter. Wnd: : Create. Static() Ø Ø Ø v 최고 16 X 16의 제한 Create. Common()함수 호출 Create. View()함수의 호출이 없음 CSplitter. Wnd: : Create. Common() Ø Ø 실제 splitter window가 생성됨 Current size를 – 1로 함 ü 크기 조절 함수 Ø Set. Column. Info()/Set. Row. Info()
Initialization (cont’d) v CSplitter. Wnd: : Create. View() Ø Ø 특정 pane에 view의 생성 Id. From. Row. Col()함수 이용 ü Ø Row와 column값으로 pane의 ID를 계산 내부적으로 CWnd의 Create()함수 호출
Initialization (cont’d) BOOL CSplitter. Wnd: : Create(CWnd* p. Parent. Wnd, int n. Max. Rows, int n. Max. Cols, SIZE size. Min, CCreate. Context* p. Context, DWORD dw. Style, UINT n. ID) { // Dynamic splitters are limited to 2 x 2 ASSERT(n. Max. Rows >= 1 && n. Max. Rows <= 2); ASSERT(n. Max. Cols >= 1 && n. Max. Cols <= 2); ASSERT(n. Max. Cols > 1 || n. Max. Rows > 1); // 1 x 1 is not m_n. Max. Rows = n. Max. Rows; m_n. Max. Cols = n. Max. Cols; m_n. Rows = m_n. Cols = 1; // start off as 1 x 1 if (!Create. Common(p. Parent. Wnd, size. Min, dw. Style, n. ID)) return FALSE; m_p. Dynamic. View. Class = p. Context->m_p. New. View. Class;
Initialization (cont’d) // add the first initial pane if (!Create. View(0, 0, m_p. Dynamic. View. Class, size. Min, p. Context)) { Destroy. Window(); // will clean up child windows return FALSE; } m_p. Col. Info[0]. n. Ideal. Size = size. Min. cx; m_p. Row. Info[0]. n. Ideal. Size = size. Min. cy; return TRUE; }
Initialization (cont’d) BOOL CSplitter. Wnd: : Create. Static(CWnd* p. Parent. Wnd, int n. Rows, int n. Cols, DWORD dw. Style, UINT n. ID) { ASSERT(n. Rows >= 1 && n. Rows <= 16); ASSERT(n. Cols >= 1 && n. Cols <= 16); ASSERT(n. Cols > 1 || n. Rows > 1); // 1 x 1 is not permitted ASSERT(m_n. Rows == 0 && m_n. Cols == 0); m_n. Rows = m_n. Max. Rows = n. Rows; m_n. Cols = m_n. Max. Cols = n. Cols; // none yet // create with zero minimum pane size if (!Create. Common(p. Parent. Wnd, CSize(0, 0), dw. Style, n. ID)) return FALSE; return TRUE; }
Initialization (cont’d) BOOL CSplitter. Wnd: : Create. Common(CWnd* p. Parent. Wnd, SIZE size. Min, DWORD dw. Style, UINT n. ID) { VERIFY(Afx. Defer. Register. Class(AFX_WNDMDIFRAME_REG)); if (!Create. Ex(0, _afx. Wnd. MDIFrame, NULL, dw. Create. Style, 0, 0, p. Parent. Wnd->m_h. Wnd, (HMENU)n. ID, NULL)) return FALSE; // create invisible m_p. Col. Info = new CRow. Col. Info[m_n. Max. Cols]; for (int col = 0; col < m_n. Max. Cols; col++) { m_p. Col. Info[col]. n. Min. Size = m_p. Col. Info[col]. n. Ideal. Size = size. Min. cx; m_p. Col. Info[col]. n. Cur. Size = -1; }
Initialization (cont’d) m_p. Row. Info = new CRow. Col. Info[m_n. Max. Rows]; for (int row = 0; row < m_n. Max. Rows; row++) { m_p. Row. Info[row]. n. Min. Size = m_p. Row. Info[row]. n. Ideal. Size = size. Min. cy; m_p. Row. Info[row]. n. Cur. Size = -1; } // create scroll bars by setting the style Set. Scroll. Style(dw. Style); return TRUE; }
Initialization (cont’d) BOOL CSplitter. Wnd: : Create. View(int row, int col, CRuntime. Class* p. View. Class, SIZE size. Init, CCreate. Context* p. Context) { Get. Dlg. Item(Id. From. Row. Col(row, col)); // set the initial size for that pane m_p. Col. Info[col]. n. Ideal. Size = size. Init. cx; m_p. Row. Info[row]. n. Ideal. Size = size. Init. cy; BOOL b. Send. Initial. Update = FALSE; CCreate. Context context. T; if (p. Context == NULL) {
Initialization (cont’d) CView* p. Old. View = (CView*)Get. Active. Pane(); if (p. Old. View != NULL && p. Old. View->Is. Kind. Of(RUNTIME_CLASS(CView))) { context. T. m_p. Last. View = p. Old. View; context. T. m_p. Current. Doc = p. Old. View->Get. Document(); if (context. T. m_p. Current. Doc != NULL) context. T. m_p. New. Doc. Template = context. T. m_p. Current. Doc->Get. Doc. Template(); } p. Context = &context. T; b. Send. Initial. Update = TRUE; } CWnd* p. Wnd = (CWnd*)p. View. Class->Create. Object(); p. Wnd->Create(NULL, dw. Style, rect, this, Id. From. Row. Col(row, col), p. Context); return TRUE; }
Pane Management v 살펴볼 사항 Ø Dynamic splitter window에서 ü Ø 전체 frame window의 크기가 조절될 때 ü v Pane이 dynamic하게 생성되는 과정 각 pane들의 크기와 위치가 조절되는 과정 관련 함수 Ø Split. Row(), Split. Column()
Pane Management (cont’d) v CSplitter. Wnd: : Split. Column() ü ü ü WINCORE. CPP Dynamic splitter windows에서 가능 각 pane에 대하여 Create. View()함수 호출 CRow. Col. Info structure에 새로운 정보를 저장 Recalc. Layout()함수를 호출하여 pane layout 조절
Pane Management (cont’d) BOOL CSplitter. Wnd: : Split. Column(int cx. Before) { cx. Before -= m_cx. Border; int col. New = m_n. Cols; int cx. New = _Afx. Can. Split. Row. Col(&m_p. Col. Info[col. New-1], cx. Before, m_cx. Splitter); if (cx. New == -1) return FALSE; // too small to split m_n. Cols++; // bump count during view creation for (int row = 0; row < m_n. Rows; row++) { CSize size(cx. New, m_p. Row. Info[row]. n. Cur. Size); if (!Create. View(row, col. New, m_p. Dynamic. View. Class, size, NULL)) { while (row > 0) Delete. View(--row, col. New); m_n. Cols--; // it didn't work out return FALSE; } }
Pane Management (cont’d) // new parts created - resize and re-layout m_p. Col. Info[col. New-1]. n. Ideal. Size = cx. Before; m_p. Col. Info[col. New]. n. Ideal. Size = cx. New; ASSERT(m_n. Cols == col. New+1); Recalc. Layout(); return TRUE; }
CSplitter. Wnd Drawing v 관련 함수 Ø Ø Ø Draw. All. Split. Bars(), On. Draw. Splitter() 실제로 On. Draw. Splitter()가 drawing을 함 CSplitter. Wnd: : On. Draw. Splitter() ü ü ü WINSPLIT. CPP Draw. All. Split. Bars()함수에서 각 row와 column에 대하여 호출 됨 Split border, box, bar등의 drawing
CSplitter. Wnd Drawing (cont’d) Ø Draw. All. Split. Bars() ü Ø Splitter bar와 splitter border를 On. Draw. Splitter()함수를 이용 하여 그림 CSplitter. Wnd: : On. Paint() ü ü ü On. Draw. Splitter()를 이용하여 splitter box를 그림 Draw. All. Split. Bars()함수를 이용하여 splitter bar와 splitter border를 그림 결국 On. Paint()가 모든 그리는 작업을 함
CSplitter. Wnd Drawing (cont’d) void CSplitter. Wnd: : Draw. All. Split. Bars(CDC* p. DC, int cx. Inside, int cy. Inside) { // draw column split bars CRect rect; Get. Client. Rect(rect); rect. left += m_cx. Border; for (int col = 0; col < m_n. Cols - 1; col++) { rect. left += m_p. Col. Info[col]. n. Cur. Size + m_cx. Border. Share; rect. right = rect. left + m_cx. Splitter; if (rect. left > cx. Inside) break; // stop if not fully visible On. Draw. Splitter(p. DC, split. Bar, rect); rect. left = rect. right + m_cx. Border. Share; }
CSplitter. Wnd Drawing (cont’d) // draw row split bars Get. Client. Rect(rect); rect. top += m_cy. Border; for (int row = 0; row < m_n. Rows - 1; row++) { rect. top += m_p. Row. Info[row]. n. Cur. Size + m_cy. Border. Share; rect. bottom = rect. top + m_cy. Splitter; if (rect. top > cy. Inside) break; // stop if not fully visible On. Draw. Splitter(p. DC, split. Bar, rect); rect. top = rect. bottom + m_cy. Border. Share; } // draw pane borders Get. Client. Rect(rect); int x = rect. left;
CSplitter. Wnd Drawing (cont’d) for (col = 0; col < m_n. Cols; col++) { int cx = m_p. Col. Info[col]. n. Cur. Size + 2*m_cx. Border; if (col == m_n. Cols-1 && m_b. Has. VScroll) cx += afx. Data. cx. VScroll - CX_BORDER; int y = rect. top; for (int row = 0; row < m_n. Rows; row++) { int cy = m_p. Row. Info[row]. n. Cur. Size + 2*m_cy. Border; if (row == m_n. Rows-1 && m_b. Has. HScroll) cy += afx. Data. cy. HScroll - CX_BORDER; On. Draw. Splitter(p. DC, split. Border, CRect(x, y, x+cx, y+cy)); y += cy + m_cy. Splitter. Gap - 2*m_cy. Border; } x += cx + m_cx. Splitter. Gap - 2*m_cx. Border; } }
CSplitter. Wnd Drawing (cont’d) void CSplitter. Wnd: : On. Draw. Splitter(CDC* p. DC, ESplit. Type n. Type, const CRect& rect. Arg) { // otherwise, actually draw CRect rect = rect. Arg; switch (n. Type) { case split. Border: case split. Intersection: case split. Box: case split. Bar: if (!afx. Data. b. Win 4) } // fill the middle COLORREF clr = afx. Data. clr. Btn. Face; p. DC->Fill. Solid. Rect(rect, clr); }
CSplitter. Wnd Drawing (cont’d) void CSplitter. Wnd: : On. Paint() { CPaint. DC dc(this); // draw the splitter boxes if (m_b. Has. VScroll && m_n. Rows < m_n. Max. Rows) On. Draw. Splitter(&dc, split. Box, …); if (m_b. Has. HScroll && m_n. Cols < m_n. Max. Cols) On. Draw. Splitter(&dc, split. Box, …); // extend split bars to window border (past margins) Draw. All. Split. Bars(&dc, rect. Inside. right, rect. Inside. bottom); // draw splitter intersections (inside only) for (int row = 0; row < m_n. Rows - 1; row++) for (int col = 0; col < m_n. Cols - 1; col++) On. Draw. Splitter(&dc, split. Intersection, rect); }
Hit Testing v 역할 Ø v 사용자가 어느 splitter component를 hit했는지… User interactions Ø Mouse move ü Ø Button down ü Ø Splitter bar위에서 cursor의 변경 Drag bar, create bar Button up ü Stop dragging
Hit Testing (cont’d) v 관련 함수 Ø CSplitter. Wnd: : Hit. Test() ü ü ü WINSPLIT. CPP 마우스 왼쪽 버튼의 클릭, 마우스 이동, 마우스 오른쪽 버튼의 더블 클릭 시 호출 Pt. In. Rect()함수를 이용 Ø Splitter component중 어느 부분인지 구별함
Splitter Window Tracking v 역할 Ø Ø v Hit. Test의 결과를 가지고 splitter component를 다시 그 림 Pane의 split 관련 함수 Ø Ø Ø CSplitter. Wnd: : Start. Tracking() CSplitter. Wnd: : On. Invert. Tracker() CSplitter. Wnd: : Stop. Tracking()
Splitter Window Tracking (cont’d) Ø CSplitter. Wnd: : On. Invert. Tracker() ü Ø 마우스가 움직이는 동안 Split border를 그리는 역할 CSplitter. Wnd: : Stop. Tracking() ü ü Tracking이 끝나고 마우스 버튼을 놓으면 호출 실제 view의 split작업
CControl. Bar Arch. v Control bar Ø Ø Frame window의 한 쪽 side에 위치하는 특별한 window Docking이 가능 위치 정보를 INI파일이나 registry에 저장 종류 ü CDialog. Bar, COle. Resize. Bar, CStatus. Bar, CTool. Bar, CRe. Bar
CControl. Bar v CControl. Bar class Ø Ø Declaration(AFXEXT. H) Implementation ü ü BARCORE. CPP BARDOCK. CPP DOCKSTAT. CPP WINFRM. CPP
CControl. Bar (cont’d) class CControl. Bar : public CWnd { int m_cx. Left. Border, m_cx. Right. Border; int m_cy. Top. Border, m_cy. Bottom. Border; int m_cx. Default. Gap; // default gap value UINT m_n. MRUWidth; // For dynamic resizing. int m_n. Count; void* m_p. Data; // m_n. Count elements enum State. Flags { delay. Hide = 1, delay. Show = 2, temp. Hide = 4, status. Set = 8 }; UINT m_n. State. Flags; // support for docking DWORD m_dw. Style; // creation style (used for layout) DWORD m_dw. Dock. Style; // indicates how bar can be docked CFrame. Wnd* m_p. Dock. Site; // current dock site, if dockable CDock. Bar* m_p. Dock. Bar; // current dock bar, if dockable CDock. Context* m_p. Dock. Context; // used during dragging virtual void Do. Paint(CDC* p. DC); void Draw. Borders(CDC* p. DC, CRect& rect); void Draw. Gripper(CDC* p. DC, const CRect& rect);
CControl. Bar (cont’d) // implementation helpers virtual LRESULT Window. Proc(UINT n. Msg, WPARAM w. Param, LPARAM l. Param); void Calc. Inside. Rect(CRect& rect, BOOL b. Horz) const; // adjusts borders etc BOOL Alloc. Elements(int n. Elements, int cb. Element); virtual BOOL Set. Status. Text(int n. Hit); void Reset. Timer(UINT n. Event, UINT n. Time); void Erase. Non. Client(); void Get. Bar. Info(CControl. Bar. Info* p. Info); void Set. Bar. Info(CControl. Bar. Info* p. Info, CFrame. Wnd* p. Frame. Wnd); friend class CFrame. Wnd; friend class CDock. Bar; };
CControl. Bar (cont’d) Ø 멤버 함수 ü Do. Paint() Ø Ø ü Control bar의 경계를 그리는 함수 On. Paint() Do. Paint() Draw. Borders() Ø Ø 실제 control bar의 경계를 그리는 함수 Control bar가 dock되었을 때만 역할 수행
Docking v CControl. Bar: : Enable. Docking() Ø Ø v BARDOCK. CPP 변수 초기화 CFrame. Wnd: : Enable. Docking() Ø Ø Ø WINFRM 2. CPP CMini. Dock. Frame. Wnd 의 사용 CDock. Bar의 사용 ü 좌, 우, 위, 아래의 control bar가 놓일 자리임
Docking (cont’d) Ø v Argument로 주어진 flag를 보고 좌, 우, 상, 하 어느 위 치에 Dock. Bar를 만들지 결정, 생성 CFrame. Wnd: : Dock. Control. Bar() Ø Ø WINFRM 2. CPP 두가지 버전이 존재 저장된 CDock. Bar의 pointer를 가져옴 CDock. Bar: : Dock. Control. Bar()함수 호출
Docking (cont’d) v CDock. Bar: : Dock. Control. Bar() Ø Ø Ø BARDOCK. CPP Control bar를 주어진 위치로 옮김 중요한 사항 ü ü ü 자리만 옮겨진 것 뿐 여전히 floating상태 Dock을 시키는 매커니즘은? Ø Ø v Control bar의 parent를 CDock. Bar로 바꿈 Dock의 효과가 발생 CDock. Bar (AFXPRIV. H)
Docking (cont’d) void CControl. Bar: : Enable. Docking(DWORD dw. Dock. Style) { m_dw. Dock. Style = dw. Dock. Style; if (m_p. Dock. Context == NULL) m_p. Dock. Context = new CDock. Context(this); // permanently wire the bar's owner to its current parent if (m_h. Wnd. Owner == NULL) m_h. Wnd. Owner = : : Get. Parent(m_h. Wnd); }
Docking (cont’d) void CFrame. Wnd: : Enable. Docking(DWORD dw. Dock. Style) { m_p. Floating. Frame. Class = RUNTIME_CLASS(CMini. Dock. Frame. Wnd); for (int i = 0; i < 4; i++) { if (dw. Dock. Bar. Map[i][1] & dw. Dock. Style & CBRS_ALIGN_ANY) { CDock. Bar* p. Dock = (CDock. Bar*)Get. Control. Bar(dw. Dock. Bar. Map[i][0]); p. Dock = new CDock. Bar; p. Dock->Create(this, … ); } } } const DWORD CFrame. Wnd: : dw. Dock. Bar. Map[4][2] = { { AFX_IDW_DOCKBAR_TOP, CBRS_TOP }, { AFX_IDW_DOCKBAR_BOTTOM, CBRS_BOTTOM }, { AFX_IDW_DOCKBAR_LEFT, CBRS_LEFT }, { AFX_IDW_DOCKBAR_RIGHT, CBRS_RIGHT }, };
Docking (cont’d) void CFrame. Wnd: : Dock. Control. Bar(CControl. Bar* p. Bar, CDock. Bar* p. Dock. Bar, LPCRECT lp. Rect) { if (p. Dock. Bar == NULL) { for (int i = 0; i < 4; i++) { if ((dw. Dock. Bar. Map[i][1] & CBRS_ALIGN_ANY) == (p. Bar->m_dw. Style & CBRS_ALIGN_ANY)) { p. Dock. Bar = Get. Control. Bar(dw. Dock. Bar. Map[i][0]); break; } } } p. Dock. Bar->Dock. Control. Bar(p. Bar, lp. Rect); }
Docking (cont’d) void CDock. Bar: : Dock. Control. Bar(CControl. Bar* p. Bar, LPCRECT lp. Rect) { CRect rect. Bar; p. Bar->Get. Window. Rect(&rect. Bar); if (lp. Rect != NULL) { // insert into appropriate row CRect rect(lp. Rect); p. Bar->Set. Window. Pos(NULL, rect, …. ); } else { // always add on current row, then create new one m_arr. Bars. Add(p. Bar); m_arr. Bars. Add(NULL); // align off the edge initially p. Bar->Set. Window. Pos(NULL, …. ); }
Docking (cont’d) // attach it to the docking site if (p. Bar->Get. Parent() != this) p. Bar->Set. Parent(this); if (p. Bar->m_p. Dock. Bar == this) p. Bar->m_p. Dock. Bar->Remove. Control. Bar(p. Bar, n. Pos); else if (p. Bar->m_p. Dock. Bar != NULL) p. Bar->m_p. Dock. Bar->Remove. Control. Bar(p. Bar, -1, m_b. Floating && !p. Bar->m_p. Dock. Bar>m_b. Floating); p. Bar->m_p. Dock. Bar = this; }
Floating v 관련 함수 Ø CFrame. Wnd: : Float. Control. Bar() ü ü WINFRM 2. CPP CMini. Dock. Frame. Wnd를 사용 Ø ü ü 역시 CDock. Bar: : Dock. Control. Bar()함수 이용 CFrame. Wnd: : Recalc. Layout()함수를 이용 Ø ü Control bar의 frame window역할 Layout 조절 Floating의 효과 Ø Control bar의 parent를 전체 frame window로 바꾸어 주는 것
Floating (cont’d) void CFrame. Wnd: : Float. Control. Bar(CControl. Bar* p. Bar, CPoint point, DWORD dw. Style) { CMini. Dock. Frame. Wnd* p. Dock. Frame = Create. Floating. Frame(dw. Style); p. Dock. Frame->Set. Window. Pos(NULL, point. x, point. y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); CDock. Bar* p. Dock. Bar = (CDock. Bar*)p. Dock. Frame-> Get. Dlg. Item(AFX_IDW_DOCKBAR_FLOAT); p. Dock. Bar->Dock. Control. Bar(p. Bar); p. Dock. Frame->Recalc. Layout(TRUE); if (Get. Window. Long(p. Bar->m_h. Wnd, GWL_STYLE) & WS_VISIBLE) { p. Dock. Frame->Show. Window(SW_SHOWNA); p. Dock. Frame->Update. Window(); } }
Dragging v 관련 함수 Ø CControl. Bar: : On. LButton. Down() ü Ø BARCORE. CPP CDock. Context class의 이용 ü ü Declaration : AFXPRIV. H Implementation : DOCKCONT. CPP
Persistence v 관련 함수 Ø CFrame. Wnd: : Save. Bar. State() ü Ø CFrame. Wnd: : Get. Dock. State() ü Ø DOCKSTAT. CPP Helper class ü CDock. State, CControl. Bar. Info
Layout Management v 관련 함수 Ø CFrame. Wnd: : Recalc. Layout() ü ü ü WINFRM. CPP CWnd: : Reposition. Bars()함수 이용 CWnd: : Set. Window. Pos()함수 이용
CMini. Frame. Wnd v CMini. Frame. Wnd class Ø Nonclient message처리를 이용 ü Ø Declaration ü Ø Mini frame모양을 그림 AFXWIN. H Implementation ü WINMINI. CPP
MRU File List v 관련 함수 Ø CWin. App: : Load. Std. Profile. Settings() ü ü Ø 저장된 MRU file list를 가져옴 CWin. App: : Init. Instance()에서 호출됨 CWin. App: : Save. Std. Profile. Settings() ü ü MRU file list를 registry에 기록 Document/View구조이면 Ø Document저장시 자동으로 list에 추가됨
MRU File List (cont’d) Ø Ø v CDocument: : Do. Save() CWin. App: : Add. To. Recent. File. List() Save. Std. Profile. Settings()는 저장된 file list를 registry에 기록 Helper class Ø CRecent. File. List class ü ü 실제 MRU file에 대한 list를 관리함 Declaration Ø AFXPRIV. H
MRU File List(contd. ) Ø Implementation ü ü AFXADV. H …
Chap. 10 DLLs and Threads
Contents v v v Understanding States MFC DLLs MFC Threads
Understanding States v 2 types state information Ø Module state ü ü ü Ø Module Application의 다른 부분과 독립적으로 실행가능한 executable code(DLL, OLE control) Unique 한 DLL을 여러 program이 동시에 쓴다면 각 program마다 module state가 존재 Module local data Thread(process) state ü Thread local data
Module State v Definition(AFXSTAT_. H) Ø AFX_MODULE_STATE ü ü ü ü CWin. App object에 대한 pointer Module의 instance handle Resource의 instance handle Application name DLL인지 아닌지를 구별하는 flag System module인지 아닌지를 구별하는 flag Thread state information …
Module State (cont’d) // AFX_MODULE_STATE (global data for a module) class AFX_MODULE_STATE : public CNo. Track. Object { public: #ifdef _AFXDLL AFX_MODULE_STATE(BOOL b. DLL, WNDPROC pfn. Afx. Wnd. Proc, DWORD dw. Version); AFX_MODULE_STATE(BOOL b. DLL, WNDPROC pfn. Afx. Wnd. Proc, DWORD dw. Version, BOOL b. System); #else AFX_MODULE_STATE(BOOL b. DLL); #endif ~AFX_MODULE_STATE(); CWin. App* m_p. Current. Win. App; HINSTANCE m_h. Current. Instance. Handle; HINSTANCE m_h. Current. Resource. Handle; LPCTSTR m_lpsz. Current. App. Name;
Module State (cont’d) BYTE m_b. DLL; // TRUE if module is a DLL, FALSE if it is an EXE BYTE m_b. System; // TRUE if module is a "system" module BYTE m_b. Reserved[2]; // padding DWORD m_f. Registered. Classes; // flags for registered window // runtime class data #ifdef _AFXDLL CRuntime. Class* m_p. Class. Init; #endif CTyped. Simple. List
Thread State v Definition(AFXSTAT_. H) Ø AFX_THREAD_STATE ü ü ü 현재의 module state에 대한 pointer 이전의 module state에 대한 pointer Message관련 정보 Interrupt된 후에 recovery를 위한 모든 정보 …
Thread State (cont’d) class _AFX_THREAD_STATE : public CNo. Track. Object { public: _AFX_THREAD_STATE(); virtual ~_AFX_THREAD_STATE(); AFX_MODULE_STATE* m_p. Module. State; AFX_MODULE_STATE* m_p. Prev. Module. State; void* m_p. Safety. Pool. Buffer; // current buffer AFX_EXCEPTION_CONTEXT m_exception. Context; CWnd* m_p. Wnd. Init; CWnd* m_p. Alternate. Wnd. Init; // special case commdlg hooking DWORD m_dw. Prop. Style; DWORD m_dw. Prop. Ex. Style; HWND m_h. Wnd. Init; BOOL m_b. Dlg. Create; HHOOK m_h. Hook. Old. Cbt. Filter; HHOOK m_h. Hook. Old. Msg. Filter;
Thread State (cont’d) MSG m_last. Sent. Msg; // see CWnd: : Window. Proc HWND m_h. Tracking. Window; // see CWnd: : Track. Popup. Menu HMENU m_h. Tracking. Menu; TCHAR m_sz. Temp. Class. Name[96]; // see Afx. Register. Wnd. Class HWND m_h. Lockout. Notify. Window; // see CWnd: : On. Command BOOL m_b. In. Msg. Filter; CView* m_p. Routing. View; // see CCmd. Target: : Get. Routing. View CFrame. Wnd* m_p. Routing. Frame; // see CCmd. Target: : Get. Routing. Frame BOOL m_b. Wait. For. Data. Source; CTool. Tip. Ctrl* m_p. Tool. Tip; CWnd* m_p. Last. Hit; // last window to own tooltip int m_n. Last. Hit; // last hittest code TOOLINFO m_last. Info; // last TOOLINFO structure int m_n. Last. Status; // last flyby status message CControl. Bar* m_p. Last. Status; // last flyby status control bar };
MFC States들의 연관 v Afx. Get. Thread. State() Ø Ø Ø AFXSTAT. CPP 현재의 AFX_THREAD_STATE를 얻을 때 사용 _afx. Thread. State이용 ü THREAD_LOCAL(_AFX_THREAD_STATE, _afx. Thread. State)
MFC States들의 연관 (cont’d) v Afx. Get. Module. State() Ø Ø Ø AFXSTAT. CPP AFX_MODULE_STATE를 얻을 때 사용 내부적으로 _afx. Thread. State를 이용 ü ü ü Thread state에는 현재의 module state에 대한 pointer 가 존 재 만약 NULL이면 _afx. Base. Module. State를 이용 PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afx. Base. Module. State)
MFC States들의 연관 (cont’d) _AFX_THREAD_STATE* AFXAPI Afx. Get. Thread. State() { return _afx. Thread. State. Get. Data(); } AFX_MODULE_STATE* AFXAPI Afx. Get. Module. State() { _AFX_THREAD_STATE* p. State = _afx. Thread. State; AFX_MODULE_STATE* p. Result; if (p. State->m_p. Module. State != NULL) { p. Result = p. State->m_p. Module. State; } else { p. Result = _afx. Base. Module. State. Get. Data(); } return p. Result; }
MFC DLLs v MFC 2. 0 Ø USRDLL ü ü ü Ø DLL에 static하게 link됨 MFC code의 사용 가능 크기가 매우 커짐(MFC 관련 code를 모두 포함) AFXDLL ü ü 자체에서 MFC를 제공하지 않음 Application이 MFC DLL을 link해야 함
DLL의 종류 v MFC 4. 0 이후 Ø Regular DLL ü ü Ø Static하게 link(USRDLL) Dynamic하게 link C style의 함수만 export가능 MFC사용은 가능 Extension DLL ü ü ü C++ interface 지원(Class를 export할 수 있다. ) Dynamic하게 link 기존의 AFXDLL
DLL Resource Issues v Resource load시 Ø Ø 바로 찾지 않고 Afx. Find. Resource. Handle()함수를 이용 Afx. Find. Resource. Handle() ü Ø Load된 extension DLL중에서 원하는 resource를 찾음 그러면 extension DLL의 list는 어떤식으로 관리되는가 ?
DLL Resource Issues (cont’d) v Dll. Main()함수 Ø Ø DLL이 load될 때 호출됨 core. DLL은 AFX_EXTENSION_MODULE ü AFXDLL_. H Afx. Init. Extension. Module(core. DLL, h. Instance) CDyn. Link. Library* p. DLL = new CDyn. Link. Library(core. DLL, TRUE); struct AFX_EXTENSION_MODULE { BOOL b. Initialized; HMODULE h. Module; HMODULE h. Resource; CRuntime. Class* p. First. Shared. Class; COle. Object. Factory* p. First. Shared. Factory; };
DLL Resource Issues (cont’d) Ø Afx. Init. Extension. Module()(DLLINIT. CPP) ü Ø h. Module과 h. Resource에 instance handle assign CDyn. Link. Library ü ü Declaration(AFXDLL_. H) Implementation(DLLINIT. CPP) Ø Ø Constructor에서 module state의 library list에 자신을 추가 결국 module state에 CDyn. Link. Library object의 list가 관리됨 ü Afx. Find. Resource. Handle()는 이 list를 이용
DLL Resource Issues (cont’d) BOOL AFXAPI Afx. Init. Extension. Module(AFX_EXTENSION_MODULE& state, HMODULE h. Module) { if (state. b. Initialized) { Afx. Init. Local. Data(h. Module); return TRUE; } state. b. Initialized = TRUE; state. h. Module = h. Module; state. h. Resource = h. Module; AFX_MODULE_STATE* p. Module. State = Afx. Get. Module. State(); state. p. First. Shared. Class = p. Module. State->m_class. List. Get. Head(); p. Module. State->m_class. List. m_p. Head =p. Module. State->m_p. Class. Init; state. p. First. Shared. Factory = p. Module. State->m_factory. List. Get. Head(); p. Module. State->m_factory. List. m_p. Head= p. Module. State->m_p. Factory. Init; return TRUE; }
DLL Resource Issues (cont’d) class CDyn. Link. Library : public CCmd. Target { DECLARE_DYNAMIC(CDyn. Link. Library) public: // Constructor CDyn. Link. Library(AFX_EXTENSION_MODULE& state, BOOL b. System = FALSE); // Attributes HMODULE m_h. Module; HMODULE m_h. Resource; // for shared resources CTyped. Simple. List
DLL Resource Issues (cont’d) CDyn. Link. Library: : CDyn. Link. Library(AFX_EXTENSION_MODULE& state, BOOL b. System) { m_factory. List. Construct(offsetof(COle. Object. Factory, m_p. Next. Factory)); m_class. List. Construct(offsetof(CRuntime. Class, m_p. Next. Class)); m_h. Module = state. h. Module; m_h. Resource = state. h. Resource; m_class. List. m_p. Head = state. p. First. Shared. Class; m_factory. List. m_p. Head = state. p. First. Shared. Factory; m_b. System = b. System; // insert at the head of the list (extensions will go in front of core DLL) Afx. Lock. Globals(CRIT_DYNLINKLIST); m_p. Module. State->m_library. List. Add. Head(this); Afx. Unlock. Globals(CRIT_DYNLINKLIST); }
DLL Resource Issues (cont’d) HINSTANCE AFXAPI Afx. Find. Resource. Handle(LPCTSTR lpsz. Name, LPCTSTR lpsz. Type) { HINSTANCE h. Inst; // check for non-system DLLs in proper order AFX_MODULE_STATE* p. Module. State = Afx. Get. Module. State(); Afx. Lock. Globals(CRIT_DYNLINKLIST); for (CDyn. Link. Library* p. DLL = p. Module. State->m_library. List; p. DLL != NULL; p. DLL = p. DLL->m_p. Next. DLL) { if (!p. DLL->m_b. System && p. DLL->m_h. Resource != NULL && : : Find. Resource(p. DLL->m_h. Resource, lpsz. Name, lpsz. Type) != NULL) { // found it in a DLL Afx. Unlock. Globals(CRIT_DYNLINKLIST); return p. DLL->m_h. Resource; } } }
MFC Threads v MFC Thread의 종류 Ø Worker thread ü Ø User-interface thread ü Ø 일반적으로 말하는 thread Message loop을 가지고 user-interface를 관장하는 thread Afx. Begin. Thread()함수를 이용하여 생성됨
Worker Threads v Afx. Begin. Thread()(THRDCORE. CPP) Ø Ø Ø v CWin. Thread object생성 CWin. Thread: : Create. Thread()호출 CWin. Thread: : Set. Thread. Priority()호출 CWin. Thread Ø Ø Declaration(AFXWIN. H) Implementation(THRDCORE. CPP)
Worker Threads (cont’d) ü CWin. Thread: : Create. Thread() Ø Ø _AFX_THREAD_STARTUP structure이용 _beginthreadex() library function을 이용
Worker Threads (cont’d) CWin. Thread* AFXAPI Afx. Begin. Thread(AFX_THREADPROC pfn. Thread. Proc, LPVOID p. Param, int n. Priority, UINT n. Stack. Size, DWORD dw. Create. Flags, LPSECURITY_ATTRIBUTES lp. Security. Attrs) { CWin. Thread* p. Thread = DEBUG_NEW CWin. Thread(pfn. Thread. Proc, p. Param); if (!p. Thread->Create. Thread(dw. Create. Flags|CREATE_SUSPENDED, n. Stack. Size, lp. Security. Attrs)) { p. Thread->Delete(); return NULL; } VERIFY(p. Thread->Set. Thread. Priority(n. Priority)); if (!(dw. Create. Flags & CREATE_SUSPENDED)) VERIFY(p. Thread->Resume. Thread() != (DWORD)-1); return p. Thread; }
User-Interface Threads v Worker thread와의 차이점 Ø Ø v User events에 대한 반응 User input의 처리 과정 Ø Ø CWin. Thread에서 상속받아야 함 다음의 함수를 이용 ü ü Exit. Instance(), Init. Instance() On. Idle(), Pre. Translate. Message(), Run()
User-Interface Threads (cont’d) v v CWin. App도 하나의 user-interface thread임 CWin. Thread: : Run()(THRDCORE. CPP) Ø Message queue에 message가 있을때와 없을때의 수행 코드로 나뉨 ü Message가 없을때 On. Idle()함수 호출
User-Interface Threads (cont’d) v Idle processing Ø CWin. Thread: : On. Idle()(THRDCORE. CPP) ü ü v Message dispatch Ø Ø v Override하면 자신의 On. Idle()함수가 호출됨 Argument 가 음수이면 UI를 update함(즉, user interface update는 idle time에 이루어짐) Idle아닐 때 Pump. Message()함수 이용 Thread의 종료는 WM_QUIT message


