作者:pengkuny
下決心把MFC學好,
從暑假到現(xiàn)在,
連皮毛都沒學到一點,
真他*丟臉.
發(fā)現(xiàn)寫日記的方法效果不錯,
該記住的終于記住了
看了仍然不懂的,用"@#$%"符號表示.
錯誤理解必然一大堆,只能期望日后補救拉,只是希望不要錯得太離譜.
2006.11.10
一.消息響應事件的模式,那么消息怎么起作用的?
?? 消息以調用一個窗口的窗口過程的形式來表明自己的存在.伴隨4個參數(shù):
消息所指窗口句柄(包含很多窗口的信息),
消息ID(整型值,消息類型,以WM_開頭),
兩個名為wParam和lParam的32位參數(shù).
二.@#$%
API函數(shù)RegisterClass注冊的類為WNDCLASS
而"窗口類"指從MFC的CWnd派生的C++類
三.匈牙利命名法:
b,c/ch,By,clr,(x,y),(cx,cy),w,dw,n,I,l,s,sz/str,p,fn,h,wnd,MSG,WM_,g,AFXAPI,WINAPI,SW_,WS_,MM_
函數(shù)名不使用下劃線
所有的類型和常量都是大寫字母,但名字中可以允許有下劃線
所有C++的類必須以大寫C為前綴,類名字的每一個子名的第一個字母都必須大寫
四.熟悉一些常用的AFX函數(shù)
五.接觸到的一些類:
CCmdTarget--CWinTread--CWinApp
Cwnd--CFrameWnd,凡是以Wnd結尾的類都是Cwnd類,框架窗口類
六.protected:對外相當于pravite,對內相當于public
七.頭文件AfxWin.h,里面包含所有類的聲明,可以仔細看一看
八.查看CWinApp的類定義
待查:分析CWinApp類;
???? DECLARE_DYNAMIC;
?
2006.11.11
一.應用程序窗口必須由InitInstance創(chuàng)建,故即使最小的MFC程序都必須覆蓋這個虛函數(shù).
?? 同理,CMainWnd繼承自CFrameWnd,它必須有自己的構造函數(shù),調用Create創(chuàng)建一個窗口.
?? CWinApp的一個非常重要的成員函數(shù)CWnd* m_pMainWnd;它是public的,指向CWnd類
二@#$%
protected:friend class CWinApp;WinApp是CFrameWnd的友元
三.ShowWindow(m_nCmdShow);UpdateWindow();
?? m_nCmdWindow表示窗口CWnd的顯示狀態(tài),CWinApp的public成員函數(shù),其值以SW_前綴,默認為SW_SHOWNORMAL
四.從Winmain.cpp中可以看到:
?? AfxWinMain在幕后操縱這一切的運行
五.現(xiàn)在可以把框架窗口看作頂層窗口看待,它是應用程序與外部世界的主要接口.
六.消息映射:將消息和成員函數(shù)相互關聯(lián)的表.
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
??? ON_WM_PAINT ()
END_MESSAGE_MAP ()
CMainWindow為消息所屬的類; CFrameWnd為消息所屬的類的基類,因為消息可以繼承.
使用ON_MESSAGE(WM_SETTEXT,OnSetText);創(chuàng)建自己的消息映射.
?
2006.11.13
主題:在窗口中繪圖
一.GDI(Graphics Device Interface)圖形設備接口負責圖形輸出.
?? 具體由設備描述表(DC)來做.
二.4類設備描述表類:
CPaintDC
CClientDC
CWindowDC
CMetaFileDC
二.創(chuàng)建一個設備描述表后,如CPaintDC dc(this);
就可以調用各種畫圖函數(shù)了,dc.Fun();
?? 6個GDI對象:跟設備描述表dc是什么關系?
基類:CGDIObject類
畫筆Pen
畫刷Brush
字體Font
位圖Bitmap
調色板Palette
區(qū)域Region
??
? 它們實際上刻畫了設備描述表dc的屬性,并不是dc的函數(shù),
通過dc.SelectObject(GDI對象指針)選入設備描述表.
三.回憶WM_PAINT消息是怎么產(chǎn)生的:
移動了窗口
原來遮掩的部分顯示出來
窗口大小改變
?
CPaintDC類只能干這個事,只能局限于響應WM_PAINT消息,所以要選用CClientDC類
四.取得全屏訪問權,入屏幕截取程序,很少見
傳遞NULL指針
CClientDC dc(NULL);
一般情況下,取this指針給構造函數(shù)即可:
CPaintDC dc(this);
CPaintDC *pDC = new CPaintDC(this);
this指向調用對象本身,不可改變.
?
五.掌握設備描述表屬性Attribute的常見術語
文本顏色 CDC::SetTextColor
背景顏色 CDC::SetBKColor
背景模式 CDC::SetBKMode
映射模式 CDC::SetMapMode
繪圖模式 CDC::SetROP2
分別由相關函數(shù)調用,非常方便.
既然有Set函數(shù),毫無疑問,就有Get函數(shù)
六.比如OnPaint函數(shù),每次調用完以后,函數(shù)內定義的設備描述表自然被銷毀
想要保存它的狀態(tài),請使用
CDC::SaveDC,對應就有:
CDC::RestoreDC來恢復
七.映射模式:
一個邏輯單位對應的距離,畫圖的時候只要告訴GDI多少單位即可,
實際上這些模式都擴大了本來的表示范圍,使得大尺寸的東東都可以壓縮比例顯示
8種映射模式,非常簡單:
(1)默認MM_TEXT
(2)公制模式:y軸反轉,完全符合數(shù)學坐標,所以y值一定要用負的.
(3)可編程模式:不反轉,但允許反轉
?? MM_ISOTROPIC? :x,y同等縮放
?? MM_ANISOTROPIC:x,y獨立縮放
八.可編程模式
SetViewportExt
SetWindowExt
九.補充:堆和棧的區(qū)別
首先必須弄懂C/C++中內存區(qū)的分配:
堆:順序隨意
棧:先進后出
一個由c/C++編譯的程序占用的內存分為以下幾個部分
1、棧區(qū)(stack)— 編譯期間就分配好的內存空間,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結構中的棧。 一切管理由系統(tǒng)負責.
2、堆區(qū)(heap) — 程序運行期間動態(tài)分配的內存空間,你可以根據(jù)程序的運行情況確定要分配的堆內存的大小.由alloca,new申請,并由free/delete釋放.注意它與數(shù)據(jù)結構中的堆是兩回事。
3、全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結束后有系統(tǒng)釋放
static指函數(shù)調用后仍然不消失的局部變量.
4、文字常量區(qū) —常量字符串就是放在這里的。 程序結束后由系統(tǒng)釋放
5、程序代碼區(qū)—存放函數(shù)體的二進制代碼。
棧:在Windows下,棧是由高地址向低地址擴展的數(shù)據(jù)結構,是一塊連續(xù)的內存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的,在 WINDOWS下,棧的大小是2M,如果申請的空間超過棧的剩余空間時,將提示overflow。
速度快.
堆:堆是由底向高地址擴展的數(shù)據(jù)結構,是不連續(xù)的內存區(qū)域。
容易產(chǎn)生碎片.
舉例:
?CPoint ptX; 和 CPoint ptX = new CPoint();兩者的區(qū)別是什么?
前者棧分配,后者堆分配,用完后delete.
與C++不同,Java自動管理棧和堆,程序員不能直接地設置棧或堆。
十.終于他媽的明白GetClientRect的作用了:
CRect rect;
GetClientRect(&rect);
將當前窗口的尺寸(比如非最大非最小的狀態(tài))來初始化這個矩形,
而不是用矩形來初始化窗口大小(難怪rect沒初始化)???????????????????????????????????????????????????????????????????????????????????????????????????????????
十一.
CRect rect;
GetClientRect(&rect);
dc.SetMapMode(MM_ANISOTROPIC);??????????????????? //可編程模式
dc.SetWindowExt(500,600);???????????????????????? //邏輯尺寸就是500*600單位
dc.SetViewportExt(rect.Width(),rect.Height());??? //設備單位/像素:rect.Width(),rect.Height()
水平方向--每單位多少像素:rect.Width()/500
垂直方向--每單位多少像素:rect.Height()/600????????????????????????????????????????????????????????? 縮放比例就這么來.
SetWindowExt(x1, y1);?????????????????????
SetViewportExt(x2, y2);
與
SetWindowExt(100*x1, 100*y1);??????????????????????
SetViewportExt(596*x2, 596*y2);
效果完全一樣,無非是一個比例而已.
在同比例縮放模式MM_ISOTROPIC下,
縮放比例取min{x2/x1, y2/y1}!
兩個范圍設置函數(shù)僅僅干了一件事,設置比例,其后畫圖使用邏輯單位,跟它們就沒有直接關系了.????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
2006.11.15
一.這句話不明白:
"使用SetWindowExt和SetViewportExt時要注意:在MM_ISOTROPIC映射模式下,
應該首先調用SetWindowExt.否則,部分客戶區(qū)可能會因落在窗口的邏輯范圍之外而不能使用。
而在MM_ANISOTROPIC映射模式下,窗口范圍和視口范圍中先設置哪一個都無關緊要。"
實際上,我實驗發(fā)現(xiàn):只要掌握放大因子k=min{x2/x1, y2/y1},和窗口真實邏輯大小(X,Y),那么畫出來的圖形(x,y)
大小就是(kx,ky),只要kx<=X, ky<=Y,那么就不會有客戶區(qū)落在窗口的邏輯范圍之外的事情發(fā)生.
二.坐標轉換
CDC::LPtoDP
CDC::DPtoLP
三.移動原點,終于搞懂了
SetViewportOrg(x,y)將視口原點移至(x,y)等價于通知Windows把邏輯點(0,0)映射成設備點(x,y),
什么意思?就是把邏輯原點移到設備點(x,y)的位置,在這個新位置安家作為新的邏輯原點,
對設備坐標沒有絲毫改變,所謂映射,只不過是一種簡單的移動關系,并不改變設備坐標
同理,SetWindowOrg(x, y)將邏輯原點(x,y)移到原設備原點(0, 0)的位置
述說的時候,(x, y)和(0, 0);邏輯點和設備點
兩個"反義詞"不要同時反說,否則等于沒說.
統(tǒng)一說:把邏輯點(*,*)移到設備點(*,*)的位置
四.兩個設備坐標值:
用戶坐標值
屏幕坐標值
互相轉化;
CWnd::ClientToScreen
CWnd::ScreenToClient
四.獲取設備信息:
CDC::GetDeviceCaps
五.GDI畫筆CPen
樣式PS_
寬度
顏色
Windows自動選用當前畫筆給圖形加邊框,若選用PS_NULL"NULL筆",邊框就沒有了.
擴展筆:@#$%
六.GDI畫刷CBrush
畫刷用來干什么?作為dc的屬性,它一旦選入,就自動填充一切畫出的封閉圖形
類型:
單色
帶陰影線:6種,默認白色背景
帶圖案:填充指定的位圖
@#$%:
移動畫刷原點:選入設備之前
brush.UnrealizeObject();
dc.SetBrushOrg(x0, y0);//注意,畫刷原點以設備坐標值給出
dc.SelectObject(&brush);
七.CDC文本函數(shù):
@#$%
DrawText
TextOut等
八.GDI字體CFont
一個很好用的API函數(shù)::ZeroMemory(指針,內存大小)將一塊內存清零.
LOGFONT為字體結構,如:
LOGFONT lf;
::ZeroMemory(&lf, sizeof(lf));
初始化lf;
lf.lfEscapement和lf.Orientation指定文本旋轉角度的10倍值
CRect::OffsetRect(x,y)設置一個矩形坐標偏移量.
光柵字體:位圖保存,不適合縮放,MS Sans Serif
TrueType字體:任意縮放
Times New Roman
Arial
Courier
Symbol
八.備用對象:一種非常好的GDI對象,系統(tǒng)預定義,無須顯式創(chuàng)建,也無須刪除,非常安全.
CDC::SelectStockObject選入DC
CDC::CreateStockObject賦給已有對象
九.怎么刪除GDI對象?
堆上創(chuàng)建的/new,需要CGDIObject::DeleteObject顯式刪除
十.怎么取消GDI對象?
變相的方法:通過選入另外一個GDI對象將當前GDI對象從設備描述表中"提取"出來.
先保存調用SelectObject時返回的指針,
然后將這個指針重選默認對象,或者選入備用對象
來取代當前對象.
實際上,@#$%
十一.CString::Format:
與C語言的printf功能一樣,支持printf所有的格式,
如string.(_T("d%"), i/100);
然后dc.TextOut即可.
十二.滾動條:窗口樣式參數(shù),將來學到更高級的滾動條控件,就應該可以拋棄這種低級的方式
滾動條向它所屬的窗口發(fā)送消息,一切響應有窗口來做,滾動條很少自己響應消息.
Create的第三個參數(shù)
WS_VSCROLL , WS_
設置:范圍,位置,頁面大小
方法一:
CWnd::SetScrollRange和CWnd::SetScrollPos
參數(shù)TRUE意味著重不重畫,小技巧
方法二:CWnd::SetScrollInfo,很好用,如:
??? SCROLLINFO si;
??? si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
??? si.nMin = 0;
??? si.nMax = nHScrollMax;
??? si.nPos = m_nHScrollPos;
??? si.nPage = m_nHPageSize;
??? SetScrollInfo (SB_HORZ, &si, TRUE);
十三.滾動條滑塊大小與窗口尺寸同步變化:
WM_SIZE消息:
窗口建立的時候,就有WM_SIZE的消息傳來,以后只要窗口尺寸改變,就有WM_SIZE消息傳來
用OnSize處理.
afx_msg void Onsize(UINT nType, int cx, int cy);輕松解決//類型+新寬度+新高度
十四.滾動條消息類型自動傳遞給nCode參數(shù),位置信息pos都是自動傳遞給消息處理函數(shù),不用擔心
WM_HSCROLL,WM_VSCROLL不是具體的消息類型,SB_才是,
OnHScroll,OnVScroll.
但是在任何事件中,更新滾動條的位置都是程序員的事情,滾動條自己不會干.
小技巧:比如有時忽略"拖動滾動條"消息SB_THUMBTRACK,
?????? 而只管"釋放滾動條"SB_THUMBPOSITION
十五.ScrollWindow(x,y)://向右滾動x個像素,向下滾動y個像素
數(shù)據(jù)快速拷貝滾動滾動,空出來的地方激活OnPaint去重畫
待續(xù)……
posted on 2006-11-15 13:56
哈哈 閱讀(2270)
評論(2) 編輯 收藏 引用