OnEraseBkgnd 的一些理解【轉】
MFC這個架構不搞清楚其中的來龍去脈,總有你鬱悶的時候……
Q: OnEraseBkgnd函數中返回TRUE或FALSE有什麼區別?
A:
WM_ERASEBKGND
Return Values
An application should return nonzero if it erases the background; otherwise, it should return zero.
A:true表示已處理背景重新整理,false表示需要在OnPaint裡處理
Q:在OnEraseBkgnd中繪製對話方塊的背景圖片和在OnPaint中繪製對話方塊的背景圖片由什麼區別,另外OnEraseBkgnd和CtlColor有什麼區別?
A:
OnEraseBkgnd是在視窗大小發生改變等情況下發生的,它將繪製視窗背景;而OnCtlColor是當視窗的控制項需要繪製時發生的,它將繪製視窗的控制項。
A:
OnEraseBkgnd :在視窗背景需要重繪時調用.
OnPaint : 此時OnEraseBkgnd已經調用過了,所以在此響應函數體內對背景進行的操作將覆蓋OnEraseBkgnd中所做的操作.
OnCtlColor : 有於在視窗將要被(第一次)繪製時響應,子視窗可以通過發關WM_CTLCOLOR請求父視窗傳來一個HBRUSH.
MFC應用程式中處理訊息的順序
1.AfxWndProc() 該函數負責接收訊息,找到訊息所屬的CWnd對象,然後調用AfxCallWndProc
2.AfxCallWndProc() 該函數負責儲存訊息(儲存的內容主要是訊息標識符和訊息參數)供應用程式以後使用,然後調用WindowProc()函數
3.WindowProc() 該函數負責發送訊息到OnWndMsg()函數,如果未被處理,則調用DefWindowProc()函數
4.OnWndMsg() 該函數的功能首先按位元組對訊息進行排序,對於WM_COMMAND訊息,調用OnCommand()訊息響應函數,對於WM_NOTIFY訊息調用OnNotify()訊息響應函數。任何被遺漏的訊息將是一個視窗訊息。OnWndMsg()函數搜尋類的訊息映像,以找到一個能處理任何視窗訊息的處理函數。如果OnWndMsg()函數不能找到這樣的處理函數的話,則把訊息返回到WindowProc()函數,由它將訊息發送給DefWindowProc()函數
5.OnCommand() 該函數查看這是不是一個控制項通知(lParam參數不為NULL,如果lParam參數為空白的話,說明該訊息不是控制項通知),如果它是,OnCommand()函數會試圖將訊息映射到製造通知的控制項;如果他不是一個控制項通知(或者如果控制項拒絕映射的訊息)OnCommand()就會調用OnCmdMsg()函數
6.OnCmdMsg() 根據接收訊息的類,OnCmdMsg()函數將在一個稱為命令傳遞(Command Routing)的過程中潛在的傳遞命令訊息和控制項通知。例如:如果擁有該視窗的類是一個架構類,則命令和通知訊息也被傳遞到視圖和文檔類,並為該類尋找一個訊息處理函數
MFC應用程式建立視窗的過程
1.PreCreateWindow() 該函數是一個重載函數,在視窗被建立前,可以在該重載函數中改變建立參數(可以設定視窗風格等等)
2.PreSubclassWindow() 這也是一個重載函數,允許首先子分類一個視窗
3.OnGetMinMaxInfo() 該函數為訊息響應函數,響應的是WM_GETMINMAXINFO訊息,允許設定視窗的最大或者最小尺寸
4.OnNcCreate() 該函數也是一個訊息響應函數,響應WM_NCCREATE訊息,發送訊息以告訴視窗的客戶區即將被建立
5.OnNcCalcSize() 該函數也是訊息響應函數,響應WM_NCCALCSIZE訊息,作用是允許改變視窗客戶區大小
6.OnCreate() 該函數也是一個訊息響應函數,響應WM_CREATE訊息,發送訊息告訴一個視窗已經被建立
7.OnSize() 該函數也是一個訊息響應函數,響應WM_SIZE訊息,發送該訊息以告訴該視窗大小已經發生變化
8.OnMove() 訊息響應函數,響應WM_MOVE訊息,發送此訊息說明視窗在移動
9.OnChildNotify() 該函數為重載函數,作為部分訊息映射被調用,告訴父視窗即將被告知一個視窗剛剛被建立
MFC應用程式關閉視窗的順序(非模態視窗)
1.OnClose() 訊息響應函數,響應視窗的WM_CLOSE訊息,當關閉按鈕被單擊的時候發送此訊息
2.OnDestroy() 訊息響應函數,響應視窗的WM_DESTROY訊息,當一個視窗將被銷毀時,發送此訊息
3.OnNcDestroy() 訊息響應函數,響應視窗的WM_NCDESTROY訊息,當一個視窗被銷毀後發送此訊息
4.PostNcDestroy() 重載函數,作為處理OnNcDestroy()函數的最後動作,被CWnd調用
MFC應用程式中開啟強制回應對話方塊的函數調用順序
1.DoModal() 重載函數,重載DoModal()成員函數
2.PreSubclassWindow() 重載函數,允許首先子分類一個視窗
3.OnCreate() 訊息響應函數,響應WM_CREATE訊息,發送此訊息以告訴一個視窗已經被建立
4.OnSize() 訊息響應函數,響應WM_SIZE訊息,發送此訊息以告訴視窗大小發生變化
5.OnMove() 訊息響應函數,響應WM_MOVE訊息,發送此訊息,以告訴視窗正在移動
6.OnSetFont() 訊息響應函數,響應WM_SETFONT訊息,發送此訊息,以允許改變對話方塊中控制項的字型
7.OnInitDialog() 訊息響應函數,響應WM_INITDIALOG訊息,發送此訊息以允許初始化對話方塊中的控制項,或者是建立新控制項
8.OnShowWindow() 訊息響應函數,響應WM_SHOWWINDOW訊息,該函數被ShowWindow()函數調用
9.OnCtlColor() 訊息響應函數,響應WM_CTLCOLOR訊息,被父視窗發送已改變對話方塊或對話方塊上面控制項的顏色
10. OnChildNotify() 重載函數,作為WM_CTLCOLOR訊息的結果發送
MFC應用程式中關閉強制回應對話方塊的順序
1.OnClose() 訊息響應函數,響應WM_CLOSE訊息,當"關閉"按鈕被單擊的時候,該函數被調用
2.OnKillFocus() 訊息響應函數,響應WM_KILLFOCUS訊息,當一個視窗即將失去鍵盤輸入焦點以前被發送
3.OnDestroy() 訊息響應函數,響應WM_DESTROY訊息,當一個視窗即將被銷毀時,被發送
4.OnNcDestroy() 訊息響應函數,響應WM_NCDESTROY訊息,當一個視窗被銷毀以後被發送
5.PostNcDestroy() 重載函數,作為處理OnNcDestroy()函數的最後動作被CWnd調用
開啟無強制回應對話方塊的順序
1.PreSubclassWindow() 重載函數,允許使用者首先子分類一個視窗
2.OnCreate() 訊息響應函數,響應WM_CREATE訊息,發送此訊息以告訴一個視窗已經被建立
3.OnSize() 訊息響應函數,響應WM_SIZE訊息,發送此訊息以告訴視窗大小發生變化
4.OnMove() 訊息響應函數,響應WM_MOVE訊息,發送此訊息以告訴視窗正在移動
5.OnSetFont() 訊息響應函數,響應WM_SETFONT訊息,發送此訊息以允許改變對話方塊中控制項的字型
以上這些的執行都是按給定的順序執行!
只有清楚的瞭解應用程式的執行順序,才能在編寫代碼的時候知道,在什麼時候應該執行什麼,以及在什麼地方該處理什麼!
這隻是本人總結的一點小小的經驗,希望能對MFC的初學者有所協助!
| 原作者:不詳 源出處:百度 發行者:施昌權 發布類型:轉載 發布日期:2008-09-24 |
| 清單控制項可以看作是功能增強ListBox,它提供了四種風格,而且可以同時顯示一列的多中屬性值。MFC中使用CListCtrl類來封裝清單控制項的各種操作。 通過調用BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );建立一個視窗,dwStyle中可以使用以下一些清單控制項的專用風格:
- LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT 這四種風格決定控制項的外觀,同時只可以選擇其中一種,分別對應:大表徵圖顯示,
小表徵圖顯示,列表顯示,詳細報表顯示
- LVS_EDITLABELS 結點的顯示字元可以被編輯,對於報表風格來講可編輯的只為第一列。
- LVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點
- LVS_SINGLESEL 同時只能選中列表中一項
首先你需要設定清單控制項所使用的ImageList,如果你使用大表徵圖顯示風格,你就需要以如下形式調用: CImageList* SetImageList( CImageList* pImageList, LVSIL_NORMAL); 如果使用其它三種風格顯示而不想顯示表徵圖你可以不進行任何設定,否則需要以如下形式調用: CImageList* SetImageList( CImageList* pImageList, LVSIL_SMALL); 通過調用int InsertItem( int nItem, LPCTSTR lpszItem );可以在列碸丶 衝Item指明位置插入一項,lpszItem為顯示字元。除LVS_REPORT風格外其他三種風格都只需要直接調用InsertItem就可以了,但如果使用報表風格就必須先設定清單控制項中的列資訊。 通過調用int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat , int nWidth, int nSubItem);可以插入列。iCol為列的位置,從零開始, lpszColumnHeading為顯示的列名,nFormat為顯示對齊,nWidth為顯示寬度,nSubItem為分配給該列的列索引。 在有多列的清單控制項中就需要為每一項指明其在每一列中的顯示字元,通過調用BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText );可以設定每列的顯示字元。nItem為設定的項的位置,nSubItem為列位置,lpszText為顯示字元。下面的代碼示範了如何設定多列並插入資料: m_list.SetImageList(&m_listSmall,LVSIL_SMALL);//設定ImageList m_list.InsertColumn(0,"Col 1",LVCFMT_LEFT,300,0);//設定列 m_list.InsertColumn(1,"Col 2",LVCFMT_LEFT,300,1); m_list.InsertColumn(2,"Col 3",LVCFMT_LEFT,300,2); m_list.InsertItem(0,"Item 1_1");//插入行 m_list.SetItemText(0,1,"Item 1_2");//設定該行的不同列的顯示字元 m_list.SetItemText(0,2,"Item 1_3"); 此外CListCtrl還提供了一些函數用於得到/修改控制項的狀態。 COLORREF GetTextColor( )/BOOL SetTextColor( COLORREF cr );用於得到/設定顯示的字元顏色。 COLORREF GetTextBkColor( )/BOOL SetTextBkColor( COLORREF cr );用於得到/設定顯示的背景顏色。 void SetItemCount( int iCount );用於得到添加進列表中項的數量。 BOOL DeleteItem(int nItem);用於刪除某一項, BOOL DeleteAllItems( );將刪除所有項。 BOOL SetBkImage(HBITMAP hbm, BOOL fTile , int xOffsetPercent, int yOffsetPercent);用於設定背景位元影像。 CString GetItemText( int nItem, int nSubItem );用於得到某項的顯示字元。 清單控制項的訊息映射同樣使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode為通知代碼,id為產生該訊息的視窗ID,memberFxn為處理函數,函數的原型如同void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR為一資料結構,在具體使用時需要轉換成其他類型的結構。對於清單控制項可能取值和對應的資料結構為:
LVN_BEGINLABELEDIT 在開始某項編輯字元時發送,所用結構:NMLVDISPINFO
LVN_ENDLABELEDIT 在結束某項編輯字元時發送,所用結構:NMLVDISPINFO
LVN_GETDISPINFO 在需要得到某項資訊時發送,(如得到某項的顯示字元)所用結構:NMLVDISPINFO
關於ON_NOTIFY有很多內容,將在以後的內容中進行詳細講解。 關於動態提供結點所顯示的字元:首先你在項時需要指明lpszItem參數為:LPSTR_TEXTCALLBACK。在控制項顯示該結點時會通過發送 TVN_GETDISPINFO來取得所需要的字元,在處理該訊息時先將參數pNMHDR轉換為LPNMLVDISPINFO,然後填充其中item.pszText。通過item中的 iItem,iSubItem可以知道當前顯示的為那一項。下面的代碼示範了這種方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加結點 m_list.InsertItem(LPSTR_TEXTCALLBACK,...) m_list.InsertItem(LPSTR_TEXTCALLBACK,...) //處理訊息 void CParentWnd::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; pLVDI->item.pszText=szOut[pTVDI->item.iItem];//通過iItem得到需要顯示的字元在數組中的位置 *pResult = 0; } 關於編輯某項的顯示字元:(在報表風格中只對第一列有效)首先需要設定清單控制項的LVS_EDITLABELS風格,在開始編輯時該控制項將會發送 LVN_BEGINLABELEDIT,你可以通過在處理函數中返回TRUE來取消接下來的編輯,在編輯完成後會發送LVN_ENDLABELEDIT,在處理該訊息時需要將 參數pNMHDR轉換為LPNMLVDISPINFO,然後通過其中的item.pszText得到編輯後的字元,並重設顯示字元。如果編輯在中途中取消該變數為NULL。 下面的代碼說明如何處理這些訊息: //處理訊息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.iItem==0);//判斷是否取消該操作 *pResult = 1; else *pResult = 0; } //處理訊息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.pszText==NULL);//判斷是否已經取消取消編輯 m_list.SetItemText(pLVDI->item.iItem,0,pLVDI->pszText);//重設顯示字元 *pResult = 0; } 上面講述的方法所進行的訊息映射必須在父視窗中進行(同樣WM_NOTIFY的所有訊息都需要在父視窗中處理)。 如何得到當前選中項位置:在清單控制項中沒有一個類似於ListBox中GetCurSel()的函數, 但是可以通過調用 GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);得到選中項位置。 |
Visual C++中實現雙緩衝的基本原理
雙緩衝的原理可以這樣形象的理解:把電腦螢幕看作一塊黑板。首先我們在記憶體環境中建立一個“虛擬“的黑板,然後在這塊黑板上繪製複雜的圖形,等圖形全部繪製完畢的時候,再一次性的把記憶體中繪製好的圖形“拷貝”到另一塊黑板(螢幕)上。採取這種方法可以提高繪圖速度,極大的改善繪圖效果。能理解到這一層,工作便變得簡單了,只要四步就可以搞定了,看下面代碼:
例如在OnDraw()函數中可以如下所述實現雙緩衝,其主要步驟分為四步:
以下為引用的內容: CPen Pen; Pen.CreatePen(PS_INSIDEFRAME,1,RGB(225,225,0)); CBrush Brush; Brush.CreateSolidBrush(RGB(225,225,0)); CDC dcMem; CBitmap bm; CRect rc; GetClientRect(&rc); // Step 1:為螢幕DC建立相容的記憶體DC :CreateCompatibleDC() dcMem.CreateCompatibleDC(pDC); // Step 2:建立位元影像:CreateCompatibleBitmap() bm.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height()); // Step 3:把位元影像選入裝置環境:SelectObject(),可以理解為選擇畫布 dcMem.SelectObject(&bm); dcMem.SelectObject(Pen); dcMem.SelectObject(Brush); dcMem.Ellipse(0,0,50,50);//畫橢圓 // Step 4:把繪製好的圖形“拷貝“到螢幕上:BitBlt() pDC->BitBlt(0,0,rc.Width(),rc.Height(),&dcMem,0,0,SRCCOPY); dcMem.DeleteDC(); bm.DeleteObject(); |
這樣便實現了雙緩衝,通過這個方法可以防止在VC中畫圖時出現螢幕閃爍的情況。