C++實(shí)驗(yàn)報(bào)告 面向?qū)ο蟪绦蛟O(shè)計(jì)方法課程_第1頁(yè)
C++實(shí)驗(yàn)報(bào)告 面向?qū)ο蟪绦蛟O(shè)計(jì)方法課程_第2頁(yè)
C++實(shí)驗(yàn)報(bào)告 面向?qū)ο蟪绦蛟O(shè)計(jì)方法課程_第3頁(yè)
C++實(shí)驗(yàn)報(bào)告 面向?qū)ο蟪绦蛟O(shè)計(jì)方法課程_第4頁(yè)
C++實(shí)驗(yàn)報(bào)告 面向?qū)ο蟪绦蛟O(shè)計(jì)方法課程_第5頁(yè)
已閱讀5頁(yè),還剩25頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

面向?qū)ο蟪绦蛟O(shè)計(jì)方法課程綜合訓(xùn)練實(shí)驗(yàn)報(bào)告軟件工程42陳景琦2141601025陳錚2141601026郭家梁2141601027歐陽(yáng)鵬程2141601030實(shí)驗(yàn)指導(dǎo)老師:梁力實(shí)驗(yàn)地點(diǎn):軟件學(xué)院教學(xué)實(shí)驗(yàn)中心機(jī)房實(shí)驗(yàn)結(jié)束日期:2015-7-1實(shí)驗(yàn)報(bào)告提交日期:2015-7-6聯(lián)系電話:陳文實(shí)驗(yàn)一、建立隊(duì)列類模板隊(duì)列是一種經(jīng)典的數(shù)據(jù)結(jié)構(gòu)。其具有明顯的現(xiàn)實(shí)意義,如排隊(duì)隊(duì)伍。具有“先進(jìn)先出”的特點(diǎn)(FIFO),組織一個(gè)隊(duì)列的方法可以是線性表或者鏈表甚至散列表均可。隊(duì)列的成員應(yīng)該包括:數(shù)據(jù)成員Val[]隊(duì)首位置Front隊(duì)列容量Max_Vol隊(duì)列大小Now_Size一個(gè)隊(duì)列至少應(yīng)該支持以下操作(方法):入隊(duì)操作push出隊(duì)操作pop取隊(duì)首元素front由于需要可視化演示,我們需要在不改變隊(duì)列的前提下,或者說(shuō)保持?jǐn)?shù)據(jù)成員私有的前提下,讀取隊(duì)列中的所有元素,因此需要有透視功能的方法。讀取元素GetVal讀取大小GetSize讀取容量GetVol存儲(chǔ)結(jié)構(gòu)我們采用的存儲(chǔ)結(jié)構(gòu)是結(jié)合線性表與散列表思想的循環(huán)隊(duì)列結(jié)構(gòu)。先線性地申請(qǐng)一塊內(nèi)存空間Val[],元素個(gè)數(shù)為隊(duì)列容量Max_Vol。隊(duì)列中的第n個(gè)元素用Val[(Front+n)%Max_Val]來(lái)訪問(這里的n從0開始計(jì)數(shù)),利用取模運(yùn)算完成了循環(huán)處理,避免了在入隊(duì)出隊(duì)操作中重復(fù)申請(qǐng)內(nèi)存,提高了效率。隊(duì)列容量更改與拷貝構(gòu)造函數(shù)在更改隊(duì)列容量(Resize)的時(shí)候,若容量高于原容量,則先申請(qǐng)一塊大內(nèi)存,再將原數(shù)據(jù)全部拷貝過(guò)來(lái);若容量低于原容量,則申請(qǐng)一塊小內(nèi)存,再將原隊(duì)列中數(shù)據(jù)依次出隊(duì),再將其推送到新隊(duì)列中。這里會(huì)使用自定義的拷貝構(gòu)造函數(shù)的方法。關(guān)于模板類在隊(duì)列類(Queue)定義的前面加上一句template<classT>即可使單一數(shù)據(jù)類型的Queue變?yōu)镼ueue<T>。當(dāng)然之后的成員函數(shù)的實(shí)現(xiàn)的前面都要加一句template<classT>*拓展:我們可以利用序列化數(shù)據(jù)類型的方法,利用MFC的ListBox控件簡(jiǎn)單快捷地實(shí)現(xiàn)隊(duì)列模板。算法描述入隊(duì)push開始:開始:push(A)隊(duì)列未滿?Now_Size<Max_Vol?最后位置的元素賦值為A隊(duì)列長(zhǎng)度+1Val[(Front+Now_Size)%Max_Vol]←ANow_Size←Now_Size+1正常結(jié)束,返回0return0隊(duì)列已滿,返回1return1否是出隊(duì)pop開始:開始:pop()隊(duì)列非空?Now_Size>0?隊(duì)首位置向后推1隊(duì)列長(zhǎng)度-1Front←(Front+1)%Max_VolNow_Size←Now_Size-1正常結(jié)束,返回0return0空隊(duì)列,返回1return1否是*拓展:ListBox控件上的隊(duì)列實(shí)現(xiàn)MFC中l(wèi)istbox控件是為了顯示一系列的文本,每個(gè)文本占一行?;趯?duì)話框的MFC自帶ListBox控件,具有以下方法:在ListBox的尾部添加一項(xiàng)StringintAddString(LPCTSTRStr);獲取ListBox行的總數(shù)intGetCount();刪除ListBox中第nIndex行的文本,注意nIndex從0開始intDeleteString(uintnIndex);通過(guò)以上方法,以及適當(dāng)?shù)亟?,我們就能?shí)現(xiàn)隊(duì)列模板類的可視化。intQUEUE_VOL是之前設(shè)定的隊(duì)列容量,CListBoxList1為隊(duì)列的ListBox載體對(duì)象。CStringQUEUE_DataString為對(duì)數(shù)據(jù)個(gè)體建模后的String序列(序列化)。注意:使用ListBox之前要對(duì)其屬性做出一些調(diào)整,在屬性中將Sort改為False,若Sort為True,在某種規(guī)范的序列化后,就能實(shí)現(xiàn)【優(yōu)先隊(duì)列】數(shù)據(jù)結(jié)構(gòu)。另外也要注意這些重要的屬性: VerticalScrollbar:是否具有垂直滾動(dòng)條 HorizontalScrollbar:是否具有水平滾動(dòng)條 MultiColumn:是否多列顯示入隊(duì)代碼:if(List1.GetCount()<QUEUE_VOL) List1.AddString(QUEUE_DataString); else MessageBox(CString("隊(duì)列已滿"));出隊(duì)代碼: if(List1.GetCount()>0) List1.DeleteString(0); else MessageBox(CString("隊(duì)列已空"));調(diào)整容量代碼: for(inti=QUEUE_VOL;i<List1.GetCount();i++) List1.DeleteItem(i);可以看到,這種實(shí)現(xiàn)過(guò)程非常簡(jiǎn)單與簡(jiǎn)潔,而且多樣性與可重用性強(qiáng)。因?yàn)橐粋€(gè)數(shù)據(jù)結(jié)構(gòu)與CString總是可以互相映射(轉(zhuǎn)換)的。只要在類模板中實(shí)現(xiàn)由CString為參數(shù)的構(gòu)造函數(shù)與將所有成員變量映射到CString上的函數(shù)(序列化),即可完成類模板與ListBox的對(duì)接。實(shí)驗(yàn)二、簡(jiǎn)單蜂窩移動(dòng)通信系統(tǒng)演示一、實(shí)驗(yàn)任務(wù)及要求在本實(shí)驗(yàn)中,我們的目標(biāo)是要實(shí)現(xiàn)一個(gè)擁有基站和移動(dòng)臺(tái)的系統(tǒng),通過(guò)在用戶的可視化界面上對(duì)移動(dòng)臺(tái)的移動(dòng)來(lái)不斷告訴用戶的設(shè)備是否還在基站的通訊范圍內(nèi)程序開始運(yùn)行二、程序的算法描述程序開始運(yùn)行關(guān)閉程序?關(guān)閉程序? 是 否接受來(lái)自用戶鍵盤的消息來(lái)決定移動(dòng)哪一個(gè)設(shè)備根據(jù)用戶要求移動(dòng)相應(yīng)的設(shè)備并在用戶界面顯示設(shè)備移出通訊半徑?接受來(lái)自用戶鍵盤的消息來(lái)決定移動(dòng)哪一個(gè)設(shè)備根據(jù)用戶要求移動(dòng)相應(yīng)的設(shè)備并在用戶界面顯示設(shè)備移出通訊半徑? 是 否輸出提示消息,告訴用戶設(shè)備在通訊范圍外關(guān)閉程序輸出提示消息,告訴用戶設(shè)備在通訊范圍外關(guān)閉程序本實(shí)驗(yàn)的關(guān)鍵在于實(shí)時(shí)在用戶界面實(shí)現(xiàn)移動(dòng)臺(tái)的坐標(biāo)輸出以及圖形的移動(dòng)界面初始化實(shí)現(xiàn)代碼:voidC移動(dòng)基站View::OnDraw(CDC*/*pDC*/){ C移動(dòng)基站Doc*pDoc=GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; //TODO:在此處為本機(jī)數(shù)據(jù)添加繪制代碼 CImageimag,imag1,imag2,imag3,imag4,imag5,imag6; CClientDCdc(this); imag.Load(_T("res//base.png")); imag.Draw(dc,400,100,500,500); imag1.Load(_T("res//bijiben.png")); imag1.Draw(dc,lap.X,lap.Y,80,62); imag2.Load(_T("res//shouji.png")); imag2.Draw(dc,pho.X,pho.Y,28,49); imag3.Load(_T("res//shoubiao.png")); imag3.Draw(dc,wat.X,wat.Y,28,30); imag4.Load(_T("res//pingban.png")); imag4.Draw(dc,surf.X,surf.Y,51,35); imag5.Load(_T("res//PDA.png")); imag5.Draw(dc,pda.X,pda.Y,41,46); imag6.Load(_T("res//lanyaerji.png")); imag6.Draw(dc,ear.X,ear.Y,40,22); CClientDCcdc(this); CStringstr; str.Format(_T("筆記本電腦坐標(biāo)為:(%d,%d)"),lap.X-650,350-lap.Y); cdc.TextOutW(100,100,str); str.Format(_T("手機(jī)坐標(biāo)為:(%d,%d)"),pho.X-650,350-pho.Y); cdc.TextOutW(100,120,str); str.Format(_T("手表坐標(biāo)為:(%d,%d)"),wat.X-650,350-wat.Y); cdc.TextOutW(100,140,str); str.Format(_T("平板電腦坐標(biāo)為:(%d,%d)"),surf.X-650,350-surf.Y); cdc.TextOutW(100,160,str); str.Format(_T("PDA坐標(biāo)為:(%d,%d)"),pda.X-650,350-pda.Y); cdc.TextOutW(100,180,str); str.Format(_T("藍(lán)牙耳機(jī)坐標(biāo)為:(%d,%d)"),ear.X-650,350-ear.Y); cdc.TextOutW(100,200,str); cdc.TextOutW(100,450,_T("使用qwer控制筆記本電腦的上下左右")); cdc.TextOutW(100,470,_T("使用uiop控制平板電腦的上下左右")); cdc.TextOutW(100,490,_T("使用asdf控制手機(jī)的上下左右")); cdc.TextOutW(100,510,_T("使用hjkl控制PDA的上下左右")); cdc.TextOutW(100,530,_T("使用zxcv控制手表的上下左右")); cdc.TextOutW(100,550,_T("使用nm,.控制藍(lán)牙耳機(jī)的上下左右"));}因?yàn)橛?個(gè)移動(dòng)臺(tái),所以首先定義6個(gè)CImag對(duì)象,分別代表6個(gè)移動(dòng)臺(tái),分別載入并畫圖,以基站的圓心為原點(diǎn),所以需要進(jìn)行簡(jiǎn)單的坐標(biāo)變換。由于TextOutW函數(shù)要求的第三個(gè)參數(shù)是字符串型,則無(wú)法實(shí)時(shí)進(jìn)行坐標(biāo)輸出,所以先定義CString對(duì)象并實(shí)時(shí)用Format函數(shù)將坐標(biāo)轉(zhuǎn)換為字符串,再用TextOutW輸出。根據(jù)用戶鍵盤輸入移動(dòng)相應(yīng)設(shè)備實(shí)現(xiàn)代碼:voidC移動(dòng)基站View::OnChar(UINTnChar,UINTnRepCnt,UINTnFlags){ //TODO:在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值 CView::OnChar(nChar,nRepCnt,nFlags); if(nChar=='q') { --lap.Y; Draw(); if(((lap.X-650)*(lap.X-650)+(lap.Y-350)*(lap.Y-350))>=lap.Lradius*lap.Lradius) MessageBox(_T("你的筆記本電腦已經(jīng)超出范圍!")); } elseif(nChar=='w') { ++lap.Y; Draw(); if(((lap.X-650)*(lap.X-650)+(lap.Y-350)*(lap.Y-350))>=lap.Lradius*lap.Lradius) MessageBox(_T("你的筆記本電腦已經(jīng)超出范圍!")); } elseif(nChar=='e') { --lap.X; Draw(); if(((lap.X-650)*(lap.X-650)+(lap.Y-350)*(lap.Y-350))>=lap.Lradius*lap.Lradius) MessageBox(_T("你的筆記本電腦已經(jīng)超出范圍!")); } elseif(nChar=='r') { ++lap.X; Draw(); if(((lap.X-650)*(lap.X-650)+(lap.Y-350)*(lap.Y-350))>=lap.Lradius*lap.Lradius) MessageBox(_T("你的筆記本電腦已經(jīng)超出范圍!")); } elseif(nChar=='a') { --pho.Y; Draw(); if(((pho.X-650)*(pho.X-650)+(pho.Y-350)*(pho.Y-350))>=pho.Pradius*pho.Pradius) MessageBox(_T("你的手機(jī)已經(jīng)超出范圍!")); } elseif(nChar=='s') { ++pho.Y; Draw(); if(((pho.X-650)*(pho.X-650)+(pho.Y-350)*(pho.Y-350))>=pho.Pradius*pho.Pradius) MessageBox(_T("你的手機(jī)已經(jīng)超出范圍!")); } elseif(nChar=='d') { --pho.X; Draw(); if(((pho.X-650)*(pho.X-650)+(pho.Y-350)*(pho.Y-350))>=pho.Pradius*pho.Pradius) MessageBox(_T("你的手機(jī)已經(jīng)超出范圍!")); } elseif(nChar=='f') { ++pho.X; Draw(); if(((pho.X-650)*(pho.X-650)+(pho.Y-350)*(pho.Y-350))>=pho.Pradius*pho.Pradius) MessageBox(_T("你的手機(jī)已經(jīng)超出范圍!")); } elseif(nChar=='z') { --wat.Y; Draw(); if(((wat.X-650)*(wat.X-650)+(wat.Y-350)*(wat.Y-350))>=wat.Wradius*wat.Wradius) MessageBox(_T("你的手表已經(jīng)超出范圍!")); } elseif(nChar=='x') { ++wat.Y; Draw(); if(((wat.X-650)*(wat.X-650)+(wat.Y-350)*(wat.Y-350))>=wat.Wradius*wat.Wradius) MessageBox(_T("你的手表已經(jīng)超出范圍!")); } elseif(nChar=='c') { --wat.X; Draw(); if(((wat.X-650)*(wat.X-650)+(wat.Y-350)*(wat.Y-350))>=wat.Wradius*wat.Wradius) MessageBox(_T("你的手表已經(jīng)超出范圍!")); } elseif(nChar=='v') { ++wat.X; Draw(); if(((wat.X-650)*(wat.X-650)+(wat.Y-350)*(wat.Y-350))>=wat.Wradius*wat.Wradius) MessageBox(_T("你的手表已經(jīng)超出范圍!")); } elseif(nChar=='u') { --surf.Y; Draw(); if(((surf.X-650)*(surf.X-650)+(surf.Y-350)*(surf.Y-350))>=surf.Sradius*surf.Sradius) MessageBox(_T("你的平板電腦已經(jīng)超出范圍!")); } elseif(nChar=='i') { ++surf.Y; Draw(); if(((surf.X-650)*(surf.X-650)+(surf.Y-350)*(surf.Y-350))>=surf.Sradius*surf.Sradius) MessageBox(_T("你的平板電腦已經(jīng)超出范圍!")); } elseif(nChar=='o') { --surf.X; Draw(); if(((surf.X-650)*(surf.X-650)+(surf.Y-350)*(surf.Y-350))>=surf.Sradius*surf.Sradius) MessageBox(_T("你的平板電腦已經(jīng)超出范圍!")); } elseif(nChar=='p') { ++surf.X; Draw(); if(((surf.X-650)*(surf.X-650)+(surf.Y-350)*(surf.Y-350))>=surf.Sradius*surf.Sradius) MessageBox(_T("你的平板電腦已經(jīng)超出范圍!")); } elseif(nChar=='h') { --pda.Y; Draw(); if(((pda.X-650)*(pda.X-650)+(pda.Y-350)*(pda.Y-350))>=pda.PDAradius*pda.PDAradius) MessageBox(_T("你的PDA已經(jīng)超出范圍!")); } elseif(nChar=='j') { ++pda.Y; Draw(); if(((pda.X-650)*(pda.X-650)+(pda.Y-350)*(pda.Y-350))>=pda.PDAradius*pda.PDAradius) MessageBox(_T("你的PDA已經(jīng)超出范圍!")); } elseif(nChar=='k') { --pda.X; Draw(); if(((pda.X-650)*(pda.X-650)+(pda.Y-350)*(pda.Y-350))>=pda.PDAradius*pda.PDAradius) MessageBox(_T("你的PDA已經(jīng)超出范圍!")); } elseif(nChar=='l') { ++pda.X; Draw(); if(((pda.X-650)*(pda.X-650)+(pda.Y-350)*(pda.Y-350))>=pda.PDAradius*pda.PDAradius) MessageBox(_T("你的PDA已經(jīng)超出范圍!")); } elseif(nChar=='n') { --ear.Y; Draw(); if(((ear.X-650)*(ear.X-650)+(ear.Y-350)*(ear.Y-350))>=ear.Eradius*ear.Eradius) MessageBox(_T("你的藍(lán)牙耳機(jī)已經(jīng)超出范圍!")); } elseif(nChar=='m') { ++ear.Y; Draw(); if(((ear.X-650)*(ear.X-650)+(ear.Y-350)*(ear.Y-350))>=ear.Eradius*ear.Eradius) MessageBox(_T("你的藍(lán)牙耳機(jī)已經(jīng)超出范圍!")); } elseif(nChar==',') { --ear.X; Draw(); if(((ear.X-650)*(ear.X-650)+(ear.Y-350)*(ear.Y-350))>=ear.Eradius*ear.Eradius) MessageBox(_T("你的藍(lán)牙耳機(jī)已經(jīng)超出范圍!")); } elseif(nChar=='.') { ++ear.X; Draw(); if(((ear.X-650)*(ear.X-650)+(ear.Y-350)*(ear.Y-350))>=ear.Eradius*ear.Eradius) MessageBox(_T("你的藍(lán)牙耳機(jī)已經(jīng)超出范圍!")); }}用四個(gè)按鍵分別代表一個(gè)設(shè)備的上下左右,使用nChar接受用戶輸入的指令,每移動(dòng)一次都相應(yīng)判斷一次該設(shè)備是否移出了通訊半徑,若移出了通訊半徑,則彈出一個(gè)對(duì)話框告訴用戶相應(yīng)設(shè)備在通訊范圍外由于Windows在畫圖界面下移動(dòng)產(chǎn)生的是疊加效應(yīng),所以我們每進(jìn)行一次移動(dòng)都要重新將屏幕刷新一次,以避免產(chǎn)生圖片重疊的情況。屏幕刷新實(shí)現(xiàn)代碼:voidC移動(dòng)基站View::Draw(){ CImageimg,img1,img2,img3,img4,img5,img6; CClientDCdcd(this); img.Load(_T("res//base.png")); img.Draw(dcd,400,100,500,500); img1.Load(_T("res//bijiben.png")); img1.Draw(dcd,lap.X,lap.Y,80,62); img2.Load(_T("res//shouji.png")); img2.Draw(dcd,pho.X,pho.Y,28,49); img3.Load(_T("res//shoubiao.png")); img3.Draw(dcd,wat.X,wat.Y,28,30); img4.Load(_T("res//pingban.png")); img4.Draw(dcd,surf.X,surf.Y,51,35); img5.Load(_T("res//PDA.png")); img5.Draw(dcd,pda.X,pda.Y,41,46); img6.Load(_T("res//lanyaerji.png")); img6.Draw(dcd,ear.X,ear.Y,40,22); CClientDCcdc2(this); CStringstr; str.Format(_T("筆記本電腦坐標(biāo)為:(%d,%d)"),lap.X-650,350-lap.Y); cdc2.TextOutW(100,100,str); str.Format(_T("手機(jī)坐標(biāo)為:(%d,%d)"),pho.X-650,350-pho.Y); cdc2.TextOutW(100,120,str); str.Format(_T("手表坐標(biāo)為:(%d,%d)"),wat.X-650,350-wat.Y); cdc2.TextOutW(100,140,str); str.Format(_T("平板電腦坐標(biāo)為:(%d,%d)"),surf.X-650,350-surf.Y); cdc2.TextOutW(100,160,str); str.Format(_T("PDA坐標(biāo)為:(%d,%d)"),pda.X-650,350-pda.Y); cdc2.TextOutW(100,180,str); str.Format(_T("藍(lán)牙耳機(jī)坐標(biāo)為:(%d,%d)"),ear.X-650,350-ear.Y); cdc2.TextOutW(100,200,str); cdc2.TextOutW(100,450,_T("使用qwer控制筆記本電腦的上下左右")); cdc2.TextOutW(100,470,_T("使用uiop控制平板電腦的上下左右")); cdc2.TextOutW(100,490,_T("使用asdf控制手機(jī)的上下左右")); cdc2.TextOutW(100,510,_T("使用hjkl控制PDA的上下左右")); cdc2.TextOutW(100,530,_T("使用zxcv控制手表的上下左右")); cdc2.TextOutW(100,550,_T("使用nm,.控制藍(lán)牙耳機(jī)的上下左右"));}這樣,我們就能每進(jìn)行一次移動(dòng)之后都實(shí)時(shí)看到最新的移動(dòng)之后的圖像而沒有疊加效應(yīng)。最后,附上程序運(yùn)行的結(jié)果:實(shí)驗(yàn)三、實(shí)現(xiàn)電影院售票實(shí)驗(yàn)四、記事本實(shí)驗(yàn)五、七巧板 七巧板是我國(guó)傳統(tǒng)的智力游戲與消遣工具,僅僅7塊小板,竟能千變?nèi)f化,因此深受人們喜愛。現(xiàn)在要將這個(gè)經(jīng)典的游戲利用VisualC++再現(xiàn)到計(jì)算機(jī)上。自定義類幾何形狀類Shape構(gòu)造函數(shù)構(gòu)造函數(shù)有3份重載 //默認(rèn)構(gòu)造函數(shù) Shape();//預(yù)設(shè)塊的構(gòu)造函數(shù) Shape(intID); //從預(yù)設(shè)Shape中拷貝構(gòu)造前cnt個(gè)圖形 Shape(Shape*S,intcnt);預(yù)設(shè)塊 一般來(lái)說(shuō),預(yù)設(shè)塊是指七巧板中有7塊經(jīng)典的預(yù)設(shè)拼塊。 為了增加游戲性,在后面的版本中還可能加入新的拼塊,甚至用戶自定義的拼塊。數(shù)據(jù)成員某些全局常量可以利用靜態(tài)成員變量來(lái)定義,避免使用宏來(lái)規(guī)避一些意外的錯(cuò)誤。staticintSIZE;staticCPointSTART;SIZE表示整個(gè)拼塊的大小(一開始七巧板是拼成一個(gè)大正方形的,這個(gè)SIZE就是指其邊長(zhǎng)),START表示初始化時(shí)拼塊們的起點(diǎn),這些拼塊在初始化構(gòu)造的時(shí)候?qū)⑹褂肧TART變量進(jìn)行定位。 intMAX_POINT; CPoint*Vertex;MAX_POINT表示這個(gè)拼塊的頂點(diǎn)數(shù),而Vertex數(shù)組則用于存放頂點(diǎn)。 COLORREFCOLOR;COLOR表示拼塊的顏色,這通常使用VisualStudio自帶的RGB宏來(lái)進(jìn)行賦值。 boolselectedselected表示拼塊是否被選中,選中的拼塊是當(dāng)前要操作的拼塊,我們應(yīng)該確保不能有多個(gè)拼塊被同時(shí)選中。成員函數(shù)(方法)voidDraw(CDC*pDC,intmode=0);voidSelect();voidSelect(boolflag);boolIsInside(CPointpoint);CPointGetCenter();voidMove(CPointstart,CPointend);voidRotate(CPointCenter,intdeg);繪圖函數(shù)對(duì)一個(gè)圖形的繪制,首先要確定載體,即畫在哪里的問題,這個(gè)可以用CDC*來(lái)定位,另外就是繪制模式mode。要知道繪制的東西是不能擦除的,只能覆蓋。比如說(shuō)一個(gè)物體移動(dòng)了,我重繪了新的位置,然而僅僅是這樣的話,老地方會(huì)殘留著物體的殘影。解決方案之一是在每次重繪之前將整個(gè)可見區(qū)域刷白。解決方案之二就是只將必要區(qū)域刷白。顯然方案二的效率要高許多,具體的實(shí)現(xiàn)就是考慮不同的繪制模式mode,mode默認(rèn)為0,當(dāng)mode為1的時(shí)候,將畫筆與刷子的顏色改為背景色,這樣就能將最小的必要區(qū)域刷白。另外一個(gè)小細(xì)節(jié)是,選中(Selected)與未選中(!Selected)的邊框是不一樣的,這樣就可以造成“選中的突出效果”。voidShape::Draw(CDC*pDC,intmode){ CBrushB; CPenNOT_SELECTED,SELECTED; CBrushERASE; ERASE.CreateSolidBrush(RGB(240,240,240)); NOT_SELECTED.CreatePen(PS_SOLID,1,RGB(0,0,0)); SELECTED.CreatePen(PS_SOLID,3,RGB(240,240,240)); B.CreateSolidBrush(COLOR); if(selected) pDC->SelectObject(SELECTED); else pDC->SelectObject(NOT_SELECTED); if(mode) pDC->SelectObject(ERASE); else pDC->SelectObject(B); pDC->Polygon(Vertex,MAX_POINT);}方法:選擇 這里Select有2份重載,默認(rèn)是“改變選擇狀態(tài)”,選中的變?yōu)槲催x中的,未選中的變?yōu)檫x中的。另外一份重載則是直接為selected賦值,這在我們不知道對(duì)象是選中的還是未選中的時(shí)候有用。//選中/取消voidShape::Select(){ selected=!selected;}//SetSelectionvoidShape::Select(boolflag){ selected=flag;}方法:幾何關(guān)系IsInside函數(shù)給出了“某點(diǎn)是否在多邊形內(nèi)部”的答案,這在判斷“鼠標(biāo)是否點(diǎn)到了拼塊”是有用的。GetCenter則是給出“圖形的默認(rèn)旋轉(zhuǎn)中心”的答案,由于有特殊存儲(chǔ)方法,Vertex是按照順序存儲(chǔ)的,只要確保等腰直角三角形中Vertex[0]與Vertex[2]都是斜邊上的頂點(diǎn),就能保證算法的正確性。boolShape::IsInside(CPointpoint){ CRgnrgn; rgn.CreatePolygonRgn(Vertex,MAX_POINT,ALTERNATE); returnrgn.PtInRegion(point);}CPointShape::GetCenter(){ returnCPoint((Vertex[0].x+Vertex[2].x)/2,(Vertex[0].y+Vertex[2].y)/2);}方法:變更 Rotate(旋轉(zhuǎn))與Move(平移)是兩種基本的方法。其中,Rotate的一般實(shí)現(xiàn)要考慮旋轉(zhuǎn)的坐標(biāo)變換: 逆時(shí)針旋轉(zhuǎn)的矩陣運(yùn)算公式: 另外,由于算法幾何上的精度問題,必須盡量減小浮點(diǎn)運(yùn)算帶來(lái)的誤差。對(duì)于浮點(diǎn)運(yùn)算要盡量利用更多的有效位數(shù)來(lái)保證精度。voidShape::Rotate(CPointCenter,intdeg){ doublerad=deg*Pirad; LONGrate=1000000; for(inti=0;i<MAX_POINT;i++) { doubledx=(Vertex[i].x-Center.x)*rate; doubledy=(Vertex[i].y-Center.y)*rate; Vertex[i].x=(LONG)((cos(rad)*dx-sin(rad)*dy)/rate+Center.x); Vertex[i].y=(LONG)((sin(rad)*dx+cos(rad)*dy)/rate+Center.y); }}Move(平移)的實(shí)現(xiàn)就相對(duì)簡(jiǎn)單得多,只要知道一個(gè)向量即可,或者說(shuō),從何方來(lái),又往何處去……voidShape::Move(CPointstart,CPointend){ for(inti=0;i<MAX_POINT;i++) { Vertex[i].x+=end.x-start.x; Vertex[i].y+=end.y-start.y; }}事件&消息鼠標(biāo)響應(yīng) 鼠標(biāo)按下的時(shí)候應(yīng)該做什么呢? 當(dāng)左鍵按下,如果判斷到鼠標(biāo)在某拼塊上,那么意味著選中了這個(gè)拼塊。用一個(gè)Dlg類中的成員變量(實(shí)際上意味著全局變量)SelectID來(lái)表示選中了誰(shuí),當(dāng)SelectID為-1的時(shí)候表示沒有選中任何拼塊,也可以視為有個(gè)虛構(gòu)的拼塊-1。對(duì)數(shù)據(jù)做了一些改變以后要記得重繪圖形Refresh。 *異步處理方法Refresh:控制重繪的區(qū)域,不將所有的繪制工作都放到OnPaint里,以提高重繪效率,這在高頻率重繪與繪制量大混合的情況下尤為重要,而且實(shí)現(xiàn)比較容易。voidCMFC七巧板Dlg::OnLButtonDown(UINTnFlags,CPointpoint){ //TODO:在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值 for(inti=0;i<Shape_Count;i++) { if(Chip[i].IsInside(point)) { Chip[i].Select(); SelectID=i; SelectPoint=point; //防止選中兩個(gè) break; } } Refresh(0); CDialogEx::OnLButtonDown(nFlags,point);}左鍵放開時(shí)要取消Select,并且重繪。voidCMFC七巧板Dlg::OnLButtonUp(UINTnFlags,CPointpoint){ //TODO:在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值 if(SelectID>=0) Chip[SelectID].Select(); SelectID=-1; Refresh(0); CDialogEx::OnLButtonUp(nFlags,point);}在左鍵按住的同時(shí),移動(dòng)鼠標(biāo),拼塊將跟隨鼠標(biāo)移動(dòng)。這里要特別注意先擦除再繪制新圖形。voidCMFC七巧板Dlg::OnMouseMove(UINTnFlags,CPointpoint){ //TODO:在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值 if(SelectID>=0) { //先擦除 Chip[SelectID].Draw(GetDC(),1); //移動(dòng) Chip[SelectID].Move(SelectPoint,point); //更新位置 SelectPoint=point; } //異步重繪 Refresh(0); CDialogEx::OnMouseMove(nFlags,point);}右鍵按下時(shí)調(diào)用旋轉(zhuǎn)方法,這里要注意的是,調(diào)用的同時(shí)將鼠標(biāo)位置傳入旋轉(zhuǎn)函數(shù),所以拼塊以鼠標(biāo)位置為旋轉(zhuǎn)中心進(jìn)行旋轉(zhuǎn)。這意味著,你點(diǎn)擊拼塊的不同位置時(shí),旋轉(zhuǎn)的效果是不同的。voidCMFC七巧板Dlg::OnRButtonDown(UINTnFlags,CPointpoint){ //TODO:在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值 if(SelectID>=0) { Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Rotate(point,45); } Refresh(0); CDialogEx::OnRButtonDown(nFlags,point);}鍵盤響應(yīng)鍵盤相應(yīng)的部分就很簡(jiǎn)單了,大體上與鼠標(biāo)響應(yīng)沒有大區(qū)別。區(qū)別在于鍵盤的輸入沒有給旋轉(zhuǎn)傳入旋轉(zhuǎn)中心,這時(shí)我們就直接使用幾何中心來(lái)作為旋轉(zhuǎn)中心了。說(shuō)明:Q,E為不同方向的旋轉(zhuǎn),W,S,A,D為四個(gè)方向的平移,Z,C表示選定不同的拼塊。voidCMFC七巧板Dlg::OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags){ //TODO:在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值 CPointCenter;if(SelectID>=0) { Center=Chip[SelectID].GetCenter(); switch(nChar) { case'E': Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Rotate(Center,45); break; case'Q': Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Rotate(Center,-45); break; case'W': Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Move(Center,Center+CPoint(0,-10)); break; case'S': Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Move(Center,Center+CPoint(0,10)); break; case'A': Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Move(Center,Center+CPoint(-10,0)); break; case'D': Chip[SelectID].Draw(GetDC(),1); Chip[SelectID].Move(Center,Center+CPoint(10,0)); break; } } if(nChar=='Z') { if(SelectID>=0) Chip[SelectID].Select(); SelectID=(SelectID+2)%Shape_Count-1; Chip[SelectID].Select(); } if(nChar=='C') { if(SelectID>=0) Chip[SelectID].Select(); SelectID=(SelectID-2+Shape_Count)%Shape_Count-1; Chip[SelectID].Select(); } Refresh(0); CDialogEx::OnKeyDown(nChar,nRepCnt,nFlags);}DEBUG:*鍵盤消息&攔截在對(duì)話框上有某些控件時(shí),鍵盤消息往往會(huì)被錯(cuò)誤地?cái)r截,交給這些控件,然而這些控件是沒有接收鍵盤消息的功能的,這是CWnd基類的PreTranslateMessage這個(gè)虛函數(shù)需要重寫(重載)。PreTanslateMessage是MFC中消息傳遞機(jī)制中的一個(gè)分流器,負(fù)責(zé)將不同的消息分配到不同的控件(容器)。所以如果消息不能正確地被接收,多半是這個(gè)函數(shù)不正確。這個(gè)函數(shù)完全可以取代KeyDown,也可以將Msg傳給KeyDown,這兩種解決方案都是可行的。BOOLCMFC七巧板Dlg::PreTranslateMessage(MSG*pMsg){ CPointCenter; if(SelectID>=0) Center=Chip[SelectID].GetCenter(); if(pMsg->message==WM_KEYDOWN) { //判斷具體鍵 switch(pMsg->wParam) { case'E': if(SelectID>=0) { Chip[SelectID].Draw(GetDC(),1); Chip[SelectI

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論