應(yīng)用MFC開發(fā)高級應(yīng)用程序
發(fā)表時間:2024-06-18 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]作者:茍建兵 清華大學(xué)熱能系(北京,100084) 目前在Windows下開發(fā)應(yīng)用程序的工具雖然很多,但是C/C++作為一種非常成熟和高效的開發(fā)語言在大型復(fù)雜項目的開發(fā)中仍然得到了廣泛應(yīng)用。為了減輕程序開發(fā)負(fù)擔(dān),提高開發(fā)效率,各種流行的C++都提供了類庫,本文就是針對如何在Vis...
作者:茍建兵 清華大學(xué)熱能系(北京,100084)
目前在Windows下開發(fā)應(yīng)用程序的工具雖然很多,但是C/C++作為一種非常成熟和高效的開發(fā)語言在大型復(fù)雜項目的開發(fā)中仍然得到了廣泛應(yīng)用。為了減輕程序開發(fā)負(fù)擔(dān),提高開發(fā)效率,各種流行的C++都提供了類庫,本文就是針對如何在Visual C++環(huán)境中使用MFC類庫來開發(fā)高級程序所需要解決的一些問題進(jìn)行了的探討,重點(diǎn)討論了利用MFC開發(fā)單文檔多視應(yīng)用程序和DDE應(yīng)用程序的方法。
文章正文
一、使用C/C++
隨著Windows系列操作系統(tǒng)的日益普遍,傳統(tǒng)的基于DOS編程逐漸轉(zhuǎn)向Windows下編程已經(jīng)成為必然趨勢。目前在Windows下開發(fā)應(yīng)用程序的工具很多,典型的如Borland
C++、Visual C++、Visual Baisic以及Delphi等等。每種開發(fā)工具都各有其特點(diǎn), 一般來講用戶可以根據(jù)自己的使用習(xí)慣和開發(fā)項目的性質(zhì)來選擇具體的開發(fā)語言。
Visual Basic是一個被軟件界稱之為劃時代的革新產(chǎn)品,該軟件改變了人們開發(fā) Windows程序的方式,它采用交互式的可視化操作,使得人們開發(fā)Windows程序的每 一過程都有直觀形象的反饋,從而加速整個開發(fā)進(jìn)程。Visual Basic使得Windows程 序設(shè)計人員不再只依賴于復(fù)雜的SDK編程,使得開發(fā)Windows程序非常容易,可以 說,用戶學(xué)習(xí)并使用VB來開發(fā)Windows應(yīng)用的時間是最短的。Visual Basic版本幾經(jīng)
演變,目前已經(jīng)發(fā)展到5.0。在4.0版本中,由于完全使用了面向?qū)ο蟮木幊谈拍睿?同時具有Windows 3.1和Windows 95下的版本,因而使得其開發(fā)復(fù)雜程序的功能逐漸 增強(qiáng)。VB5.0則拋棄了Windows 3.x的用戶,只能在32位Windows中使用,據(jù)悉,該版 本吸收了Delphi的成功策略,引入了本地代碼(Native Code)編譯器,從而使得程序 執(zhí)行速度大大加快,克服了以往版本由于執(zhí)行文件采用P-Code代碼而導(dǎo)致運(yùn)行速度
慢的特點(diǎn),根據(jù)微軟的聲明,該版本的采用本地代碼編譯后得到的應(yīng)用程序在某些 情況下執(zhí)行速度較以往提高了10~20倍,執(zhí)行速度可以直逼與采用Visual C++編寫的 應(yīng)用,而應(yīng)用開發(fā)速度則是VB的強(qiáng)項,因此Visual Basic 5.0非常具有競爭性。目 前Visual Basic非常廣泛地用于開發(fā)各種Windows程序,如數(shù)據(jù)庫前端應(yīng)用程序和多 媒體應(yīng)用等。但是,在作者看來,采用VB也有一定的缺點(diǎn),原因有以下幾點(diǎn):
1. Visual Basic來源于Basic語言,雖然經(jīng)過微軟的不斷增強(qiáng),但是仍然缺乏非常 靈活的數(shù)據(jù)類型和編程策略,因而在開發(fā)一些項目必須的復(fù)雜數(shù)據(jù)結(jié)構(gòu)遇到麻煩, 如鏈表、圖和二叉樹等等。由于在中大型項目開發(fā)后期,開發(fā)工作不再以界面為 主,而是在算法設(shè)計和底層軟硬件工作,這就使VB開發(fā)項目的后期工作量大幅度增 加,為了達(dá)到項目要求,經(jīng)常需要再轉(zhuǎn)向C/C++開發(fā)一些專用的動態(tài)連接庫來解決問
題。
2. Visual Basic運(yùn)行速度慢,前文講過,采用P-Code代碼雖然執(zhí)行文件很小,但是 在運(yùn)行時需要解釋執(zhí)行,并且,它的運(yùn)行必須有對應(yīng)的VBRUN.DLL和所使用的VBX或 者OCX支持。對于浮點(diǎn)操作密集或者循環(huán)嵌套很多的應(yīng)用來說,VB沒有采取特別的優(yōu) 化,因而執(zhí)行速度遠(yuǎn)不如用C/C++和Fortran開發(fā)的應(yīng)用速度快。VB 5.0雖然通過引 入本地代碼編譯器大大彌補(bǔ)了這個缺陷,但是由于其只能運(yùn)行于32位Windows環(huán)境因 而在16位Windows上速度問題仍然得不到解決。雖然目前轉(zhuǎn)向32位Windows的趨勢非 常強(qiáng)勁,但是不容忽視由于硬件的限制或者使用習(xí)慣等諸多原因,還有許多用戶仍 然在16位Windows上工作。在計算機(jī)十分普及的美國,96年使用16位Windows的用戶 仍然超過了使用32位Windows的用戶,任何進(jìn)行系統(tǒng)軟件設(shè)計的人員都應(yīng)該照顧到這 些仍然使用16位Windows的用戶。
3. VB不能靈活地使用系統(tǒng)資源。熟悉Windows編程的人都知道,如果要直接訪問硬 件或者要編寫對系統(tǒng)進(jìn)行有效訪問的應(yīng)用程序,沒有Windows API函數(shù)的幫助則非常 困難,但是令VB程序員失望的是,API函數(shù)是用C語言和匯編語言實現(xiàn)的,是為C編程 準(zhǔn)備的,如果要在VB里面使用這些上千個API函數(shù)則比較麻煩,特別是,如果設(shè)計人 員不懂C語言則尤其困難。由于API函數(shù)的復(fù)雜性,而其本身不是為了方便VB編程而 提供的,因此在VB里面調(diào)用API函數(shù)需要一定的技巧,這些技巧足夠用一本很厚的書 來表述。VB程序員可以從書店里找到好多本類似的書籍。可以說,任何一個VB程序 員發(fā)展到一定階段都需要與眾多的API函數(shù)打交道。另外,由于VB不支持端口操作, 因此,如果要編寫類似數(shù)據(jù)采集等需要與硬件交互的程序則需要求救于C/C++語言。
4. Visual Basic項目分發(fā)和管理困難,其原因同上講的,VB應(yīng)用的運(yùn)行不能脫離VB 的運(yùn)行庫和所使用的控件,因此,如果開發(fā)人員要將VB應(yīng)用分發(fā)給用戶那么一定要 帶上VB的運(yùn)行庫和所使用的控件,并且要保證正確安裝,這就導(dǎo)致即使一個非常簡 單的應(yīng)用也需要附帶大量其它相關(guān)支撐庫程序,對于VB 4.0及更高版本,由于大量 的使用了OLE控件(在VB中稱為OCX),其安裝更為復(fù)雜。 Delphi軟件是國際寶蘭公司(Borland)的得意之作,也是備受軟件界推崇,與VB一 樣,它完全是一個交互式的可視化開發(fā)平臺,支持Client/Server應(yīng)用程序的開發(fā) 其最新版本2.0可以開發(fā)Windows 3.x、Windows 95和Windows NT的應(yīng)用程 序。Delphi開發(fā)速度也非?,與VB相比,由于具有本地代碼編譯器因此它產(chǎn)生的 可執(zhí)行文件執(zhí)行速度大大加快。Delphi軟件是一個非常有競爭力的軟件,采用的是 面向?qū)ο蟮腛bject pascal語言,支持硬件操作和API調(diào)用。但是由于采用的編程語 言為Pascal,這種語言并不非常流行,許多程序設(shè)計人員完全不熟悉這種語言,因 此極大地限制了該軟件的使用,如果寶蘭公司能夠?qū)elphi軟件提供的RAD開發(fā)機(jī)制
引入到其Borland C++中,則可能會形成一個非常成功的產(chǎn)品(目前該版本已經(jīng)推 出,即C++ Builder,筆者注)。 VB和Delphi引入的可視化開發(fā)方法還有一個共同的缺點(diǎn)就是各個版本之間的兼容問 題。一般來講,采用這些可視化開發(fā)工具開發(fā)的應(yīng)用程序在移植到高版本時不會遇 到太大困難,但是一旦往相反方向移植則困難重重,有時甚至不可能。C/C++語言則 不具有這種局限性,各個版本之間的相互移植并不困難,高版本往低版本移植一般 只需重建工程文件即可大功告成。
綜上所述,根據(jù)作者的觀點(diǎn),如果要開發(fā)一個大型復(fù)雜的應(yīng)用程序首選的還是 C/C++,特別是在16位Windows下。雖然這會使前期工作增加,但是在項目的中后期 將逐漸會領(lǐng)略到其優(yōu)越性和開發(fā)效率,其靈活高效的執(zhí)行代碼適合于對速度和應(yīng)用 程序之間的協(xié)同性要求很高的場合。純粹基于Windows SDK來開發(fā)Windows程序是一 項艱巨的工程,值得慶幸的是目前各種流行的C/C++開發(fā)工具都提供了類庫開發(fā)框架
來簡化整個開發(fā)過程而又不失其固有的靈活高效性,不同的開發(fā)語言所提供的類庫 開發(fā)框架不同,如Borland C++提供的OWL(Object Windows Library)和 Visual C++ 提供的MFC(Microsoft Fundmental Class),這兩種類庫都封裝了大量的Windows API和Windows的開發(fā)元素而使得開發(fā)任務(wù)簡化,兩種類庫各有其優(yōu)點(diǎn),據(jù)作者掌握 的資料,采用MFC編寫的應(yīng)用程序執(zhí)行代碼更小,執(zhí)行速度也更快,這大概是因為該
軟件的開發(fā)者是開發(fā)Windows操作系統(tǒng)的Microsoft公司的緣故吧,現(xiàn)在MFC正逐漸成 為Windows下的類庫開發(fā)標(biāo)準(zhǔn),正被越來越多的其它C/C++編譯工具所支持,如 Watcom C++。使用MC類庫同時配合Visual C++提供的AppWizard、ClassWizard和 AppStudio可以大幅度提高開發(fā)效率。筆者在工作中積累了一些MFC的使用經(jīng)驗現(xiàn)在 提出來供大家參考,希望對廣大同行有所幫助,尤其是那些仍然致力于16位Windows 編程的程序員。本文使用的Visual C++ 1.51編譯器,但是其方法同樣適用于其它 VC++版本,包括Visual C++ 4.x。
二、MFC編程綜述
采用MFC開發(fā)Windows程序之所以能夠大幅度提高開發(fā)速度和效率主要是因為MFC在類 層次封裝了大量Windows SDK函數(shù)和典型Windows應(yīng)用的缺省處理,這樣,用戶只需 要較少的編程就可以實現(xiàn)自己的開發(fā)任務(wù)。如果在MFC基礎(chǔ)上再配合Visual C++提供 的AppWizard、ClassWizard和AppStudio工具那么更可以大幅度加快開發(fā)進(jìn)程。MFC提供大量的基類供程序員使用,常見的如CWinApp類、CFrameWnd類、CMDIFrameWnd 類、CMDIChildWnd類、CView類、CDC類和CDocument類等等。通過從這些基類中派生
出用戶自己的類,然后重載特殊的幾個函數(shù)就可以生成一個獨(dú)立的應(yīng)用程序?梢 說,采用MFC編寫Windows應(yīng)用程序是非常方便的,雖然其學(xué)習(xí)過程并不簡單,但是 其提供的靈活高效性足以使任何Windows程序開發(fā)人員為之付出努力。如果用戶不曾 使用過MFC,那么用戶可以通過附錄中所列的參考書去學(xué)習(xí)MFC的強(qiáng)大功能。 采用MFC應(yīng)用框架產(chǎn)生的應(yīng)用程序使用了標(biāo)準(zhǔn)化的結(jié)構(gòu),因而使得采用MFC編寫的程 序的在不同平臺上的移植變得非常容易,事實上,MFC的16位和32位版本之間差別很 小。MFC提供的標(biāo)準(zhǔn)化結(jié)構(gòu)是經(jīng)過眾多專家分析調(diào)研后總結(jié)編寫出來的,一般情況下 可以滿足絕大多數(shù)用戶的要求,但有時用戶也可以通過重載一些函數(shù)來修改其缺省 的風(fēng)格從而實現(xiàn)自己特有的風(fēng)格,如自定義應(yīng)用圖表和灰色背景等。在MFC提供的文 檔視結(jié)構(gòu)中,文檔、視和資源之間的聯(lián)系是通過定義文檔模板來實現(xiàn)的,如:
m_pSimuTemplate = new CMultiDocTemplate(
IDR_SIMUTYPE,
RUNTIME_CLASS(CSimuDoc),
RUNTIME_CLASS(CMyChild), // Derived MDI child frame
RUNTIME_CLASS(CSimuView));
上中第一項IDR_SIMUTYPE就包括了視口的菜單,加速鍵和圖表等資源,如果用戶使 用AppWizard來產(chǎn)生的應(yīng)用基本框架,那么其也同時產(chǎn)生了缺省的圖標(biāo),如果用戶不 滿意缺省圖標(biāo)(實際上用戶很少滿足于缺省圖標(biāo)),只需要將缺省圖標(biāo)刪除,然后 編輯或者直接引入一個新的圖標(biāo),在存儲這一圖標(biāo)時只需要使用與被刪除圖標(biāo)同樣 的ID即可實現(xiàn)替代。
熟悉Windows程序開發(fā)的人都知道,在Windows上通過使用灰色背景可以增強(qiáng)應(yīng)用程 序的視覺效果,曾有人戲稱,灰色是圖形界面永恒的顏色。使用MFC產(chǎn)生的應(yīng)用程序 的背景缺省為白色,如果用戶希望改變成灰色或者其它顏色,那就需要使用單獨(dú)處 理,解決的辦法很多,如在每次視口的OnPaint()事件中采用灰色刷子人為填充背 景,但是這不是最好的辦法。筆者發(fā)現(xiàn)最好的辦法就是采用AfxRegisterWndClass()
函數(shù)注冊一個使用灰色背景刷的新的窗口類,這需要重載PreCreateWindow()函數(shù)來
實現(xiàn)這一點(diǎn),如下程序代碼片段所示:
BOOL CSimuView::PreCreateWindow(CREATESTRUCT& cs)
{
HBRUSH hbkbrush=CreateSolidBrush(RGB(192,192,192));//創(chuàng)建灰色背景刷
LPCSTR lpMyOwnClass=AfxRegisterWndClass(CS_HREDRAW
CS_VREDRAW CS_OWNDC,0,hbkbrush);//注冊新類
cs.lpszClass=lpMyOwnClass;//修改缺省的類風(fēng)格
return TRUE;
}
采用這種方法速度最快,也最省力。同時,還可以在PreCreateWindow()函數(shù)定義所 希望的任何窗口風(fēng)格,如窗口大小,光標(biāo)式樣等。
三、使用單文檔-多視結(jié)構(gòu)
如果用戶使用過MFC進(jìn)行編程,那么就會發(fā)現(xiàn)借助于AppWizard基于MFC無論編寫SDI (單文檔界面)還是編寫MDI(多文檔界面)都是十分方便的。MDI應(yīng)用程序目前使用越 來越普遍,人們熟悉的Microsoft公司的Office系列產(chǎn)品以及Visual系列產(chǎn)品都是典 型的多文檔應(yīng)用程序。這種多文檔界面具有多窗口的特點(diǎn),因而人們可以在一個程 序中使用多個子窗口來實現(xiàn)不同數(shù)據(jù)的瀏覽查看。如果用戶要實現(xiàn)在MDI各個窗口之
間針對同一數(shù)據(jù)進(jìn)行不同的可視化就是一件比較麻煩的事情。值得慶幸的是,MFC提 供的文檔-視結(jié)構(gòu)大大簡化了這一工作。文檔-視結(jié)構(gòu)通過將數(shù)據(jù)從用戶對數(shù)據(jù)的觀 察中分離出來,從而方便實現(xiàn)多視,亦即多個視口針對同一數(shù)據(jù),如果一個視口中 數(shù)據(jù)發(fā)生改變,那么其它相關(guān)視口中的內(nèi)容也會隨之發(fā)生改變以反映數(shù)據(jù)的變化。 SDI和MDI這兩種Windows標(biāo)準(zhǔn)應(yīng)用程序框架并不是總能滿足用戶的需要,就作者的工
作而言,就特別需要一種被稱為單文檔多視的應(yīng)用程序,英文可以縮寫為SDMV。通 過SDMV應(yīng)用我們可以利用文檔類來統(tǒng)一管理應(yīng)用程序的所有數(shù)據(jù),同時需要采用 窗口以多種方式來可視化這些的數(shù)據(jù),如棒圖,趨勢圖和參數(shù)列表,從而方便用戶 從不同角度來觀察數(shù)據(jù)。MDI雖然具有多窗口的特點(diǎn),但是其為多文檔,即通常情況 下,一個視口對應(yīng)一個文檔,視口+文檔便構(gòu)成一個子窗口。在各個子窗口之間數(shù)據(jù)
相互獨(dú)立,如果要保持?jǐn)?shù)據(jù)同步更新就需要采用特殊的技術(shù)了,采用這種方式既費(fèi) 時又費(fèi)力。通過筆者的實踐發(fā)現(xiàn),利用MFC本身提供的多視概念通過適當(dāng)改造MDI窗 口應(yīng)用程序就可以實現(xiàn)上述SDMV結(jié)構(gòu)
。
所謂SDMV應(yīng)用程序本質(zhì)上仍然是一個MDI應(yīng)用程序,只是在程序中我們?nèi)藶榭刂剖蛊?只能生成一個文檔類,這個文檔在第一個視口創(chuàng)建時創(chuàng)建,注意,這里并不需要限 制各個視口的創(chuàng)建先后順序。此后與MDI窗口固有特性不同的是,所有新創(chuàng)建的子窗 口都不再創(chuàng)建獨(dú)立文檔,而是把該新視口直接連接到已有的文檔對象上,這樣就使 其成為單文檔多視的結(jié)構(gòu),所有相關(guān)數(shù)據(jù)都存儲在文檔對象中,一旦文擋中數(shù)據(jù)發(fā)
生改變,通過UpdateAllViews()函數(shù)通知所有相關(guān)視口,各個視口就可以在 OnUpdate()中相應(yīng)數(shù)據(jù)的變化。這種響應(yīng)機(jī)制如下圖所示:
圖 1 文檔-視結(jié)構(gòu)數(shù)據(jù)更新機(jī)制
由于MDI本質(zhì)上并不是為這種單文檔多視機(jī)制服務(wù)的,因而在實際應(yīng)用時需要解決一 些問題。
1、窗口標(biāo)題問題
窗口標(biāo)題本來不應(yīng)該成為問題,缺省情況下MDI窗口通過在文檔模板中提供的資源ID 所提供的對應(yīng)字符串來確定窗口標(biāo)題。但是對于SDMV應(yīng)用,由于各個視口實質(zhì)上是 對應(yīng)于同一個文擋,因此每個視口都具有相同標(biāo)題,只不過增加了一個數(shù)據(jù)用于指 示這是第幾個視口。如果在各個視口中指明具體的窗口名字,那么由不同的視口啟 動創(chuàng)建文檔產(chǎn)生的窗口標(biāo)題就不同,這個名字會影響到后繼視口。為了作到不同類 型的視口如棒圖視口和曲線視口具有不同的標(biāo)題,這就需要一定的技術(shù)處理。根據(jù) 筆者的摸索發(fā)現(xiàn)可以采用如下步驟實現(xiàn):
首先在從標(biāo)準(zhǔn)的MDI子窗口基類CMDIChildWnd派生一個自己的子窗口類,姑且命名為 CMyChild,然后在其成員變量中增加一個CString型變量用以存儲當(dāng)前窗口標(biāo)題:
CString winTitle;
然后在不同的視口創(chuàng)建過程中通過獲取父窗口指針按自己的意愿對上述變量進(jìn)行賦 值,程序片段如下:
pChild=(CMyChild*)GetParent();
pChild->winTitle="棒圖顯示窗口";
最后在CMyChild派生類中重載CMDIChildWnd基類中的OnUpdateFrameTitle()函數(shù)來 強(qiáng)制實現(xiàn)窗口標(biāo)題的個性化,這一函數(shù)在各種類庫手冊上和聯(lián)機(jī)幫助中都沒有,但 的確有這樣一個具有保護(hù)屬性的函數(shù)用來實現(xiàn)窗口標(biāo)題的更新操作,這可以從MFC類庫的源代碼中找到該函數(shù)的實現(xiàn)。重載后的源代碼如下:
void CMyChild::OnUpdateFrameTitle(BOOL bAddToTitle)
{
// update our parent window first
GetMDIFrame()->OnUpdateFrameTitle(bAddToTitle);
if ((GetStyle() & FWS_ADDTOTITLE) == 0)
return; // leave child window alone!
CDocument* pDocument = GetActiveDocument();
if (bAddToTitle && pDocument != NULL)
{
char szOld[256];
GetWindowText(szOld, sizeof(szOld));
char szText[256];
lstrcpy(szText,winTitle); //Modified by author!
if (m_nWindow > 0)
wsprintf(szText + lstrlen(szText), ":%d", m_nWindow);
// set title if changed, but don't remove completely
if (lstrcmp(szText, szOld) != 0)
SetWindowText(szText);
}
}
2、如何創(chuàng)建SDMV應(yīng)用
如何創(chuàng)建SDMV應(yīng)用比較麻煩,下面通過舉例來具體說明。該例子假設(shè)用戶需要建棒 圖類型和曲線形式的兩種視口,假設(shè)用戶已經(jīng)利用CView基類派生并且實現(xiàn)了這兩 類,分別對應(yīng)于CMyChart和CMyTraceView兩個類。
1) 在應(yīng)用類(從CWinApp派生出來的類)的頭文件中加入下列變量和函數(shù)原型說 明:
CMultiDocTemplate* m_pMyTraceTemplate;
CMultiDocTemplate* m_pMyChartTemplate;
int ExitInstance();
2) 在應(yīng)用類的InitInstance成員函數(shù)中刪除對AddDocTemplate函數(shù)的調(diào)用和 OpenFileNew()語句,并且加入如下代碼:
m_pMyTraceTemplate = new CMultiDocTemplate(
IDR_MYTRACEVIEW,
RUNTIME_CLASS(CSimuDoc),
RUNTIME_CLASS(CMyChild), // Derived MDI child frame
RUNTIME_CLASS(CMyTraceView));
m_pMyChartTemplate = new CMultiDocTemplate(
IDR_MYCHART,
RUNTIME_CLASS(CSimuDoc),
RUNTIME_CLASS(CMyChild), // Derived MDI child frame
RUNTIME_CLASS(CMyChart));
3) 實現(xiàn)ExitInstance()函數(shù),在其中刪除所用的兩個輔助模板:
int CTestApp::ExitInstance()
{
if(m_pMyChartTemplate) delete m_pMyChartTemplate;
if(m_pMyTraceTemplate) delete m_pMyTraceTemplate;
return TRUE;
}
4) 在菜單資源中去掉File菜單中的New和Open項,加入New Chart View和New
Trace View兩項,在對應(yīng)的菜單命令中實現(xiàn)如下:
void CMainFrame::OnNewMychart()
{
// TODO: Add your command handler code here
OnNewView(((CSimuApp*)AfxGetApp())->m_pMyChartTemplate);
}
void CMainFrame::OnNewMyTrace()
{
// TODO: Add your command handler code here
OnNewView(((CSimuApp*)AfxGetApp())->m_pMyTraceTemplate);
}
上中OnNewView的實現(xiàn)如下:
BOOL CMainFrame::OnNewView(CMultiDocTemplate* pDocTemplate)
{
CMDIChildWnd* pActiveChild = MDIGetActive();
CDocument* pDocument;
if (pActiveChild == NULL
(pDocument = pActiveChild->GetActiveDocument()) == NULL)
{
TRACE0("Now New the specify view\n");
ASSERT(pDocTemplate != NULL);
ASSERT(pDocTemplate->IsKindOf(RUNTIME_CLASS(CDocTemplate)));
pDocTemplate->OpenDocumentFile(NULL);
return TRUE;
}
// otherwise we have a new frame to the same document!
CMultiDocTemplate* pTemplate = pDocTemplate;
ASSERT_VALID(pTemplate);
CFrameWnd* pFrame = pTemplate->CreateNewFrame(pDocument, pActiveChild);
if (pFrame == NULL)
{
TRACE0("Warning: failed to create new frame\n");
return FALSE; // command failed
}
pTemplate->InitialUpdateFrame(pFrame, pDocument);
return TRUE;
}
OnNewView是整個SDMV應(yīng)用的核心組成,它的任務(wù)是創(chuàng)建一個新的指定類型的視口, 它首先判斷是否有活動視口存在,文檔是否已經(jīng)創(chuàng)建,正常情況下活動視口存在則 表明文檔存在,如果不存在則利用所指定的文檔模板創(chuàng)建一個新的活動視口,否則 則只創(chuàng)建視口,同時將其連接到已存在的文檔對象上。
通過以上步驟就可以實現(xiàn)SDMV應(yīng)用,在其后的具體應(yīng)用中利用文檔對象的 UpdateAllViews()函數(shù)和視口的OnUpdate()函數(shù)就可以很好的工作了。
四、使用DDE服務(wù)
Windows 3.x是一個分時多任務(wù)操作環(huán)境,在此環(huán)境下,多個應(yīng)用程序可以并發(fā)地執(zhí) 行。為了在并發(fā)執(zhí)行的多個任務(wù)之間共享數(shù)據(jù)和資源,Windows 提供了幾種機(jī)制, 主要是通過剪貼板(Clipboard)和動態(tài)數(shù)據(jù)交換(Dynamic Data Exchange)。前者對 于用戶需要直接參與的數(shù)據(jù)交換來說,是一個非常方便的工具,但是如果希望數(shù)據(jù) 交換自動進(jìn)行時就必須依靠DDE技術(shù)了。編寫DDE應(yīng)用的技術(shù)也發(fā)展了好幾代,從最 初的基于消息的DDE到基于DDEML(動態(tài)數(shù)據(jù)交換管理庫),再到現(xiàn)在流行的OLE技 術(shù)。DDE技術(shù)的發(fā)展使得程序開發(fā)人員編寫DDE應(yīng)用更為簡潔。從發(fā)展趨勢來看,基 于OLE的數(shù)據(jù)交換是最好的,它特別符合當(dāng)今軟件領(lǐng)域的客戶-服務(wù)器機(jī)制 (Client-Server)。為適應(yīng)多平臺和Internet的需要,在OLE基礎(chǔ)上微軟又開發(fā)了
ActiveX技術(shù)。但是不容忽視的是,基于傳統(tǒng)的DDE數(shù)據(jù)交換也自有它的應(yīng)用空間, 使用仍然廣泛。目前在Windows 3.x下,基于OLE的遠(yuǎn)程數(shù)據(jù)交換還很不成熟,但是 在WFW(Windows for Workgroup)下基于網(wǎng)絡(luò)動態(tài)數(shù)據(jù)交換的技術(shù)卻很成熟,目前也 應(yīng)用非常普遍。關(guān)于DDE應(yīng)用的開發(fā)和NetDDE的應(yīng)用可以參看附錄7。
1、回調(diào)函數(shù)的處理
由于DDEML機(jī)制需要使用回調(diào)函數(shù),因此使用DDEML的關(guān)鍵是解決在MFC編程體系中回 調(diào)函數(shù)的使用;卣{(diào)函數(shù)(Callback function)大量用于Windows的系統(tǒng)服務(wù),通過 它,程序員可以安裝設(shè)備驅(qū)動程序和消息過濾系統(tǒng),以控制Windows的有效使用。 許多程序員都發(fā)現(xiàn),利用MFC或者其它的C++應(yīng)用編寫回調(diào)函數(shù)是非常麻煩的,其根 本原因是回調(diào)函數(shù)是基于C編程的Windows SDK的技術(shù),不是針對C++的,程序員可以 將一個C函數(shù)直接作為回調(diào)函數(shù),但是如果試圖直接使用C++的成員函數(shù)作為回調(diào)函 數(shù)將發(fā)生錯誤,甚至編譯就不能通過。通過查詢資料發(fā)現(xiàn),其錯誤是普通的C++成員 函數(shù)都隱含了一個傳遞函數(shù)作為參數(shù),亦即“this”指針,C++通過傳遞一個指向自 身的指針給其成員函數(shù)從而實現(xiàn)程序函數(shù)可以訪問C++的數(shù)據(jù)成員。這也可以理解為 什么C++類的多個實例可以共享成員函數(shù)但是確有不同的數(shù)據(jù)成員。由于this指針的 作用,使得將一個CALLBACK型的成員函數(shù)作為回調(diào)函數(shù)安裝時就會因為隱含的this 指針使得函數(shù)參數(shù)個數(shù)不匹配,從而導(dǎo)致回調(diào)函數(shù)安裝失敗。要解決這一問題的關(guān) 鍵就是不讓this指針起作用,通過采用以下兩種典型技術(shù)可以解決在C++中使用回調(diào) 函數(shù)所遇到的問題。這種方法具有通用性,適合于任何C++
。
1. 不使用成員函數(shù),直接使用普通C函數(shù),為了實現(xiàn)在C函數(shù)中可以訪問類的成員變 量,可以使用友元操作符(friend),在C++中將該C函數(shù)說明為類的友元即可。這種 處理機(jī)制與普通的C編程中使用回調(diào)函數(shù)一樣。
2. 使用靜態(tài)成員函數(shù),靜態(tài)成員函數(shù)不使用this指針作為隱含參數(shù),這樣就可以作 為回調(diào)函數(shù)了。靜態(tài)成員函數(shù)具有兩大特點(diǎn):其一,可以在沒有類實例的情況下使 用;其二,只能訪問靜態(tài)成員變量和靜態(tài)成員函數(shù),不能訪問非靜態(tài)成員變量和非 靜態(tài)成員函數(shù)。由于在C++中使用類成員函數(shù)作為回調(diào)函數(shù)的目的就是為了訪問所有 的成員變量和成員函數(shù),如果作不到這一點(diǎn)將不具有實際意義。解決的辦法也很簡 單,就是使用一個靜態(tài)類指針作為類成員,通過在類創(chuàng)建時初始化該靜態(tài)指針,如 pThis=this,然后在回調(diào)函數(shù)中通過該靜態(tài)指針就可以訪問所有成員變量和成員函 數(shù)了。這種處理辦法適用于只有一個類實例的情況,因為多個類實例將共享靜態(tài)類 成員和靜態(tài)成員函數(shù),這就導(dǎo)致靜態(tài)指針指向最后創(chuàng)建的類實例。為了避免這種情 況,可以使用回調(diào)函數(shù)的一個參數(shù)來傳遞this指針,從而實現(xiàn)數(shù)據(jù)成員共享。這種 方法稍稍麻煩,這里就不再贅述。
2、在MFC中使用DDEML
對于典型的MFC應(yīng)用程序,主框架窗口類(CMainFrame)只有一個實例,因此可以使用 靜態(tài)成員函數(shù)作為回調(diào)函數(shù),從而實現(xiàn)DDE機(jī)制。具體的代碼片段如下:
(1) 在CMainFrame類中聲明如下靜態(tài)成員:
static CMainFrame* pThis;
static DWORD idInst;
static HDDEDATA CALLBACK EXPORT DdeCallback(UINT,UINT,HCONV,HSZ,HSZ, HDDEDATA,DWORD,DWORD);
(2) 在類的創(chuàng)建代碼(OnCreate())中作如下說明:
pThis=this;
lpDdeCallback=MakeProcInstance((FARPROC)DdeCallback,hInstance);
if(DdeInitialize(&idInst,(PFNCALLBACK)lpDdeCallback,CBF_FAIL_EXECUTES
CBF_SKIP_REGISTRATIONS CBF_SKIP_UNREGISTRATIONS,0L))
{
AfxMessageBox("不能初始化DDE服務(wù)","錯誤");
DestroyWindow();
}
(3) 回調(diào)函數(shù)實現(xiàn)如下:
HDDEDATA FAR PASCAL _export CMainFrame::DdeCallback(UINT iType,UINT iFmt, HCONV hConv,HSZ hsz1,HSZ hsz2,HDDEDATA hData,DWORD dwData1,DWORD dwData2)
{
char szBuffer[16];
int i;
switch(iType)
{
case XTYP_CONNECT: //hsz1=topiv, hsz2=service
return (HDDEDATA)TRUE;//TRUE;
case XTYP_ADVSTART: //hsz1=topic, hsz2=item
case XTYP_REQUEST:
case XTYP_ADVREQ:
case XTYP_POKE: //hsz1=Topic, hsz2=item, hData=data
case XTYP_ADVSTOP:
return NULL;
}
}
3、避免變量類型沖突
如果在MFC應(yīng)用直接使用DDEML服務(wù),那么該MFC應(yīng)用在編譯時將會遇到變量類型HSZ 重復(fù)定義錯誤。經(jīng)過追蹤發(fā)現(xiàn),錯誤在于在DDEML.H對HSZ作了如下定義:
DECLARE_HANDLE32(HSZ);
而在AFXEXT.H(通過stdafx.h引入)中對HSZ又作了如下說明:
typedef BPSTR FAR* HSZ; // Long handle to a string
兩個定義一個為32位整數(shù),一個為BASIC字符串指針,當(dāng)然會發(fā)生編譯器不能作變量 類型轉(zhuǎn)換的錯誤。實際上,將HSZ聲明為BASIC字符串指針主要用于在MFC應(yīng)用中使用 VBX控制。要改正這一錯誤,就必須保證不要在同一個代碼模塊中使用DDEML和VBX支 持,通過將使用DDEML和VBX的代碼分開,并在使用DDEML代碼的模塊中最開頭定義如 下編譯器宏就可以解決上述問題:
#define NO_VBX_SUPPORT
五、使用3D控制
毫無疑問,3D控制的使用可以顯著提高Windows應(yīng)用程序的界面友好性,目前,許多 流行的Windows
應(yīng)用程序都使用了3D控制,典型的如Microsoft公司的Office系列軟 件,而且,在Windows 95和Windows NT 4.0中,3D控制更是作為操作系統(tǒng)的一部分 直接提供,這意味著在其上運(yùn)行的軟件不需要作任何特殊處理,就具有3D界面效 果,但是,很遺憾的是,在Windows 3.x中,除了命令按鈕控制使用3D控制以外,其
余所有的控制,如編輯框,列表框,檢查框等都只使用2D控制,要想使用3D控制, 程序設(shè)計人員就必須在自己的程序中作一定的修改,考慮到目前3D效果的流行,這 點(diǎn)努力是值得的。 為了支持3D效果,Microsoft公司提供了一個專門用于3D控制的動態(tài)連接庫,即
CTL3D.DLL,但是在其Visual C++中卻沒有如何使用3D控制的討論,并且,Visual C++也不直接支持3D編碼,因為它不包括使用3D控制所必須的頭文件。但是,這并不 意味著在Visual C++中不能使用3D控制,只不過用戶需要從其它地方獲取技術(shù)支持 罷了。由于使用的是動態(tài)連接庫機(jī)制,因此,任何其它語言提供的3D頭文件和 CTL3D.DLL的輸入庫都是可用的。作者使用的就是Borland公司的Borland C++中提供 的CTL3D.H和CTL3D.LIB。在C/C++中使用3D控制的方法也有很多種,在這里,為節(jié)約 篇幅,只討論與本文相關(guān)的主題,即使用MFC編程時如何使用3D控制。
在MFC的所有對話框中使用3D控制可以遵循如下步驟:
1. 在CWinApp::InitInstance函數(shù)中調(diào)用Ctl3dRegister和Ctl3dAutosubclass函
數(shù):
Ctl3dRegister(AfxGetInstanceHandle());
Ctl3dAutoSubclass(AfxGetInstanceHandle());
值得一提的是,在AppWizard產(chǎn)生的應(yīng)用框架的CWinApp::InitInstance中有一個函 數(shù)調(diào)用為SetDialogBkColor,此函數(shù)的作用是將所有對話框的背景顏色設(shè)置為灰 色,這個功能與3D界面實現(xiàn)相同的功能,可以移去此語句。
由于CTL3D在初始化時讀入所有的系統(tǒng)顏色并自己維持,為了使應(yīng)用程序能夠正確反 映系統(tǒng)顏色的變化,MFC應(yīng)用程序可以在WM_SYSCOLORCHANGE消息中調(diào)用 Ctl3dColorChange函數(shù)。
2. 在MFC應(yīng)用程序的CWinApp類中的ExitInstance函數(shù)中調(diào)用Ctl3dUnregister函 數(shù),以方便Windows對CTL3D庫的正確管理。
3. 在MFC應(yīng)用程序的項目文件中加入CTL3D.LIB(可以用IMPORT.EXE產(chǎn)生)。 使用上述CTL3D的自動子類化的機(jī)制可以大大簡化使用3D控制,如果這不滿足你的要 求,那么你就必須單獨(dú)在需要使用3D控制的對話框的OnInitDialog()中自行子類化
相關(guān)的控制類了,典型的如下代碼片斷所示:
BOOL CMyDialog::OnInitDialog()
{
Ctl3dSubclassDlgEx(m_hWnd,CTL3D_ALL);
return TRUE;
}
上面講了在對話框中使用3D效果的辦法,如果用戶想在非對話框中使用3D控制,典 型的在FormView導(dǎo)出類中使用,可以在導(dǎo)出類的OnInitialUpdate函數(shù)中進(jìn)行適當(dāng)修 改,修改的大小取決于你是否使用了3D控制的自動子類化機(jī)制。如果使用前面提到 的自動子類化方法,那么僅需要在相應(yīng)的OnInitialUpdate函數(shù)中調(diào)用 Ctl3dSubclassDlg函數(shù)了,如下代碼片斷所示:
void CMyView::OnInitialUpdate()
{
Ctl3dSubclassDlg(m_hWnd,CTL3D_ALL);
}
否則,則需要修改如下:
void CMyView::OnInitialUpdate()
{
Ctl3dSubclassDlgEx(m_hWnd,CTL3D_ALL);
}
六、使用自定義消息
1、MFC的消息映射機(jī)制
Windows是一個典型的消息驅(qū)動的操作系統(tǒng),程序的運(yùn)行是靠對各種消息的響應(yīng)來實 現(xiàn)的,這些消息的來源非常廣泛,既包括Windows系統(tǒng)本身,如WM_CLOSE、 WM_PAINT、WM_CREATE和WM_TIMER等常用消息,又包括用戶菜單選擇、鍵盤加速 鍵以及工具條和對話框按鈕等等,如果應(yīng)用程序要與其它程序協(xié)同工作,那么消息的來 源還包括其它應(yīng)用程序發(fā)送的消息,串行口和并行口等硬件發(fā)送的消息等等?
之,Windows程序的開發(fā)是圍繞著對眾多消息的合理響應(yīng)和實現(xiàn)來實現(xiàn)程序的各種功 能的。使用過C語言來開發(fā)Windows程序的人都知道,在Windows程序的窗口回調(diào)函數(shù) 中需要安排Switch語句來響應(yīng)大量的消息,同時由于消息的間斷性使得不同的消息 響應(yīng)之間信息的傳遞是通過大量的全局變量或者靜態(tài)數(shù)據(jù)來實現(xiàn)的。 人們常用的兩種類庫OWL和MFC都提供了消息映射機(jī)制用以加速開發(fā)速度,使用者只 需要按規(guī)定定義好對應(yīng)消息的處理函數(shù)自身即可,至于實際調(diào)用由類庫本身所提供 的機(jī)制進(jìn)行,或采用虛函數(shù),或采用消息映射宏。為了有效節(jié)約內(nèi)存,MFC并不大量 采用虛函數(shù)機(jī)制,而是采用宏來將特定的消息映射到派生類中的響應(yīng)成員函數(shù)。這 種機(jī)制不但適用于Windows自身的140條消息,而且適用于菜單命令消息和按鈕控制 消息。MFC提供的消息映射機(jī)制是非常強(qiáng)大的,它允許在類的各個層次上對消息進(jìn)行 控制,而不簡單的局限于消息產(chǎn)生者本身。在應(yīng)用程序接收到窗口命令時,MFC將按 如下次序?qū)ふ蚁鄳?yīng)的消息控制函數(shù):
SDI應(yīng)用
MDI應(yīng)用
視口
視口
文檔
文檔
SDI主框架
MDI子框架
應(yīng)用
MDI主框架
應(yīng)用
大多數(shù)應(yīng)用對每一個命令通常都只有一個特定的命令控制函數(shù),而這個命令控制函 數(shù)也只屬于某一特定的類,但是如果在應(yīng)用中對同一消息有多個命令控制函數(shù),那 么只有優(yōu)先級較高的命令控制函數(shù)才會被調(diào)用。為了簡化對常用命令的處理,MFC在 基類中提供并實現(xiàn)了許多消息映射的入口,如打印命令,打印預(yù)覽命令,退出命令 以及聯(lián)機(jī)幫助命令等,這樣在派生類中就繼承了所有的基類中的消息映射函數(shù),從 而可以大大簡化編程。如果我們要在自己派生類中實現(xiàn)對消息的控制,那么必須在 派生類中加上相應(yīng)的控制函數(shù)和映射入口。
2、使用自己的消息
在程序設(shè)計的更深層次,人們常常會發(fā)現(xiàn)只依賴于菜單和命令按鈕產(chǎn)生的消息是不 夠的,常常因為程序運(yùn)行的邏輯結(jié)構(gòu)和不同視口之間數(shù)據(jù)的同步而需要使用一些自 定義的消息,這樣通過在相應(yīng)層次上安排消息響應(yīng)函數(shù)就可以實現(xiàn)自己的特殊需 要。比如如果我們要在特定的時間間隔內(nèi)通知所有數(shù)據(jù)輸出視口重新取得新數(shù)據(jù), 要依靠菜單命令和按鈕命令實現(xiàn)不夠理想,比較理想的解決辦法是采用定時器事件 進(jìn)行特定的計算操作,操作完成后再采用SendMessage發(fā)送自己的特定消息,只有當(dāng) 這一消息得到處理后才會返回主控程序進(jìn)行下一時間計算。通過在文檔層次上安排 對消息的響應(yīng)取得最新計算數(shù)據(jù),而后通過UpdateAllViews()成員函數(shù)來通知所有 相關(guān)視口更新數(shù)據(jù)的顯示。視口通過重載OnUpdate()成員函數(shù)就可以實現(xiàn)特定數(shù)據(jù) 的更新顯示。
如果用戶能夠熟練使用SendMessage()函數(shù)和PostMessage()函數(shù),那么要發(fā)送自定 義消息并不難,通常有兩種選擇,其一是發(fā)送WM_COMMAND消息,通過消息的WORD wParam參數(shù)傳遞用戶的命令I(lǐng)D,舉例如下:
SendMessage(WM_COMMAND,IDC_GETDATA,0); //MFC主框架發(fā)送 然后在文檔層次上安排消息映射入口:
ON_COMMAND(IDC_GETDATA, OnGetData)
同時在文檔類中實現(xiàn)OnGetData()函數(shù):
void CSimuDoc::OnGetData()
{
TRACE("Now in SimuDoc,From OnGetData\n");
UpdateAllViews(NULL);
}
注意在上中的消息映射入口需要用戶手工加入,Visual C++提供的ClassWizard并不 能替用戶完成這一工作。上中例子沒有使用PostMessage函數(shù)而使用SendMessage函 數(shù)的原因是利用了SendMessage函數(shù)的特點(diǎn),即它只有發(fā)送消息得到適當(dāng)處理后方才 返回,這樣有助于程序控制。
另一種發(fā)送自定義消息的辦法是直接發(fā)送命令I(lǐng)D,在控制層次上采用ON_MESSAGE來 實現(xiàn)消息映射入口,注意這時的命令控制函數(shù)的原型根據(jù)Windows本身消息處理的規(guī) 定必須如下:
afx_msg LONG OnCaculationOnce(WPARAM wParam,LPARAM lParam);
相對來講,這種機(jī)制不如上述機(jī)制簡單,也就不再贅述。
七、使用不帶文擋-視結(jié)構(gòu)的MFC應(yīng)用
文檔-視結(jié)構(gòu)的功能是非常強(qiáng)大的,可以適合于大多數(shù)應(yīng)用程序,但是有時我們只需 要非常簡單的程序,為了減少最終可執(zhí)行文件尺寸和提高運(yùn)行速度,我們沒有必要 使用文擋-視結(jié)構(gòu),典型的有簡單SDI應(yīng)用和基于對話框的應(yīng)用。
1、簡單SDI應(yīng)用
此時只需要使用CWinApp和CFrameWnd兩個類就完全可以了。由于CWinApp類封裝了 WinMain函數(shù)和消息處理循環(huán),因此任何使用MFC進(jìn)行編程的程序都不能脫離開該 類。實際上使用CWinApp類非常簡單,主要是派生一個用戶自己的應(yīng)用類,如 CMyApp,然后只需重載CWinApp類的InitInstance()函數(shù):
BOOL CMyApp::InitInstance()
{
m_pMainWnd=new CMainFrame();
ASSERT(m_pMainWnd!=NULL); //error checking only
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
至于所需要的主框架類,則可以直接使用ClassWizard實用程序生成,該類的頭文件 與實現(xiàn)代碼可以與CMyApp類的頭文件和實現(xiàn)代碼放在一起。注意,這里由一個技 巧,由于ClassWizard的使用需要有相應(yīng)的CLW文件存在,而收工建代碼時沒有對應(yīng) 的CLW文件,因此不能直接使用,解決辦法是進(jìn)入App Studio實用工具后使用 ClassWizard,此時系統(tǒng)會發(fā)覺不存在相應(yīng)的CLW文件,系統(tǒng)將提示你重建CLW文件并 彈出相應(yīng)對話框,這時候你不需要選擇任何文件就直接選擇OK按鈕,這樣系統(tǒng)將為 你產(chǎn)生一個空的CLW文件,這樣就可以使用ClassWizard實用工具了。為了將CWinApp 和CFrameWnd的派生類有機(jī)地結(jié)合在一起,只需在CFrameWnd派生類的構(gòu)造函數(shù)中進(jìn) 行窗口創(chuàng)建即可。典型代碼如下:
CMainFrame::CMainFrame()
{
Create(NULL,"DDE Client Application",WS_OVERLAPPEDWINDOW,rectDefault, NULL,MAKEINTRESOURCE(IDR_MAINFRAME));
}
采用ClassWizard實用程序生成相關(guān)類代碼后,所有的類的其它實現(xiàn)和維護(hù)就同普通由AppWizard實用程序產(chǎn)生的代碼一樣了。
2、基于對話框的程序
有些主要用于數(shù)據(jù)的輸入和輸出等的應(yīng)用在使用時沒有必要改變窗口大小,典型的 如各種聯(lián)機(jī)注冊程序,這些使用對話框作為應(yīng)用的主界面就足夠了,而且開發(fā)此類 應(yīng)用具有方便快捷的特點(diǎn),代碼也比較短小,如果直接采用各種控制類生成所需要 的控制就特別麻煩。在Visual C++ 4.x版本中使用AppWizard就可以直接生成基于對 話框的應(yīng)用。在Visual 1.x中沒有此功能,因此這類應(yīng)用需要程序員自己實現(xiàn) 實際上使用MFC實現(xiàn)基于對話框的應(yīng)用非常簡單,同樣只使用兩個MFC類作為基類, 這兩個類為CWinApp類和CDialog類。所使用的對話框主界面同樣可以先用App Studio編輯對話框界面,再使用ClassWizard產(chǎn)生相應(yīng)代碼框架,然后修改CMyApp類 的聲明,增加一個該對話框類的成員變量m_Mydlg,最后修改CMyApp類的
InitInstance()函數(shù)如下:
BOOL CMyApp::InitInstance()
{
m_Mydlg.DoModal();
return TRUE;
}
八、MFC應(yīng)用的人工優(yōu)化
使用C/C++編寫Windows程序的優(yōu)點(diǎn)就是靈活高效,運(yùn)行速度快,Visual C++編譯器 本身的優(yōu)化工作相當(dāng)出色,但這并不等于不需要進(jìn)行適當(dāng)?shù)娜斯?yōu)化,為了提高程 序的運(yùn)行速度,程序員可以從以下幾方面努力:
1) 減少不必要的重復(fù)顯示
相對來講,Windows的GDI操作是比較慢的,因此在程序中我們應(yīng)該盡可能地控制整 個視口的顯示和更新,如果前后兩此數(shù)據(jù)不發(fā)生變化,那么就不要重新進(jìn)行視口的 GDI圖形操作,尤其對于背景圖顯示時非萬不得已時不要重繪,同時不要經(jīng)常五必要 的刷新整個窗口。
2) 在視口極小化時不要進(jìn)行更新屏幕操作
在窗口處于極小化時沒有必要繼續(xù)進(jìn)行視口更新工作,這樣可以顯著提高速度。為 此需要在子窗口一級捕獲上述信息(視口不能捕獲該類信息),再在視口中進(jìn)行相 應(yīng)操作。如下代碼片段所示:
首先在子窗口類中添加如下程序段:
void CMyChild::OnSysCommand(UINT nID,LPARAM lparam)
{
CMDIChildWnd::OnSysCommand(nID,lparam);
if(nID==SC_MINIMIZE){
RedrawFlag=0;
}
else
RedrawFlag=1;
}
再在視口更新時中修改如下:
void CMyChart::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint )
{
if(pChild->RedrawFlag)
{
InvalidateRect(&r,FALSE);
TRACE("Now In CMyChart::OnUpdate\n");
}
}
至于上中pChild指針可以在視口創(chuàng)建的例程中獲取:
pChild=(CMyChild*)GetParent();
3) 使用永久性的資源
在頻繁進(jìn)行GDI輸出的視口中,如在監(jiān)控軟件中常常使用的趨勢圖顯示和棒圖顯示等 等,應(yīng)該考慮在類層次上建立頻繁使用的每種畫筆和刷子,這可以避免頻繁的在堆 中創(chuàng)建和刪除GDI對象,從而提高速度。
4) 使用自有設(shè)備描述句柄
亦即在創(chuàng)建視口時通過指定WM_OWNDC風(fēng)格來擁有自己的顯示設(shè)備句柄,這雖然會多 消耗一些內(nèi)存,一個DC大約占800字節(jié)的內(nèi)存,但是這避免了每次進(jìn)行GDI操作前創(chuàng) 建并合理初始化顯示設(shè)備句柄這些重復(fù)操作。特別是要自定義坐標(biāo)系統(tǒng)和使用特殊 字體的視口這一點(diǎn)尤其重要。在16M機(jī)器日益普遍的今天為了節(jié)約一點(diǎn)點(diǎn)內(nèi)存而降低 速度的做法并不可取。
5) 優(yōu)化編譯時指定/G3選項和/FPix87選項
/G3選項將強(qiáng)迫編譯器使用386處理器的處理代碼,使用嵌入式協(xié)處理器指令對那些 頻繁進(jìn)行浮點(diǎn)運(yùn)算的程序很有幫助。采用這兩種編譯開關(guān)雖然提高了對用戶機(jī)型的 要求,但在386逐漸被淘汰,486市場大幅度萎縮,586市場日益普及的今天上述問題 已經(jīng)不再成為問題了。
九、結(jié)束語
總體上講,使用Visual C++和MFC類庫進(jìn)行Windows編程是非常方便的,本文中所提 到的一些看法只代表本人的觀點(diǎn),經(jīng)驗也只是筆者根據(jù)近年使用MFC進(jìn)行Windows編 程的總結(jié),在此寫出來是希望對那些使用VC和MFC進(jìn)行Windows編程的同行有所幫 助,如有不同看法歡迎與筆者聯(lián)系討論。
十、參考文獻(xiàn):
[1]. David J.Kruglinski ,Visual C++技術(shù)內(nèi)幕,清華大學(xué)出版社,1995
[2]. 鄭雪明,Visual C++基礎(chǔ)類庫參考大全,學(xué)苑出版社,1994
[3]. B.R. Overland,Visual C++程序設(shè)計精髓,科學(xué)出版社,1995
[4]. Mike Klein,Windows程序員使用指南--DLL和內(nèi)存管理,清華大學(xué)出版社,
1995
[5]. Richard Wilton,Microsoft Windows軟件開發(fā)環(huán)境與技術(shù), 清華大學(xué)出版
社,1993
[6]. 芶建兵,倪維斗,Windows下網(wǎng)絡(luò)DDE的使用,電子與電腦,1997.2
作者聯(lián)系地址:清華大學(xué)熱能系動控教研組
聯(lián)系電話:(010)-62781739
BP:68213388-50610