使用 使用 MFC MFC
在視窗程式的執行過程中, 使用者與程式 執 行間的關係是一個交互影響的過程.
整個視窗大致可分為兩個部份, 一是視窗框架,
二是客戶區
如何撰寫視窗程式 如何撰寫視窗程式
利用AF(Application Frameworks)簡稱應用軟體架構 因為AF本身就是一個很複雜的類別階層, 而運用AF的 方法就是利用類別的繼承
CObject
應用程式類別 視窗類別
繪圖類別 容器類別 其他類別
如何撰寫視窗程式 如何撰寫視窗程式
應用程式類別: 定義了建立應用程式可能需要利用的類 別, 如:CWinApp(視窗應用程式類別), CDocTemplate(文 件範本類別)等等.
視窗程式類別: 定義了建構視窗所需的類別
如:CFrameWnd(視窗框架類別),CDialog(對話盒類別), CView(瀏覽類別)等等.
繪圖類別: 用於畫圖的類別, 如:CDC(裝置內文類別), Cpen(畫筆類別),Cbrush(畫刷類別)等等.
容器類別: Clist,Carry,Cmap等容器類別.
其他類別: ODBC資料庫類別.
如何撰寫視窗程式 如何撰寫視窗程式
要使用MFC類別時,必需要先載入afcwin 的標頭檔
當我們要撰寫視窗程式時必需要建立兩 種物件
一是繼承CWinApp的應用程式物件
二是繼承CFrameWnd的視窗框架物件
如何撰寫視窗程式 如何撰寫視窗程式
每一個程式都只有一個應用程式類別
(CWinApp), 這個應用程式類別用於產生應用程 式物件, 且是程式的進入點. 當建立了應用程式 物件後, 將由該物件負責視窗框架物件的建立, 且應用程式類別將有一個屬性指向所使用的視 窗框架物件.
應用程式物件
Pointer
視窗框架物件
MFC MFC 的 的 Example Example
#include <afxwin.h> //載入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類別.
MyFrame
MyFrame 程式範例 程式範例
#include <afxwin.h>
#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); //設定視窗所使用的選單 }
};
MyFrame
MyFrame 程式範例 程式範例
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()
函數 名稱 訊息 代號
Mouse
Mouse 訊息傳入的參數 訊息傳入的參數
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() //當滑鼠左鍵放開後的回應函數,釋 放滑鼠訊息接收權
Message
Message 程式範例 程式範例
#include <afxwin.h>
#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(UINT nFlags, CPoint point)
{ ReleaseCapture(); } //當滑鼠 左鍵放開後的回應函數,釋放滑 鼠訊息接收權
Message
Message 程式範例 程式範例
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(UINT nFlags, 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/View
Document/View 的基本架構 的基本架構
Document/view(文件/瀏覽)的架構, 就是用來管 理視窗介面下, 資料的儲存與顯示, 在分工上, Document物件用於管理視窗程式的資料儲存, 而View物件負責將Document儲存的資料正確顯 示在視窗上.
一個完整的視窗應用程式, 必須具備有應用程 式類別(CWinApp).視窗框架類別
(CFrameWnd).Document類別(文件類別).View類
別(瀏覽類別).
Document/View
Document/View 的基本架構 的基本架構
Document物件 View物件
視窗框架物件 應用程式物件
重新整理 重新整理
1. 應用程式物件用於建立應用程式
2. 視窗框架物件用於建立視窗介面
3. Document物件用於運作.儲存資料
4. View物件用於將Document物件顯示於視窗
5. 從資料的角度來看, Document物件與View物件
其實是一體的, 只是將資料的處理與顯示的工
作分開
Document/View
Document/View 架構圖 架構圖
應用程式物件
Pointer
指向
文件樣版物件物件 Pointer
文件物件 Pointer 視窗框架物件
Pointer 1.產生
3.產生 2.產生 瀏覽物件
Pointer 4.產生
Document/View
Document/View 程式範例 程式範例
#include <afxwin.h>
#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(MyVie w, CView)
//宣告MyView為run-time類 別
class MyFrame : public CFrameWnd {
DECLARE_DYNCREATE(MyFra me) //宣告run-time類別
};
IMPLEMENT_DYNCREATE(MyFra me, CFrameWnd)
//宣告MyFrame為run-time 類別
Document/View
Document/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(MyVie w)); //單文件視窗的View
AddDocTemplate(DocTemplate);//
將單文件樣版物件設定給MyApp 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;//建立應用程 式物件
程式說明 程式說明
宣告Run-Time類別
因為CSignleDocument在無法得知視窗框架物件.Vie w 類別.Document類別的情況下,等到執行時才決定運用哪 幾個類別的應用程式.
宣告
DECLARE_DYNAMIC(類別名稱) 然後在該類別外做如下宣告
IMPLEMENT_DYNAMIC(類別名稱,衍生類別名稱)
Document/View
Document/View 架構的應用 架構的應用 視窗的重繪
視窗的重繪
#include <afxwin.h>
#include "repaint.h"
#include <afxtempl.h> //定義樣 版類別的標頭檔
class MyDocument : public CDocument
{
public:
CArray<CPoint, CPoint &> pArray;
//容納滑鼠軌跡點的Array 容器
void AddPoint(CPoint p) //將軌跡 點加到容器內
{ pArray.Add(p); }
CPoint GetPoint(int i) //將軌跡 點從容器中取出
{ return pArray[i]; }
int GetSize()
{ return pArray.GetSize(); } //取得容器的大小
DECLARE_DYNCREATE(MyDo cument) //宣告為run-time 類別
DECLARE_MESSAGE_MAP() //宣告訊息映射表
};
IMPLEMENT_DYNCREATE(MyDoc ument, CDocument)
//建立run-time類別
BEGIN_MESSAGE_MAP(MyDocum ent, CDocument)
END_MESSAGE_MAP() //建立訊息映射表
Document/View
Document/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, CPoint point)
{ 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/View
Document/View 架構的應用 架構的應用 視窗的重繪
視窗的重繪
afx_msg void OnLButtonUp(UINT, CPoint point){ ReleaseCapture(); } //釋放滑鼠訊息的接收權
DECLARE_DYNCREATE(MyVie w) //宣告為run-time類別
DECLARE_MESSAGE_MAP() //宣告訊息映射表};
IMPLEMENT_DYNCREATE(MyVie w, 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(MyFra me) //宣告為run-time類別
DECLARE_MESSAGE_MAP() //宣告訊息映射表
};
IMPLEMENT_DYNCREATE(MyFra me, CFrameWnd)
//建立run-time類別
BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)
END_MESSAGE_MAP() //建立訊息映射表
Document/View
Document/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()//取得軌跡點的大小.