1 / 143

視窗程式設計

視窗程式設計. 第六章 進階繪圖與編輯控制. 大 綱. 簡介 建立繪圖師專案-可捲動展視窗 建立抽象圖形類別 建立特定圖形類別-由抽象而入具體 圖形編輯 繪圖師 之 文件管理 繪圖師 之 編輯控制 圖形選取-圖形調整與位移 展示窗變動處理 其它進階功能-思考與練習 結論. 第六章 進階繪圖與編輯控制. 簡介. 各種視窗程式設計之優劣比較. 高階發展工具 學習容易 無法隨心所欲,低階行為不易控制,執行效率偏低 Win32 執行檔小,效率高 隨心所欲,但學習困難,發展費時 MFC( 相較於 Win32) 執行檔稍大,效率稍差

Download Presentation

視窗程式設計

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 視窗程式設計 第六章 進階繪圖與編輯控制

  2. 大 綱 • 簡介 • 建立繪圖師專案-可捲動展視窗 • 建立抽象圖形類別 • 建立特定圖形類別-由抽象而入具體 • 圖形編輯 • 繪圖師之文件管理 • 繪圖師之編輯控制 • 圖形選取-圖形調整與位移 • 展示窗變動處理 • 其它進階功能-思考與練習 • 結論

  3. 第六章進階繪圖與編輯控制 簡介

  4. 各種視窗程式設計之優劣比較 • 高階發展工具 • 學習容易 • 無法隨心所欲,低階行為不易控制,執行效率偏低 • Win32 • 執行檔小,效率高 • 隨心所欲,但學習困難,發展費時 • MFC(相較於Win32) • 執行檔稍大,效率稍差 • 隨心所欲,且學習容易,發展省時

  5. 定義C++類別的重要諸元 • 定義適當的外部成員資料/函式 • 定義適當的虛擬函式 • 將功能抽象化 (abstract class) • 可改寫(overridable) • 定義適當的輔助函式(helper functions) • 內部經常被呼叫的功能 • 妥善的掌握 • 自動狀態機觀念

  6. 程式製作原則 • 減少鋸齒層次 • 以歪至多一次為原則 • 歪一次以上請檢討程式製作方式或規劃完善的演算法後進行實作 • 每一實作單元在一畫面上能完整呈現

  7. 本章範例—繪圖師專案 檢視完成後之結果

  8. 第六章進階繪圖與編輯控制 建立繪圖師專案-可捲動展視窗

  9. 專案建立選項 • 專案名稱為Painter • “File Extention”欄位鍵入“pnt” • CPainterView類別,將其Base class選為CScrollView 編譯執行觀察捲軸變化

  10. sizeTotal.cx sizeTotal.cy 文件的尺寸與座標系

  11. 文件的尺寸與座標系 void CPainterView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = sizeTotal.cy = 100; SetScrollSizes(MM_TEXT, sizeTotal); }

  12. 文件的尺寸與座標系 voidSetScrollSizes( intnMapMode, //座標系別 SIZEsizeTotal, //文件尺寸 constSIZE&sizePage=sizeDefault, //頁尺寸 constSIZE&sizeLine=sizeDefault //行尺寸 );

  13. 座標系模式

  14. 設定座標系之相關函式 • CDC::SetMapMode() • CDC::SetWindowExt() • CDC::SetWindowOrg() • CDC::SetViewportExt() • CDC::SetViewportOrg()

  15. 文件尺寸文件管理與展視窗類別各司其職 • 文件管理類別 • 根據資料決定文件尺寸 • 展視窗類別 • 根據文件尺寸相關資料,設定相關模式後呈現文件內容

  16. 文件管理類別的尺寸管理 class CPainterDoc : public CDocument { . . . . . . . . . . . . . . . . . . // Attributes public: CSize m_sizePage; // Operations CSize GetPageSize() {return m_sizePage;} . . . . . . . . . . . . . . . . . . };

  17. 文件管理類別的尺寸管理 BOOL CPainterDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; // use MM_HIMETRIC // A4 size paper 210mm x 297 mm m_sizePage.cx=21000; //x-軸向右為正 m_sizePage.cy=29700; //y-軸向下為正 return TRUE; }

  18. 展現窗相關諸元 void CPainterView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); SetScrollSizes(MM_HIMETRIC, GetDocument()->GetPageSize()); }

  19. 展現窗功能測試 void CPainterView::OnDraw(CDC* pDC) { . . . . . . . . . . . . . . //以下程式碼測試完成後移去 CRect rect(0, 0, 21000, -29700); //矩形繪圖位置 rect.NormalizeRect(); //矩形座標正規化 rect.InflateRect(-1500,-1500); //壓縮矩形 pDC->Rectangle(&rect); //繪製矩形 }

  20. 展視窗之比例配合 • 捲軸視窗之比例配合功能 CScrollView::SetScrollToFitSize()

  21. 功能表增加檢視方法選項 • 於IDR_MAINFRAME功能表中加入 ﹝檢視(V)﹞|﹝整頁模式顯示(F)﹞選項,其ID設為ID_VIEW_FULLPAGE。 • 於CPainterDoc定義中宣告屬性為public,型態為BOOL之成員變數m_bViewFullPage。 • 於CPainterDoc::OnNewDocument()中將成員變數m_bViewFullPage設為FALSE。

  22. 變更功能表顯示內容 • 於PainterDoc.h檔前端定義以下巨集: // 呼叫 UpdateAllViews() 之提示 #define UV_NONE 0 #define UV_SCALING 1 // 功能表文字 #define STR_VIEW_FULLPAGE _T("整頁模式顯示") #define STR_VIEW_NOSCALING _T("原比例顯示")

  23. ID_VIEW_FULLPAGE命令處理與介面更新 void CPainterDoc::OnViewFullpage() { m_bViewFullPage = !m_bViewFullPage; SetModifiedFlag(); UpdateAllViews(NULL, UV_SCALING); } void CPainterDoc::OnUpdateViewFullpage(CCmdUI* pCmdUI) { pCmdUI->SetText(m_bViewFullPage ? STR_VIEW_NOSCALING : STR_VIEW_FULLPAGE); }

  24. void CDocument::UpdateAllViews( CView* pSender, //更改文件內容之展視窗LPARAM lHint = 0L, //長整數重繪提示CObject* pHint = NULL //物件指標重繪提示); 文件變動引發之重繪與提示命令

  25. void CView::OnUpdate( CView* pSender, //更改文件內容之展視窗LPARAM lHint, //長整數重繪提示CObject* pHint //物件指標重繪提示); 文件變動引發之重繪與提示命令處理

  26. 展視窗文件更新之重繪處理 void CPainterView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { CPainterDoc* pDoc=GetDocument(); CSize sizeDoc=pDoc->GetPageSize(); switch(lHint){ case UV_SCALING: if(pDoc->m_bViewFullPage) SetScaleToFitSize(sizeDoc); else SetScrollSizes(MM_HIMETRIC, sizeDoc); break; default: CScrollView::OnUpdate(pSender, lHint, pHint); break; } }

  27. 展視窗為何不能正常工作? void CPainterView::OnDraw(CDC* pDC) { . . . . . . . . . . . . . . //以下程式碼測試完成後移去 CRect rect(0, 0, 21000, -29700); //矩形繪圖位置 rect.NormalizeRect(); //矩形座標正規化 rect.InflateRect(-1500,-1500); //壓縮矩形 pDC->Rectangle(&rect); //繪製矩形 } DC被動了什麼手腳?哪裡有錯?

  28. CXxxView之WM_PAINT訊息處理函式 void CView::OnPaint() { // standard paint routine CPaintDC dc(this); //建立繪圖DC OnPrepareDC(&dc);//打點繪圖DC OnDraw(&dc); //呼叫OnDraw()虛擬函式 }

  29. 打點畫布(DC) • CView::OnPrepareDC()啥事都沒作 。 • CScrollView::OnPrepareDC()您認為為我們做了些什麼 ? • 您能自力找出CScrollView::SetScrollToFitSize()無法正常工作的原因嗎?

  30. 斧底抽薪檢視原始碼 void CScrollView::SetScaleToFitSize(SIZE sizeTotal) { // Note: It is possible to set sizeTotal members to negative //values to effectively invert either the X or Y axis. ASSERT(m_hWnd != NULL); m_nMapMode = MM_SCALETOFIT; // special internal value (-1) m_totalLog = sizeTotal; // 作者加註:記錄文件大小(邏輯單位) . . . . . . . . . . . . . } 線上說明居然有誤

  31. 請再試試 恍然大悟後 void CPainterView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { CPainterDoc* pDoc=GetDocument(); CSize sizeDoc=pDoc->GetPageSize(); switch(lHint){ case UV_SCALING: if(pDoc->m_bViewFullPage){ sizeDoc.cy = -sizeDoc.cy; SetScaleToFitSize(sizeDoc); } else SetScrollSizes(MM_HIMETRIC, sizeDoc); break; . . . . . . . . . . . . . . . . . . . . } }

  32. 效果當不理想怎麼辦? • CScrollView::SetScrollToFitSize()無等比例縮放功能? • 未做置中處理 • 該如何補救?

  33. 檢視原始碼 void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { . . . . . . . . . . . . . . . . . switch (m_nMapMode) { case MM_SCALETOFIT: pDC->SetMapMode(MM_ANISOTROPIC); //實際模式 //以下為設定xy-軸顯示比例之原始碼 . . . . . . . . . . . . . . . . break; default: ASSERT(m_nMapMode > 0); pDC->SetMapMode(m_nMapMode); break; } //以下為設定原點之原始碼 . . . . . . . . . . . . . . . . . } 無法等比例縮放的原因

  34. 改造(OnPrepareDC) #define MM_SCALETOFIT (-1) void CPainterView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { if(m_nMapMode!=MM_SCALETOFIT){ CScrollView::OnPrepareDC(pDC, pInfo); //呼叫原函式 return; } . . . . . . . . . . . . . . . . . }

  35. 改造(OnPrepareDC) pDC->SetMapMode(MM_ISOTROPIC); //原為MM_ANISOTROPIC //設定文件邏輯單位尺寸與圖素單位尺寸比 pDC->SetWindowExt(m_totalLog); //設定視窗座標範圍 CRect rect; GetClientRect(&rect); //得取文件所在視窗大小 pDC->SetViewportExt(rect); //設定viewport座標範圍

  36. 改造(OnPrepareDC) //設定原點 //計算文件以圖素為單位的尺寸 m_totalDev=m_totalLog; m_totalDev.cx=abs(m_totalDev.cx);//取正值 m_totalDev.cy=abs(m_totalDev.cy);//取正值 pDC->LPtoDP(&m_totalDev); //將尺寸轉為圖素單位 CPoint ptVpOrg(0, 0); if (m_bCenter) //新發現(線上說明未說明此成員資料用途) {//計算新原點位置,將文件置於視窗中間 ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2; ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2; } pDC->SetViewportOrg(ptVpOrg); //設定viewport原點 CView::OnPrepareDC(pDC, pInfo); }

  37. Wext.cx VPext.cx VPext.cy Wext.cy 縮放比設定 Viewport Extension Window Extension

  38. 縮放比設定 • CDC::SetWindowExt() • CDC::SetViewportExt()

  39. Wext.cx VPext.cx VPext.cy Wext.cy 原點設定 CDC::SetWindowOrg() CDC::SetViewportOrg()

  40. 邏輯座標與設備座標間之轉換 • CDC::DPtoLP() • CDC::LPtoDP()

  41. 再試試看 展視窗起始設定 void CPainterView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); m_bCenter=TRUE;//文件置中 CPainterDoc* pDoc=GetDocument(); CSize sizeDoc=GetDocument()->GetPageSize(); if(pDoc->m_bViewFullPage){ sizeDoc.cy=-sizeDoc.cy; SetScaleToFitSize(sizeDoc); } else SetScrollSizes(MM_HIMETRIC, sizeDoc); }

  42. 練 習 • 練習6.1 • 利用CDC::SetWindowOrg()達成整頁模式時文件置中的效果。 • 於功能表中設計一文件置中選項,撰寫相關處理程式。

  43. 文件區與非文件區辨識 BOOL CPainterView::OnEraseBkgnd(CDC* pDC) { CScrollView::OnEraseBkgnd(pDC); //忽叫原函式 int nOldDC=pDC->SaveDC(); //儲存DC狀態 OnPrepareDC(pDC); //將DC打點成目前模式 CRect rectClient; GetClientRect(&rectClient); //得取視窗矩形(圖素座標) pDC->DPtoLP(&rectClient); //圖素座標->邏輯座標 //取得文件區,將之設為繪圖保護區 CSize sizePage=GetDocument()->GetPageSize(); CRect rectPage(0, 0, sizePage.cx, -sizePage.cy); pDC->ExcludeClipRect(&rectPage); //文件區設為保護區

  44. 文件區與非文件區辨識 CBrush brush(GetSysColor(COLOR_APPWORKSPACE)); //以繪圖刷填充視窗用戶區,但保護區無法被繪入 pDC->FillRect(&rectClient, &brush); pDC->RestoreDC(nOldDC); //還原DC狀態 return TRUE; }

  45. 第六章進階繪圖與編輯控制 建立抽象圖形類別

  46. C++之虛擬函式 • 達成類別可被改造之功能 • 達成類別抽象化的目的

  47. 虛擬函式之宣告 class CMyClass1 { void fun1(); void fun2(); virtual void vfun1(); virtual void vfun2(); virtual void vfun3(); }; class CMyClass2 : public CMyclass1 { void fun1(); void vfun1(); virtual void vfun2(); }; class CMyClass3 : public CMyclass2 { void fun1(); void fun2(); virtual void vfun2(); virtual void vfun3(); };

  48. class CMyClass1 { void fun1(); void fun2(); virtual void vfun1(); virtual void vfun2(); virtual void vfun3(); }; class CMyClass2 : public CMyclass1 { void fun1(); void vfun1(); virtual void vfun2(); }; 虛擬函式之宣告 class CMyClass3 : public CMyclass2 { void fun1(); void fun2(); virtual void vfun2(); virtual void vfun3(); }; main() { CMyClass1 obj1; CMyClass2 obj2; CMyClass3 obj3; CMyClass1* p; p = &obj1; p->fun1(); p->fun2(); p->vfun1(); p->vfun2(); p->vfun3(); p = &obj2; p->fun1(); p->fun2(); p->vfun1(); p->vfun2(); p->vfun3(); p = &obj3; p->fun1(); p->fun2(); p->vfun1(); p->vfun2(); p->vfun3(); }

  49. 抽象類別 class CMyClass1 { void fun1(); void fun2(); virtual void vfun1() = 0; virtual void vfun2() = 0; virtual void vfun3(); }; 抽象類別不得有類別物件實體 CMyClass1 obj1;//不合法 CMyClass1* pObj1 = new CMyClass1;//不合法

  50. 抽象類別 class CMyClass1 { void fun1(); void fun2(); virtual void vfun1() = 0; virtual void vfun2() = 0; virtual void vfun3(); }; class CMyClass2 : public CMyClass1 { virtual void vfun1(); }; 一類別含任一抽象函式即為抽象類別 CMyClass1 obj1;//不合法 CMyClass1* pObj1 = new CMyClass1;//不合法 CMyClass2 obj2;//不合法 CMyClass2* pObj2 = new CMyClass2;//不合法

More Related