使用mfc - 國立臺灣大學d92005/visualcpp_slide/mfc.pdf · 在vc++中的file選new,...

40
使用 使用 MFC MFC 在視窗程式的執行過程中, 使用者與程式 行間的關係是一個交互影響的過程. 整個視窗大致可分為兩個部份, 一是視窗框架, 二是客戶區

Upload: others

Post on 16-Apr-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

  • 使用使用MFCMFC

    在視窗程式的執行過程中, 使用者與程式 執行間的關係是一個交互影響的過程.整個視窗大致可分為兩個部份, 一是視窗框架, 二是客戶區

  • 如何撰寫視窗程式如何撰寫視窗程式

    利用AF(Application Frameworks)簡稱應用軟體架構因為AF本身就是一個很複雜的類別階層, 而運用AF的方法就是利用類別的繼承

    CObject

    應用程式類別

    視窗類別

    繪圖類別 容器類別 其他類別

  • 如何撰寫視窗程式如何撰寫視窗程式

    應用程式類別: 定義了建立應用程式可能需要利用的類別, 如:CWinApp(視窗應用程式類別), CDocTemplate(文件範本類別)等等.視窗程式類別: 定義了建構視窗所需的類別如:CFrameWnd(視窗框架類別),CDialog(對話盒類別),CView(瀏覽類別)等等.繪圖類別: 用於畫圖的類別, 如:CDC(裝置內文類別),Cpen(畫筆類別),Cbrush(畫刷類別)等等.容器類別: Clist,Carry,Cmap等容器類別.其他類別: ODBC資料庫類別.

  • 如何撰寫視窗程式如何撰寫視窗程式

    要使用MFC類別時,必需要先載入afcwin的標頭檔

    當我們要撰寫視窗程式時必需要建立兩種物件

    一是繼承CWinApp的應用程式物件二是繼承CFrameWnd的視窗框架物件

  • 如何撰寫視窗程式如何撰寫視窗程式

    每一個程式都只有一個應用程式類別(CWinApp), 這個應用程式類別用於產生應用程式物件, 且是程式的進入點. 當建立了應用程式物件後, 將由該物件負責視窗框架物件的建立, 且應用程式類別將有一個屬性指向所使用的視窗框架物件.

    應用程式物件Pointer

    視窗框架物件

  • MFCMFC的的ExampleExample

    #include //載入afxwin標頭檔

    class MyApp : public CWinApp //繼承CWinApp{public:

    BOOL InitInstance() //程式進入點{

    CFrameWnd *Frame = new CFrameWnd(); //建立CFrameWnd物件(產生)m_pMainWnd = Frame; //將m_pMainWnd設定為Frame

    Frame->Create(NULL,“Hello MFC”); //建立視窗(建立)Frame->ShowWindow(SW_SHOW);

    return true;}

    };

    MyApp a_app; //建立應用程式物件

  • 程式說明程式說明

    要如何自定應用程式類別???1. 繼承CWinApp類別2. 重載CWinApp::IninInstance函數, 此函數為視窗程式的進入點, 回傳值的型態為BOOL

    class MyApp : public CWinApp //繼承CWinApp{public:

    BOOL InitInstance() //程式進入點{…}

    };

  • 程式說明程式說明

    CWinApp::m_pMainWnd屬性, 這個屬性將指向應用程式所使用的視窗框架物件.

    CWinApp::IninInstance函數, 在該函數中完成下列工作.

    1. 產生視窗框架物件

    2. 將該視窗框架物件的指標,設定給CWinApp::m_pMainWnd屬性3. 在螢幕中建立視窗框架

    4. 顯示視窗框架物件

  • 程式說明程式說明

    BOOL InitInstance() //程式進入點{

    CFrameWnd *Frame = new CFrameWnd(); //建立CFrameWnd物件

    m_pMainWnd = Frame; //將m_pMainWnd設定為Frame

    Frame->Create(NULL,"Hello MFC"); //建立視窗Frame->ShowWindow(SW_SHOW);return true;}

    建立應用程式物件

    MyApp a_app; //建立應用程式物件

  • 建立自訂視窗建立自訂視窗

    當您想要建立一個自定的視窗框架時, 您必須建立一個繼承於CFrameWnd類別的視窗框架類別, 然後將視窗組合出自定的視窗類別.在此範例我們不直接利用CFrameWnd類別, 而是使用繼承的方式, 由CFrameWnd類別衍生出自定的MyFrame類別.

  • MyFrameMyFrame程式範例程式範例#include #include "MyFrame.h" //由資源編輯器所產生的標頭檔

    class MyFrame : public CFrameWnd //繼承CFrameWnd類別{private:

    CMenu *FMenu;public:

    MyFrame(){

    Create(NULL,"Hello MFC"); //建立視窗FMenu = new CMenu; //產生選單FMenu->LoadMenu(IDR_MENU1); //載入選單SetMenu(FMenu); //設定視窗所使用的選單

    }};

  • MyFrameMyFrame程式範例程式範例

    class MyApp : public CWinApp{public:

    BOOL InitInstance(){

    CFrameWnd *Frame = new MyFrame; //產生視窗m_pMainWnd = Frame; //將視窗物件設定給應用程式

    Frame->ShowWindow(SW_SHOW); //顯示視窗

    return true;}

    };MyApp a_app; //建立應用程式物件

  • 資源檔的設定與使用資源檔的設定與使用

    1. 在VC++中的File選New, 再點選Files中的Resource Template進行script的編輯.

    2. 再點選Insert中的Resource進行資源檔的編輯.3. 編輯完畢後, 再將script存成*.rc的檔案格式, 再到Resource Files中將剛才存檔的.rc import進來即可.

  • 程式說明程式說明

    我們將利用MyFrame程式範例介紹下列重點1. 視窗框架與資源檔

    2. 視窗元件的使用

  • 程式說明程式說明

    在上述程式中在MyFrame類別中, 亦有一個指向Cmenu物件的FMenu指標屬性,當您要操作該選單時(如: 新增, 刪除等等)可透過CMenu來完成.

    而在第17行利用LoadMenu將定義在資源檔中的選單代號載入, 再利用SetMenu函數將Fmneu設定為視窗使用的選單

  • 程式說明程式說明

    在視窗框架類別中是負責產生應用程式物件所使用的視窗框架物件, 也就是應用程式的視窗介面, 所以資源檔中定義的資源大部份都是建立視窗框架時所用的元件

    #include "MyFrame.h"//由資源編輯器所產生的標頭檔

  • 程式說明程式說明

    // Used by MyFrame.rc#define IDR_MENU1 101#define ID_Exit 40001

    // Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE 102#define _APS_NEXT_COMMAND_VALUE 40002#define _APS_NEXT_CONTROL_VALUE 1000#define _APS_NEXT_SYMED_VALUE 101#endif#endif

  • 視窗的訊息傳遞與處理視窗的訊息傳遞與處理

    在視窗作業系統下, 作業系統將不斷由電腦系統的週邊裝置得到訊息, 就連您輕輕的移動了一下滑鼠, 作業系統也會收到滑鼠移動的訊息.

    在多而繁雜的訊息中, 如何讓應用程式知道究竟哪些訊息要回應? 要如何回應呢? 這要透過訊息映射表的建立.

  • 視窗訊息的種類視窗訊息的種類

    回應訊息與處理函數分為兩種1. 標準系統訊息

    標準系統訊息是由作業系統所產生的訊息, 比如: 移動滑鼠或按下滑鼠左鍵…等. 而接收並處理這類標準系統訊息的類別, 必須衍生自CWnd類別.定義的方式通常以ON_WM_XXX方式定義BEGIN_MESSAGE_MAP(類別名稱,基礎類別名稱)

    ON_WM_LBUTTONDOWN()ON_WM_MOUSEMOVE()ON_WM_LBUTTONUP()

    END_MESSAGE_MAP()

  • 視窗訊息的種類視窗訊息的種類

    而回應系統訊息名稱, MFC均已定義, 其宣告方式如下

    afx_msg void OnLButtonDown(UINT nFlags, CPoint point){……; }//當滑鼠左鍵按下後的回應函數,取得滑鼠訊息接收權

    其中nFlags與point為傳入函數的參數.

  • 視窗訊息的種類視窗訊息的種類

    2. 命令訊息

    命令訊息大致上是指由使用者自行定義的選單.工具列.控制項…等視窗元件, 被選取時所產生的訊息. 回應這類訊息的類別必須衍生自CCmdTarget類別. 這類訊息回息回應項目的定義方式如下:BEGIN_MESSAGE_MAP類別名稱,基礎類別名稱)

    ON_COMMAND(訊息代號,回應函數)

    …END_MESSAGE_MAP()

  • 視窗訊息的種類視窗訊息的種類

    命令訊息必須在建立該命令時, 即建立一個代號, 這個代號, 就是建立資源物件時設定的資源代號, 比如: 我們在定義File選單的Exit選項為ID_EXIT1. 而回應函數的名稱也必須由我們定義,比如: 我們在定義File選單的Exit函數名稱為ONExit. 而在宣告這類訊息處理函數時, 我們必須在該函數前加afx_msg, 定義方式如下:afx_msg void 回應函數名稱(參數…)ex:afx_msg void OnExit() //ID_EXIT1的回應函數對於一些大部份視窗程式常用到的命令, MFC亦定義了代號(Standard Command Ids)

  • 訊息映射表的建立訊息映射表的建立

    DECLARE_MESSAGE_MAP() //宣告訊息映射表然後在類別外宣告所處理的訊息, 以及處理函數.

    BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)//建立MyFrame類別的訊息映射表

    訊息回應項目

    …END_MESSAGE_MAP()

  • 訊息映射表的建立訊息映射表的建立

    class MyFrame : public CFrameWnd{ …

    DECLARE_MESSAGE_MAP()//宣告訊息映表};

    BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)//建立MyFrame類別的訊息映射表

    ON_COMMAND(ID_Exit1, OnExit)ON_WM_LBUTTONDOWN()ON_WM_MOUSEMOVE()ON_WM_LBUTTONUP()

    END_MESSAGE_MAP()

    函數名稱

    訊息代號

  • MouseMouse訊息傳入的參數訊息傳入的參數

    Mouse訊息產生時,幾個特殊按鍵利用nFlags傳入,而Mouse的座標則經由point傳入

    旗標 說明

    MK_CONTROL 鍵盤上的CTRL被按下

    MK_MBUTTON Mouse的中間按鍵被按下

    MK_RBUTTON Mouse的右邊按鍵被按下

    MK_SHIFT 鍵盤上的shift被按下

  • 繪圖相關說明繪圖相關說明

    1. SetCapture(); //當滑鼠左鍵按下後的回應函數,取得滑鼠訊息接收權

    2. CClientDC aDC(this); //建立一個畫布aDC.SetPixel(point, RGB(255, 0 ,0));//利用SetPixel在畫布上點出紅點

    3. GetCapture() //判斷滑鼠游標是否在視窗之上4. ReleaseCapture() //當滑鼠左鍵放開後的回應函數,釋放滑鼠訊息接收權

  • MessageMessage程式範例程式範例

    #include #include "Message.h" //載入資源檔所使用之標頭檔

    class MyFrame : public CFrameWnd{ private:

    CMenu *FMenu;public:MyFrame() //建構子{ Create(NULL,"Hello MFC");

    FMenu = new CMenu;FMenu>LoadMenu(IDR_MENU1);SetMenu(FMenu);}~MyFrame(){ delete FMenu;}

    //解構子

    afx_msg void OnExit()//ID_EXIT1的回應函數

    {MessageBox("Exit1"); DestroyWindow();

    }afx_msg void OnLButtonDown(UINT nFlags, CPoint point){ SetCapture(); } //當滑鼠左鍵按下後的回應函數,取得滑鼠訊息接收權

    afx_msg void OnLButtonUp(UINTnFlags, CPoint point){ ReleaseCapture(); } //當滑鼠左鍵放開後的回應函數,釋放滑鼠訊息接收權

  • MessageMessage程式範例程式範例

    afx_msg void OnMouseMove(UINT nFlags, CPoint point){ //當滑鼠移動時的回應函數

    if (this == GetCapture())//判斷滑鼠游標是否在視窗之上

    {CClientDC aDC(this);//建立一個畫布aDC.SetPixel(point,

    RGB(255, 0 ,0));//利用SetPixel在畫布上點出紅點} }afx_msg void OnLButtonUp(UINTnFlags, CPoint point){ ReleaseCapture(); } //當滑鼠左鍵放開後的回應函數,釋放滑鼠訊息接收權

    DECLARE_MESSAGE_MAP()//宣告訊息映射表};

    class MyApp : public CWinApp//應用程式類別

    {public:

    BOOL InitInstance() //程式進入點

    {CFrameWnd *Frame = new MyFrame;m_pMainWnd = Frame;Frame>ShowWindow(SW_SHOW); //顯示視窗

    return true;}

    } a_app; //宣告應用程式物件

  • Document/ViewDocument/View的基本架構的基本架構

    Document/view(文件/瀏覽)的架構, 就是用來管理視窗介面下, 資料的儲存與顯示, 在分工上, Document物件用於管理視窗程式的資料儲存, 而View物件負責將Document儲存的資料正確顯示在視窗上.一個完整的視窗應用程式, 必須具備有應用程式類別(CWinApp).視窗框架類別(CFrameWnd).Document類別(文件類別).View類別(瀏覽類別).

  • Document/ViewDocument/View的基本架構的基本架構

    Document物件 View物件

    視窗框架物件應用程式物件

  • 重新整理重新整理

    1. 應用程式物件用於建立應用程式

    2. 視窗框架物件用於建立視窗介面

    3. Document物件用於運作.儲存資料4. View物件用於將Document物件顯示於視窗5. 從資料的角度來看, Document物件與View物件其實是一體的, 只是將資料的處理與顯示的工作分開

  • Document/ViewDocument/View架構圖架構圖應用程式物件

    Pointer指向

    文件樣版物件物件

    Pointer

    文件物件Pointer

    視窗框架物件Pointer

    1.產生

    3.產生 2.產生

    瀏覽物件

    Pointer

    4.產生

  • Document/ViewDocument/View程式範例程式範例

    #include #include "Doc_View.h"class MyDocument : public

    CDocument{DECLARE_DYNCREATE(MyDocu

    ment) //宣告run-time類別};IMPLEMENT_DYNCREATE(MyDoc

    ument, CDocument)//宣告MyDocument為run-time類別class MyView : public CView{public:

    void OnDraw(CDC * aDC)//必須過載的虛擬函數 { }DECLARE_DYNCREATE(MyView)/

    /宣告run-time類別};

    IMPLEMENT_DYNCREATE(MyView, CView)

    //宣告MyView為run-time類別

    class MyFrame : public CFrameWnd{

    DECLARE_DYNCREATE(MyFrame) //宣告run-time類別

    };IMPLEMENT_DYNCREATE(MyFra

    me, CFrameWnd)//宣告MyFrame為run-time

    類別

  • Document/ViewDocument/View程式範例程式範例

    class MyApp : public CWinApp{public:

    BOOL InitInstance(){CDocument *doc; //宣告指向文件的指標

    CSingleDocTemplate* DocTemplate; //宣告指向單文件樣版物件的指標

    DocTemplate = new CSingleDocTemplate( //建立具有單文件樣版物件

    IDR_MENU1, //用於單文件框架的資源代號

    RUNTIME_CLASS(MyDocument), //單文件視窗的Document

    RUNTIME_CLASS(MyFrame), //單文件視窗的視窗框架

    RUNTIME_CLASS(MyView)); //單文件視窗的ViewAddDocTemplate(DocTemplate);//將單文件樣版物件設定給MyAppdoc = DocTemplate->CreateNewDocument(); //建立新的文件

    m_pMainWnd = DocTemplate->CreateNewFrame( doc, NULL );//建立一個視窗框架DocTemplate->InitialUpdateFrame( (CFrameWnd*)m_pMainWnd, doc );//起始化視窗框架中的Viewm_pMainWnd->ShowWindow( SW_SHOW); //顯示視窗return true;}} a_app;//建立應用程式物件

  • 程式說明程式說明

    宣告Run-Time類別因為CSignleDocument在無法得知視窗框架物件.Vie w類別.Document類別的情況下,等到執行時才決定運用哪幾個類別的應用程式.

    宣告

    DECLARE_DYNAMIC(類別名稱)然後在該類別外做如下宣告

    IMPLEMENT_DYNAMIC(類別名稱,衍生類別名稱)

  • Document/ViewDocument/View架構的應用架構的應用視窗的重繪視窗的重繪

    #include #include "repaint.h"#include //定義樣版類別的標頭檔

    class MyDocument : public CDocument

    {public:

    CArray pArray;//容納滑鼠軌跡點的Array

    容器

    void AddPoint(CPoint p) //將軌跡點加到容器內

    { pArray.Add(p); }CPoint GetPoint(int i) //將軌跡點從容器中取出

    { return pArray[i]; }

    int GetSize(){ return pArray.GetSize(); }

    //取得容器的大小DECLARE_DYNCREATE(MyDocument) //宣告為run-time類別

    DECLARE_MESSAGE_MAP()//宣告訊息映射表

    };IMPLEMENT_DYNCREATE(MyDoc

    ument, CDocument)//建立run-time類別

    BEGIN_MESSAGE_MAP(MyDocument, CDocument)

    END_MESSAGE_MAP()//建立訊息映射表

  • Document/ViewDocument/View架構的應用架構的應用視窗的重繪視窗的重繪

    class MyView : public CView{public:void OnDraw(CDC * aDC) //過載

    OnDraw虛擬函數{MyDocument *doc = (MyDocument *)GetDocument();//取得目前Document物件的指標int num = doc->GetSize();//取得目前儲存的軌跡點點數int i;for(i = 0; i < num; ++i) //將Document中儲存的軌跡點重繪到視窗上

    {CPoint point = doc->GetPoint(i);aDC->SetPixel(point, RGB(255, 0 ,0));}}

    afx_msg void OnLButtonDown(UINT, CPointpoint){ SetCapture(); } //取得滑鼠訊息的接收權

    afx_msg void OnMouseMove(UINT, CPoint point){if (this == GetCapture()){CClientDC aDC(this);//建立畫布aDC.SetPixel(point, RGB(255, 0 ,0));//將點畫在畫布上MyDocument *doc = (MyDocument *)GetDocument();//取得目前Document物件的指標doc->AddPoint(point); //將軌跡點加入Document物件中}}

  • Document/ViewDocument/View架構的應用架構的應用視窗的重繪視窗的重繪

    afx_msg void OnLButtonUp(UINT, CPoint point){ ReleaseCapture(); }//釋放滑鼠訊息的接收權DECLARE_DYNCREATE(MyView) //宣告為run-time類別DECLARE_MESSAGE_MAP()//宣告訊息映射表};

    IMPLEMENT_DYNCREATE(MyView, CView)//建立run-time類別

    BEGIN_MESSAGE_MAP(MyView, CView)ON_WM_LBUTTONDOWN()ON_WM_MOUSEMOVE()ON_WM_LBUTTONUP()

    END_MESSAGE_MAP()//建立訊息映射表

    class MyFrame : public CFrameWnd{public:

    DECLARE_DYNCREATE(MyFrame) //宣告為run-time類別DECLARE_MESSAGE_MAP()

    //宣告訊息映射表};

    IMPLEMENT_DYNCREATE(MyFrame, CFrameWnd)//建立run-time類別

    BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)

    END_MESSAGE_MAP()//建立訊息映射表

  • Document/ViewDocument/View架構的應用架構的應用視窗的重繪視窗的重繪

    class MyApp : public CWinApp{public:

    BOOL InitInstance(){CDocument *doc;CSingleDocTemplate* DocTemplate;DocTemplate = new CSingleDocTemplate( //單文件樣版類別

    IDR_MENU1,RUNTIME_CLASS(MyDocument),RUNTIME_CLASS(MyFrame), RUNTIME_CLASS(MyView));AddDocTemplate(DocTemplate);//將文件樣版物件加入應用程式

    doc = DocTemplate->CreateNewDocument(); //建立新文件

    m_pMainWnd = DocTemplate->CreateNewFrame( doc, NULL );//建立新的視窗框架DocTemplate->InitialUpdateFrame( (CFrameWnd*)m_pMainWnd, doc );//起始化View物件m_pMainWnd->ShowWindow( SW_SHOW ); //顯示視窗

    return true;}

    } a_app;

  • 程式說明程式說明

    利用MFC所提供的容器類別 Carray類別, 將滑鼠在視窗中移動時, 傳入的軌跡點存起來.Carray的宣告方式:Carray函數說明

    void AddPoint(Cpoint p)//將軌跡點加入容器中.Cpoint GetPoint(int i)//從容器中取得軌跡點.Int GetSize()//取得軌跡點的大小.