1. 程式人生 > >vc++學習筆記—11月14日

vc++學習筆記—11月14日

第三章 應用程式框架

控制代碼
HWND 視窗控制代碼
HBITMAP 點陣圖控制代碼
HICON 圖示控制代碼
HMENU 選單控制代碼
HFILE 檔案控制代碼
HINSTANCE 當前例項控制代碼
HGLOBAL 全域性記憶體物件控制代碼
HDC 裝置環境控制代碼
HCURSOR 游標控制代碼
HFONT 字型控制代碼
HPEN 畫筆控制代碼
HBRUSH 畫刷控制代碼
HLOCAL 區域性記憶體物件控制代碼

旁註:
char是char[]的首地址
同樣 main是main()的首地址

訊息
  訊息號: 事先定義好的訊息標識
  wParam: 字引數 訊息附加資訊
  lParam:長位元組引數 訊息附加資訊
訊息迴圈:
常見的:
 while(GetMessage(&Msg,NULL,0,))
{
TranslatMessage(&Msg);//將訊息的虛擬鍵轉換為字元資訊 例如把

wm_keyup/wm_keydown 轉換為wm_char訊息,它不會消滅以前的舊訊息而是產生一

個新訊息

DispatchMessage(&Msg);//將訊息傳送到指定視窗,即把訊息傳遞給視窗類中的

lpfnWndProc所指向的函式名
}

視窗函式WinProc()
定義了程式對於接收到的不同訊息的響應,包含了對各種可能接受到的訊息的處

理過程。
每一個case處理一個訊息
      
當你不感興趣的訊息也不能不管,在一般的訊息回撥函式中default 都會return

defwindowproc(...)交由系統處理,否則視窗會不顯示
回撥函式的callback是用來區分_stdcall(delphi語系以及其他api的語言約定)與

_cdle(c語言的語言約定)的 不同函式 的。

初始化
 1 定義視窗類
 2 註冊視窗  RegisterClass();
 3 建立視窗  CreateWindow();
 4 視窗顯示  ShowWindow();

MFC類庫

包括CWinApp CDoucument CView CFrameWnd CDocTemplate 五大類

命令相關類 CCmdTarget  是訊息對映屬性的基類,訊息對映規定了當一個物件接

收到訊息命令時,呼叫哪個函式進行處理。

執行緒基類 CWinThread 可直接使用

應用程式類 CWinApp

視窗類 CWnd

框架視窗類 CFrameWnd

文件視窗類 CDocTemplate

winmain中lCmdline引數為 系統引數之意

視窗重畫cs_vredraw..為單獨位為1的意思如0x00001
如要去掉,可以採用style&~cs_vredraw

視窗類wndClass

旁註:HDC
HDC hdc1 建立一個hdc的變數(hdc是指跟顯示裝置相關的中間層變數,只要複製

給hdc就可以被顯示)
hdc1.getDC(指定要顯示視窗的控制代碼如hwnd);
可以用TextOut(hdc1,...)來顯示文字
用完要釋放  ReleaseDC(hwnd,hdc1)

 Class :

建構函式
它的名字就是類的名字,一般會在public中,它會在類建立的時候被呼叫,本來

用於自動給引數賦初值的函式,是類建立所必須的如果不寫,系統會預設一個

例子:
class Point
{
public:
 int x;
 int y;
/* void init()       ///////////////////////此處用於 手工賦初值的

方法,如Point s1; s1.init();//即為初始化
 {
  x=0;
  y=0;
 }*/
 Point()//////////////此就是建構函式
 {
  x=0;
  y=0;
 }
---------------
解構函式:

它的名字就是~類名字,它會在類使用完的時候呼叫,本來用於釋放類佔據的空

間的,一般也會出現在public中

例子:

class Point
{
public:
 int x;
 int y;

 
 ~Point()/// 此即為解構函式
 {
 }

---------
函式的過載

有多個名字相同 引數個數或者型別不同的函式

例如:
Point()
 {
  x=0;
  y=0;
 }
Point(int a,int b)
 {
  x=a;
  y=b;
 }
到時候那個符合引數就用那個。。自適應的。

----------------------
this指標用於指向物件,

例如:
Class Point
{
...
void output(int x,int y)
 {
  this->x=x;
  this->y=y;
 }
}
...
Point ist;

此時類中的this就是指ist
----------------
函式的繼承和派生

例如class a;
再定義b時,可採用
class b :public a
{

}
即b繼承了a類,b是a的派生
====摘自csdn
繼承和派生兩個術語的區別在於它們的主賓關係不同。  
  繼承是對於父類來說是被動的,可以描述為:父類XXX被子類XXX繼承  
   
  而派生對於父類來說是主動的。描述為:父類XXX派生子類XXX。  
   
  關於派生類和子類的區別:應該是繼承關係的層次結構的概念區別。  
  派生類可以是多餘一級的繼承關係,  
  子類是一級關係。  
  但同時也有這樣的概念:子類屬於派生類。  
   
  例如:基類A,  
              類B直接繼承於A  
              類C直接繼承於B;  
   
          那麼依據上面的說法則有:  
   
              類A派生類B,類A被類B繼承;類B派生類C,   類B被類C繼承。  
              類B是類A的子類,類C是類B的子類;  
              類B和類C都是類A的派生類。  
------------------------
多型性

就是父類的同名函式若設定為虛擬函式,則放棄父虛擬函式的型別,主要看子類。子

類有的呼叫子的,沒有的呼叫父類。
----------------------
虛擬函式

見上述函式的多型性 ,
例子:
class animal
{
public:
....
..
virtual viod breathe()//此即為虛擬函式,
 {
 }

}

若為virtual viod breathe()=0;則為純虛擬函式純虛擬函式是父類用來“留白”的

,即,子類必須定義自己的這個函式
--------------
引用

就是一種別名
例子:
int a=6;
int &b=a;
則b就是a的引用,而且b變換,a也會跟著變化,
注意引用只能在定義時候定義一次,之後不會被重複定義
用法
如果b=5,則a也會變成5

一般用法 定義函式

change(int &a,int &b0)
{...}
使用的時候change(x,y)即使把引數x和y的 本身 進行交換。。。

======================
類的一般 用法
把檔案分為cpp和h檔案
h檔案中只是宣告類的函式,不做具體定義
如 animal.h就只用寫
class animal
{
public:
animal(int heght , int weght);
viod eat();
viod sleep();
virtual viod breathe();
}
在animal.cpp中寫

animal:: animal()//注意此處不必寫函式返回值,因為建構函式沒有返回值
{
//建構函式
}
void Animal::eat()
{
}
.....

繼承animail類的fish類 定義的fish構建函式
Fish::Fish():Animal(300,400)
{
}
---------注意標頭檔案不參與編譯
--------------
::shownwindow() 表示呼叫全域性或者平臺的函式
AFX類是框架類的函式,系統把眾多類聯絡起來的全域性函式
AfxGetApp()可以獲得一個CWinApp類的指標即this
CWinApp是應用程式類

先構建 CWinApp 先構建全域性變數
然後構建winmain
afxwinmain是winmain的呼叫函式,用來完成winmain函式的功能
AfxRegisterClass註冊視窗類函式,用來使用win32風格的幾種視窗
Initapplication()是用來初始化管理用函式
InitInstance()呼叫子類的初始化函式

this 指向是CxxxApp xxxApp 定義中的xxxApp 是應用程式類

PreCreatWindows()函式中先註冊視窗AfxDeferRegisterClass

()//AfxEndDeferRegisterClass判斷有沒有註冊,如果沒有就註冊引數
可以通過其引數 CREATESTRUCT& cs改變有無最大化等視窗型別
主視窗的建立,是在ProcessShellComand(cmdinfo)實現的
::CreatWindowEx(...)建立視窗,其返回值是個控制代碼
m_pMainWnd是指向cMainFrame的指標
CWinThread::Run()完成了訊息迴圈

注意wndcls.lpfnWndProc=DefWindowProc並非單純把訊息交給訊息處理函式,所

謂的Defxxxx而是做了訊息對映,所以此處該處理函式是沒有相應的。--leon註解

單文件程式的子視窗是cxxxxview類
LPCTSTR 常量字串

CxxxDOC 文件類
在C++中,結構體也是一種特殊的類

MFC和WIN32 建立視窗方法的區別和聯絡


 WNDCLASS wndcls;
 wndcls.cbClsExtra=0;
 wndcls.cbWndExtra=0;
 ......
 RegisterClass(&wndcls);

 CWnd wnd;//wnd並不是視窗,視窗銷燬時之銷燬了控制代碼為空,但是成員

函式仍可以用,但是如果wnd銷燬,則視窗銷燬
 wnd.CreateEx(...);//hwnd 內部傳遞並沒有外漏
 wnd.ShowWindow(SW_SHOWNORMAL);
 wnd.UpdateWindow();
|WIN32----------------------------------------------------------------

--個MFC
v HWND hwnd;
 hwnd=CreateWindowEx();
 ::ShowWindow(hwnd,SW_SHOWNORMAL);
 ::UpdateWindow(hwnd);

 ......

CButton::Create(LPSTSTR按鍵的文字,風格,大小和位置,父視窗,ID)
例子 : CButton btn;//加到class中的private中
呼叫
        btn.Create("test",WS_Child|BS_PUSHBUTTON,CRect(0,0,1,1),this,

ID123);
        btn.ShowWindow。。。
小鎖 private ,鑰匙protect ,什麼都沒有就是public
得到父視窗指標HWND GetParent();


----------------------------------------------------------------------

--------------------
----------------------------------------------------------------------

--------------------
文字編輯
建立插入符
CreateSolidCaret(20寬度,100高度);
ShowCaret();
//Ascent 升序高度,即h角到頭的高度
//Descent 降序高度 ,即G從頭到腳的高度
獲得字型高度
CCilentDC dc(this);
TEXTMETRIC tm;//注意此處的tm為隨意命名
dc.GetTextMetrics(&tm);
tm.tmhight 就是他的高度
這個用法很有用!

點陣圖插入符

CBitmap bitmap;//如果要用,最好放到類的private中,以免析構的時候被幹掉
bitmap.LoadBitmap(IDC_XXX);//CString也有類似的讀取資源的方法就是

LoadString//可以在資源的String Table中新增
CreateCaret(&bitmap);
ShowCaret();


View 類, 中的OnDraw 視窗重繪時經歷

CDC類定義的*pDC
CString str("Hello World!");
文字輸出:
pDC->TextOut(50,50,str);//50,50就是文字的左上角的座標

CSize 中的成員x y 分別是長度和高度

獲得字串的高度
CSize sz=pDC->GetTextExtent(str);

畫矩形 pDC->Rectangle(x0,y0,x1,y1);
cstring.GetLength()取長度
 //////////////////////////////
此函式實在CxxxView類中右擊選擇 Add Windowsmessage Hander 從而增添的訊息

截獲WM_CHAR訊息做的響應
void CTextView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 CClientDC dc(this);
 CFont font;
 font.CreatePointFont(300,"華文行楷",NULL);
 CFont *pOldFont=dc.SelectObject(&font);
 TEXTMETRIC tm;
 dc.GetTextMetrics(&tm);
 if(0x0d==nChar)//回車
 {
  m_strLine.Empty();
  m_ptOrigin.y+=tm.tmHeight;
 }
 else if(0x08==nChar)// 退格
 {
  COLORREF clr=dc.SetTextColor(dc.GetBkColor());
  dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);
  m_strLine=m_strLine.Left(m_strLine.GetLength()-1);
  dc.SetTextColor(clr);
 }
 else
 {
  m_strLine+=nChar;
 }
 CSize sz=dc.GetTextExtent(m_strLine);

 CPoint pt;
 pt.x=m_ptOrigin.x+sz.cx;
 pt.y=m_ptOrigin.y;

 SetCaretPos(pt);
 dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);

 dc.SelectObject(pOldFont);

 CView::OnChar(nChar, nRepCnt, nFlags);
}

CTextView::OnTimer(UINT nIDEvent) //文字追隨變色的Timer元件程式碼
{
 // TODO: Add your message handler code here and/or call default
 m_nWidth+=5;

 CClientDC dc(this);
 TEXTMETRIC tm;
 dc.GetTextMetrics(&tm);
 CRect rect;
 rect.left=0;
 rect.top=200;
 rect.right=m_nWidth;
 rect.bottom=rect.top+tm.tmHeight;

 dc.SetTextColor(RGB(255,0,0));
 CString str;
 str.LoadString(IDS_WEIXIN);
 dc.DrawText(str,rect,DT_LEFT);

 rect.top=150;
 rect.bottom=rect.top+tm.tmHeight;
 dc.DrawText(str,rect,DT_RIGHT);

 CSize sz=dc.GetTextExtent(str);
 if(m_nWidth>sz.cx)
 {
  m_nWidth=0;
  dc.SetTextColor(RGB(0,255,0));
  dc.TextOut(0,200,str);
 }
///////////////////////////////////////////////////////////////////////

/
 CView::OnTimer(nIDEvent);
}

///////////////////////////////////////
=======================================================================

====
關於訊息的三點:

1.類的標頭檔案中註釋巨集之間(//{{AFX_VIRTUAL(xxx)。。。//}}AFX_VIRTUAL)
2.原始檔的
BEGIN_MESSAGE_MAP(CXXXView, CView)
 //{{AFX_MSG_MAP(CXXXView)
這個位置
//}}AFX_MSG_MAP
3.原始檔的viod cXXxx::onXXX ()自定義的處理函式部分

MFC的訊息對映(非WIN32的訊息迴圈處理)

WIN32的程式設計中 訊息處理是把所有的訊息都做成虛擬函式,只要定了子類就可以進

行相應
這樣會造成記憶體資源的浪費

後臺有個控制代碼和c++類物件指標的對映表 ,有訊息發生後,後臺會把訊息以及相

關的視窗對應起來,通過該視窗的控制代碼找到C++物件的指標,然後將指標傳給基類

,基類通過訊息迴圈呼叫了WindowProc,而WindowProc本身是虛擬函式,在具體子

類定義次函式時必然會呼叫了OnWinMsg(訊息路由部分),OnWinMsg會查詢 1和2

從而判斷有沒有該訊息響應的生命,最後找到3 進行處理。--孫鑫先生原文

我理解MFC的訊息對映過程是這樣的:

訊息產生了-》啟用那個後臺的對映表-》查詢響應視窗的控制代碼-》WindowProc-》

OnWinMsg-》看看1,2部分有無定義,有的話就—》3 ;、、、、沒有就算了(交

由基類處理) :)

view中無須用函式獲得本視窗控制代碼,直接用m_hWnd就是本視窗控制代碼

畫線函式及其用法:

win32用法

HDC hdc;
hdc=::GetDC(m_hWnd);//平臺sdk的函式需要加::
MoveToEx(hdc,m_old.x,m_old.y,NULL);//先把滑鼠移動到最初的點
LineTo(hdc,point.x,point.y);//畫函式
::ReleaseDC(m_hWnd,hdc);//用完釋放dc

MFC用法

CDC *pDC=GetDC();
pDC->MoveTo(m_old);
pDC->LineTo(point);
ReleaseDC(pDC);
註釋同上


更快的MFC(自動會GetDC和ReleaseDC)

//CClientDC dc(GetParent());//若用此法,可以在工具欄上畫,即目標是整個

框架,但不包括非客戶區域即標題欄和選單。
CClientDC dc(this);//注意此函式需要的是一個CWnd的指標,而不是hwnd,hwnd

只是cwnd的一個變數可以用cwnd->hwnd 來呼叫
dc.Moveto(m_old);
dc.LineTO(ponit);

第四種方法,CWindowDC(也自動會GetDC和ReleaseDC)

CWindowDC dc(this);//若用GetParent可以全窗畫
dc.MoveTo(m_old);
dc.LineTo(ponit);

桌面本身就是視窗!
獲取桌面視窗的控制代碼: GetDesktopWindow()可以獲取一個CWnd;

注意,此處若用CWnd::的就是獲取CWnd類的指標
若用sdk的即::類的就是獲取這個視窗的控制代碼!

CPen畫筆類
CPen pen(筆形,寬度,RGB顏色);
需要選入裝置描述表中!!
應採用SelectObject可以選擇pPen,pBrush,pFont,pBitmap(使用時需要加& 如

&pen,其返回值也是指標,需要用 *pen接)
其返回值是先前一個狀態的裝置,比如定義了新畫筆,那麼返回值就是舊畫筆。

CBrush畫刷類

顏色畫刷
CBrush brush(RGB(255,0,0));
CClientDC dc(this);
dc.FillRect(CRect(m_old,point),&brush);//填充
//畫紅色矩形

點陣圖畫刷

CBitmap bitmap;
bitmap.LoadBitmap(IDB_XXXX);
CBrush brush(&bitmap);
CClientDC dc(this);
dc.FillRect(CRect(m_old,point),&brush);//填充


畫矩形最快的方法:
dc.Rectangle(CRect(m_old,point));


透明畫刷方法:

CBrush:*pB=CBrush::FromHandle((HBURSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pB);
dc.Rectangle....
---------------------
Class p
{
public:
       void a()
       {}
       static void b()
』//靜態使用成員函式可以在任何地方寫 
如, 靜態環境不能呼叫非靜態(沒有static定義)的成員變數,

非靜態的可以引用靜態引數

靜態的必須初始化!!即在定義前就要做好!

p point;
p:b();就可以


        {}
}
==============================================
ss選單:

新增選單命令響應函式的四大檔案篇
 
MainFrame
第三優先順序
App
第四優先順序
Doc
第二優先順序
View
最高優先順序

個級別都是如果有函式,就不再允許別的類相應

-----------

訊息分類

標準訊息:
它是CWnd派生的類,它派生的類中都可以接受到這個訊息
除了WM_COMMAND外,所有已WM開頭的訊息

命令訊息
選單,快捷鍵,工具欄按鈕的訊息
都是以WM_COMMAND呈現,要區分 需要選單項的ID號碼
CCmdTarget(CWnd的父類)派生的類都可以接受這類訊息

通告訊息
有控制元件產生的訊息,按鍵的單擊,區分需要ID。。。
也是以WM_COMMAND呈現
CCmdTarget(CWnd的父類)派生的類都可以接受這類訊息

CWnd類可以接受所有的訊息,但是CCmdTarget只能接受後兩者

命令訊息的路由:                                     
AfxWndProc->AfxCallWandProc->WindowProc->OnWndMsg  ->.1 OnNotify(通告消

息)  ->OnCmdMsg   
                                                     .2 OnCommand(命令

訊息)

標記選單——帶對勾的那種
實現方法:
在相應函式處加入OnCreate中
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_按鍵,

MF_BYCOMMAND|MF_CHECKED);//MF_UNCHECKED
0 代表是第幾個子選單
GetMenu是CWnd的一個成員函式,它返回一個指向整個選單欄的指標
而GetSubMenu只是返回子選單的指標
CheckMenuItem是在選單中放置或者取消一個標記

注意如果用索引法,一定能夠要計算分割欄!

設定預設選單(字型變粗)
GetMenu()->GetSubMenu(0)->SetDefaultItem(ID);
一個子菜單隻能有一個預設選單,即最後一次命名的。

設定圖片選單
SetMenuItemBitmaps
可以有連個點陣圖,選中一個位圖,沒選中一個位圖。
CBitmap cc;
cc.loadbitmap(圖片的ID);
SetMenuItemBitmaps(ID_FILE_OPEN,MF_BYCOMMAND,&m_cbp,&m_cbp);

按鍵變灰色的函式:GetMenu()->GetSubMenu(0)->EnableMenuItem(ID,

MF_BYCOMMAND/MF_DISABLE|MF_GRAYED);需要在mainframe的建構函式中加

m_bAutoMenuEnable=0;


GetSystemMetrics();//獲得系統引數,詳情請參考msdn可以查到很多有用的資料
移走選單 : SetMenu(NULL);
回覆選單:
CMenu menu;
menu.LoadMenu(選單的ID);
SetMenu(&menu);
1.10
CMenu類