Windows 應(yīng)用程序所要做的每項(xiàng)工作幾乎都是基于消息處理的, Windows 系統(tǒng)消息分為常用 Windows 消息,控件通知消息和命令。然而,有時(shí)我們需要定義自己的消息來通知程序什么事情發(fā)生了,這就是用戶自定義消息。 ClassWizard 并沒有提供增加用戶自定義消息的功能,所以要使用用戶自定義消息,必須手工編寫代碼。然后 ClassWizard 才可以象處理其它消息一樣處理你自定義的消息。具體做法如下詳解:
第一步:定義消息。一個(gè)消息實(shí)際上是開發(fā) Windows95 應(yīng)用程序時(shí), Microsoft 推薦用戶自定義消息至少是 WM_USER+100 ,因?yàn)楹芏嘈驴丶惨褂?WM_USER 消息。
第二步:實(shí)現(xiàn)消息處理函數(shù)。該函數(shù)使用 WPRAM 和 LPARAM 參數(shù)并返回 LPESULT 。
LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam){// TODO: 處理用戶自定義消息 AfxMessageBox(" 處理用戶自定義消息 "); return 0;}
第三步:在類頭文件的 AFX_MSG 塊中說明消息處理函數(shù):
class CMainFrame:public CMDIFrameWnd{
...
// 一般消息映射函數(shù)
protected:
// {{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()}
第四步:在用戶類的消息塊中,使用 ON_MESSAGE 宏指令將消息映射到消息處理函數(shù)中。
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
//}}AFX_MSG_MAPEND_MESSAGE_MAP()
這樣,一個(gè)用戶自定義消息就可以使用了,如果用戶需要一個(gè)整個(gè)系統(tǒng)唯一的消息,可以調(diào)用 SDK 函數(shù) RegisterWindowMessage 并使用 ON_REGISTER_MESSAGE 宏指令取代 ON_MESSAGE 宏指令,其余步驟同上。
VC++ 為程序員提供了一套功能強(qiáng)大、方便快捷的編程工具,它可以幫你方便的生成窗口、菜單等用戶界面,可惜就是做出來的東西都一樣,沒有一點(diǎn)個(gè)性。下面,就介紹一些方法,讓我們可以按照自己的設(shè)計(jì)定制出更加符合自己程序風(fēng)格的窗口。
一、如何在多文檔界面下去掉開始的子窗口
在多文檔界面程序中,程序剛啟動(dòng)的時(shí)候會(huì)自動(dòng)打開一個(gè)新的子窗口,而一個(gè)實(shí)際的應(yīng)用系統(tǒng)往往是由用戶操作后再生成新的窗口。下面是如何去掉開始的子窗口。
首先在應(yīng)用程序的 App 類里找到
BOOL CMyMDIApp::InitInstance() 下面有:
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
這是在處理命令行參數(shù),在這幾句話后面加一行:
cmdInfo.m_nShellCommand=CCommandLineInfo::FileNothing; 就可以了。再運(yùn)行程序,就會(huì)發(fā)現(xiàn)程序并沒有自動(dòng)開啟一個(gè)子窗口,而只剩下主框架窗口了。
二、修改窗口標(biāo)題欄
在缺省情況下,窗口標(biāo)題欄中顯示的標(biāo)題為程序名 + 當(dāng)前文檔的文件名。比如 " MyProgram - 文檔 1 . t x t " ,那若要在標(biāo)題欄顯示一個(gè)自己定義的字符串,而不是程序名,可以通過在程序里調(diào)用 CWnd::SetWindowText() 方法來實(shí)現(xiàn),而如果我們還想要后面的文檔名自動(dòng)顯示,這么做就不行了,這時(shí)可以用資源編輯器編輯字符串表( StringTable )資源,在 StringTable 中雙擊 IDR-MAIN-FRAME 項(xiàng), caption 中顯示一字符串 xx\n\yy...... ,將第一個(gè)參數(shù)修改為用戶自己希望見到的主窗口標(biāo)題即可。
如果你不想讓系統(tǒng)自動(dòng)幫你把文檔的文件名添加到標(biāo)題欄中,需要在 CMainFram 的 PreCreateWindow 函數(shù)中刪除 FWS_ADDTOTITLE 標(biāo)志的窗口樣式:
cs.style &= ~FWS_ADDTOTITLE ;
這樣,程序運(yùn)行起來,窗口標(biāo)題就是 "MyProgram" 而沒有后面的 "- 文檔 1.txt" 這樣的字符串了。
三、修改主框架窗口、子窗口及其顯示風(fēng)格
MFC 的 CWnd 類會(huì)在調(diào)用 CWnd::Create() 方法前先調(diào)用一下 PreCreateWindo() 方法,其參數(shù)是 CREATESTRUCT cs ,其中包括了創(chuàng)建窗口時(shí)各參數(shù),例如大小,風(fēng)格等等,我們可以通過重載這個(gè)成員函數(shù)來修改主窗口和子窗口的風(fēng)格等屬性。 PreCreateWindow 函數(shù)的原型為: Virtual BOOL PreCreateWindow ( CREATESTRUCT cs )。重載 PreCreateWindow 函數(shù)以后,則在創(chuàng)建窗口前可以修改 CREATESTRUCT 結(jié)構(gòu)以替換缺省參數(shù)。 CREATESTRUCT 結(jié)構(gòu)存放窗口特征,如窗口坐標(biāo)、風(fēng)格等,還可以定義新窗口風(fēng)格。
若想修改主框架窗口,則可以在 MainFrm.cpp 的下列成員函數(shù)中加入待修改的內(nèi)容。例如:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
// 通過修改 CREATESTRUCT 結(jié)構(gòu)來修改窗口類或風(fēng)格
cs.cx=450;
cs.cy=300;
// 定義新窗口的高度、寬度
// 定義新窗口風(fēng)格為去掉主窗口名及最大化等按鈕
cs.style=ws-POPWINDO;
return CFrameWnd::PreCreateWindow(cs); }
定制子窗口的操作與上述主窗口相同,可在 ChildFrame.cpp 中加入以下內(nèi)容:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
// 通過修改 CREATESTRUCT 結(jié)構(gòu)來修改窗口類或風(fēng)格
return CMDIChildWnd::PreCreateWindow(cs);
}
要修改視圖窗口的顯示性質(zhì),則可在視圖文件 MyView.cpp 的下述成員函數(shù)中加入以下語句:
BOOL MyView::PreCreateWindow(CREATESTRUCT&cs)
{
// 在這里修改 cs 結(jié)構(gòu),改變 View 的風(fēng)格。
cs.lpszClass=AfxRegisterWndClass(cs-HREDRAW|CS-VREDRAW,0,(HBRUSH))::GetStockObject(WHITE-BRUSH),0);
return CScrollView::PreCreateWindow(cs);
}
其中, cs 的參數(shù) pszClass 用于存放 Windows 窗口類名稱。要想注冊(cè) Windows 窗口類,則必須調(diào)用全局函數(shù) AfxRegisterWndClass 。該函數(shù)原型為:
LPCTSTR AFXAPI AfxRegisterWndClass(UINTnClassStyle,HCURSOR hCursor=0,HBRUSH hbrBackground=0,HICON hIcon=0)
上述各參數(shù)用于定義風(fēng)格,其含義分別為光標(biāo)資源句柄、背景資源句柄、圖標(biāo)資源句柄。上述增加的語句的作用是:改變窗口大小時(shí)重畫窗口、不顯示光標(biāo)圖標(biāo)、設(shè)置白色背景。
四、窗口的滾動(dòng)
MFC 中的 CScrollView 可以幫助你自動(dòng)實(shí)現(xiàn)窗口滾動(dòng)的決大部分功能,使用 CscrollView 時(shí), ClassWizard 生成 OnInitialUpdate() 成員函數(shù)為:
void CMyScrollView::OnInitialUpdat()
{
CScrollView::OnIntialUpdate();
CSize sizePage;
sizePage.cs=sizePage.cy=400;
SetScrollSizes(MM-TEXT,sizePage);
}
其中, cs 和 cy 分別為滾動(dòng)窗口的水平、垂直分量,表明窗口的水平、垂直方向尺寸小于 400 像素單位時(shí)將出現(xiàn)水平方向滾動(dòng)條和垂直方向滾動(dòng)條。通過修改滾動(dòng)尺寸,可改變出現(xiàn)滾動(dòng)條的最小窗口。例如,若 sizePage.cx=600;sizePage.cy=800; ,則當(dāng)窗口尺寸小于 600*800 時(shí),就會(huì)出現(xiàn)滾動(dòng)條。
五、窗口分割
該功能可將窗口分割成多個(gè)可滾動(dòng)的幀,幀之間的邊界稱為分割條,可用分割條來調(diào)整每個(gè)幀的相對(duì)大小。要想增加窗口分割功能,則必須修改主窗口類。首先,在主窗口類的頭文件 MainFrm.h 中添加以下代碼:
CSplitterWnd m-SWnd;
Virtual BOOL OnCreateClient (LPCREATESTRUCTcs,CcreateContext *pContext);
再在 MainFrm.cpp 中添加成員函數(shù) OnCreateClient 的定義:
BOOL CmainFrame::OnCreateCline(LPCREATESTRUCTcs,CcreateContext *p Context)
{
return m-SWnd.Creat(this,2,2,Csize(20,20),pContext);
}
新的 CSplitterWnd 類對(duì)象 m-SWnd 用于創(chuàng)建和管理分割窗口,該窗口中可以包含一個(gè)或多個(gè)幀。首次創(chuàng)建主窗口時(shí),將調(diào)用成員函數(shù) OnCreateClient 。在缺省情況下,該函數(shù)創(chuàng)建一個(gè)填充主框窗口客戶區(qū)的視圖窗口。覆蓋該函數(shù)后,將調(diào)用 CsplitterWnd 的成員函數(shù) Create 來創(chuàng)建分割窗口。其中,第一個(gè)參數(shù)用于指定分割的父窗口(主窗口);第二個(gè)參數(shù)指定垂直方向上的幀個(gè)數(shù)為 2 ;第三個(gè)參數(shù)指定水平方向上的幀的個(gè)數(shù);第四個(gè)參數(shù)用于設(shè)置每個(gè)幀的最小尺寸;第五個(gè)參數(shù)傳遞描述信息。上述分割窗口的每個(gè)幀都是由視圖類對(duì)象管理的,當(dāng)用戶在某一幀內(nèi)顯示文檔和圖形時(shí),必須在其它幀中重新繪制,從而在多個(gè)幀中均顯示相同的內(nèi)容。為此,必須調(diào)用顯示文檔類的 UpdateALLView 成員函數(shù)來更新其它幀。此時(shí),只需加入 pdoc- > UpdataALLView(NULL) 即可。