天天看點

MFC經驗 GDI和 GDI+實作雙緩存

MFC架構各部分指針擷取方式:

  記住,是擷取指針

MFC經驗 GDI和 GDI+實作雙緩存

MFC消息流程圖:

MFC經驗 GDI和 GDI+實作雙緩存

string CString char* 的互相轉換:

    string 轉 CString     CString.Format("%s", string.c_str());  //用c_str()比data()好     char 轉 CString     CString.Format("%s", char*);  // 可以直接給CString指派 ,不要用Format        char* 轉 string     string s(char *);          CString 轉 string     string s(CString.GetBuffer());  //測試顯示 可以直接用CString 賦給string , //因CString 有operator LPCTSTR 不拷貝 隻傳回指針

  string 轉 char *     char *p = string.c_str();       CString 轉char *     CString.GetBuffer();

   可直接指派,不用轉換,因為LPCTSTR在CString中被重載了.

 一條重要經驗:

 如果我們的類/結構體中有CArray(或CList等其他的派生自CObject類,即很多的控件類)的成員變量,我們最好添加上一個public類型的operator=運算賦重載函數,否則編譯器報錯 error C2248: “CObject::operator =”: 無法通路 private 成員(在“CObject”類中聲明)

 建立全屏視窗:

    win.CreateEx(0, szProgram, szProgram,               WS_POPUP,               0, 0,               GetSystemMetrics( SM_CXSCREEN ),               GetSystemMetrics( SM_CYSCREEN ),               NULL, NULL, hInst);        

目錄對話框SHBrowseForFolder:

CString sFolderPath;  BROWSEINFO bi;  TCHAR Buffer[MAX_PATH];  //初始化入口參數bi開始  bi.hwndOwner = NULL;  bi.pidlRoot = NULL;  bi.pszDisplayName = Buffer;//此參數如為NULL則不能顯示對話框  bi.lpszTitle = _T("選擇路徑");  bi.ulFlags = BIF_RETURNONLYFSDIRS;  bi.lpfn = NULL;  bi.iImage = 0;  //初始化入口參數bi結束  LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//調用顯示選擇對話框  if(pIDList)  {   SHGetPathFromIDList(pIDList, Buffer);   //取得檔案夾路徑到Buffer裡   sFolderPath = Buffer;//将路徑儲存在一個CString對象裡  }

CTreeCtrl使用圖示:

一種最簡單的方法: 1.在資料總管中建立ICON;如:IDI_ICON_DEVICE,IDI_ICON_DEVICE_SEL;  2.在CTreeCtrlEx中增加成員變量:CImageList m_ImageList;  3.在void CLocTreeView::OnInitialUpdate()中增加如下代碼: m_ImageList.Create(16,16,ILC_COLOR32,2,2);  m_ImageList.Add( AfxGetApp()->LoadIcon(IDI_ICON_DEVICE));  m_ImageList.Add( AfxGetApp()->LoadIcon(IDI_ICON_DEVICE_SEL));  m_oTreeCtrl.SetImageList(&m_ImageList,TVSIL_NORMAL); 4.在向樹中插入Item時指定這個Item對應的ICON位圖,代碼如下:       HTREEITEM hCurItem = m_oTreeCtrl.InsertItem( "ItemContent",0,1, hItemParent);//參數中0,1為icon的索引 其中的0指添加好後的圖檔為IDI_ICON_DEVICE,選中後顯示的圖檔為:IDI_ICON_DEVICE_SEL;

CTreeCtrl使用圖示 另:

建立一個CTreeCtrl控制成員 m_Tree;

使用圖示的方法:

Step1:   //load icon

HICON icon[4];

Icon[0]=AfxGetApp()->LoadIcon(IDI_ICON1);

Icon[1]=AfxGetApp()->LoadIcon(IDI_ICON2);

Step2: //建立CImageList

CImageList *ImageList4Tree = new CImageList;

ImageList4Tree.Create(16,16,0,4,4); //16,16為圖示分辯率,4,4為該list最多能容納的圖示數

For(int i=0;i<2;i++)

{

       ImageList4Tree->Add(Icon[i]); //讀入圖示

}

Step3: //使用建立好的CImageList

m_Tree.SetImageList(ImageList4Tree);

Step4: //在添加項的同時選用圖示

m_Tree.InsertItem(itemName,0,1,parentItem); //第2個參數是item在添加好後的圖示   //第3個參數為item在被選中後的圖示

樹一次展開所有結點:

主要思想是遞歸。

<code>01</code>

<code>void</code> <code>CMenuCreatDlg::OnMENUITEMexpandtree() </code><code>//展開所有節點</code>

<code>02</code>

<code>{</code>

<code>03</code>

<code>// TODO: Add your command handler code here</code>

<code>04</code>

<code>MyExpandTree(m_tree.GetRootItem());</code>

<code>05</code>

<code>}</code>

<code>06</code>

<code>void</code> <code>CMenuCreatDlg::MyExpandTree(HTREEITEM hTreeItem)</code>

<code>07</code>

<code>08</code>

<code>if</code><code>(!m_tree.ItemHasChildren(hTreeItem))</code>

<code>09</code>

<code>10</code>

<code>return</code><code>;</code>

<code>11</code>

<code>12</code>

<code>HTREEITEM hNextItem = m_tree.GetChildItem(hTreeItem);</code>

<code>13</code>

<code>while</code> <code>(hNextItem != NULL)</code>

<code>14</code>

<code>15</code>

<code>MyExpandTree(hNextItem);</code>

<code>16</code>

<code>hNextItem = m_tree.GetNextItem(hNextItem, TVGN_NEXT);</code>

<code>17</code>

<code>18</code>

<code>m_tree.Expand(hTreeItem,TVE_EXPAND);</code>

<code>19</code>

<code>1</code>

<code>&lt;p&gt; &lt;/p&gt;</code>

<code>2</code>

<code>&lt;p&gt; &lt;/p&gt;&lt;p&gt;</code><code>void</code> <code>ExpandBranch(HTREEITEM hItem,CTreeCtrl&amp; tree,&lt;br&gt;                 </code><code>BOOL</code> <code>bExpand </code><code>/*=TRUE*/</code><code>)&lt;/p&gt;&lt;p&gt;</code><code>/* bExpand =TRUE 展開所有節點,否則為折疊*/</code><code>&lt;br&gt;{&lt;br&gt;   </code><code>if</code> <code>(tree.ItemHasChildren(hItem))&lt;br&gt;   {&lt;br&gt;      tree.Expand(hItem,bExpand?TVE_EXPAND:TVE_COLLAPSE);&lt;br&gt;      hItem=tree.GetChildItem(hItem);&lt;br&gt;      </code><code>do</code> <code>&lt;br&gt;      {&lt;br&gt;         ExpandBranch(hItem,tree);&lt;br&gt;      } </code><code>while</code><code>((hItem=tree.GetNextSiblingItem(hItem))!=NULL);&lt;br&gt;   }&lt;br&gt;}&lt;br&gt;&lt;/p&gt;&lt;p&gt;</code>

<code>3</code>

<code>&lt;/p&gt;&lt;strong&gt; 給樹控件添加右鍵菜單:&lt;/strong&gt;</code>

<code>4</code>

<code>&lt;p&gt; &lt;/p&gt;&lt;p&gt;首先定義右鍵消息函數:&lt;/p&gt;&lt;p&gt;    afx_msg  </code><code>void</code>  <code>OnRBClick(NMHDR* pNMHDR, </code><code>LRESULT</code><code>* pResult);    &lt;/p&gt;&lt;p&gt;    然後在消息循環中定義消息對應關系:&lt;/p&gt;&lt;p&gt;    ON_NOTIFY(NM_RCLICK, ID_TREECTRL, OnRbClick)&lt;/p&gt;&lt;p&gt;    接着定義消息函數内容:&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;</code><code>void</code> <code>CXMLEditorDlg::OnNMRClickTree(NMHDR *pNMHDR, </code><code>LRESULT</code> <code>*pResult)&lt;br&gt;{&lt;br&gt; </code><code>// TODO: 在此添加控件通知處理程式代碼&lt;br&gt; *pResult = 0;&lt;/p&gt;&lt;p&gt; CPoint point;&lt;br&gt; GetCursorPos(&amp;point);&lt;br&gt; CPoint pointInTree = point;&lt;br&gt; m_TreeCtrl.ScreenToClient(&amp;pointInTree);&lt;br&gt; UINT flag = TVHT_ONITEM;&lt;br&gt; HTREEITEM hItem = m_TreeCtrl.HitTest(pointInTree, &amp;flag);&lt;/p&gt;&lt;p&gt; m_hSelectedItem = hItem;&lt;br&gt; if(hItem != NULL)&lt;br&gt; {&lt;br&gt;  //m_TreeCtrl.SelectItem(hItem);&lt;br&gt;  CMenu menu;&lt;br&gt;  menu.LoadMenu(IDR_TREE);&lt;br&gt;  menu.GetSubMenu(0)-&gt;TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);&lt;br&gt; }&lt;br&gt;}&lt;/p&gt;&lt;p&gt;&lt;strong&gt; vs2005導入GIF圖檔:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;用源碼編輯器打開.rc檔案.添加如下&lt;/p&gt;&lt;p&gt;IDR_EYES                GIF                     "res\\eyes.gif"&lt;br&gt;IDR_FELIX               GIF                     "res\\felix_new.gif"&lt;br&gt;IDR_TYPE                GIF                     "res\\type.gif"&lt;/p&gt;&lt;p&gt;然後 在resource.h中 添加 ID定義&lt;/p&gt;&lt;p&gt;#define IDC_HAND                        133&lt;br&gt;#define IDR_EYES                        134&lt;br&gt;#define IDR_TYPE                        137&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;下邊的也行:&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;br&gt;手工在.rc檔案裡添加&lt;br&gt;IMG1 IMAGE "res\\test.gif"&lt;/p&gt;&lt;p&gt;在load時可以這樣:&lt;br&gt;&lt;span style="color: red"&gt;hResInfo = FindResource(hInst , "IMG1", "IMAGE");&lt;/span&gt;&lt;br&gt;if (hResInfo == NULL)  &lt;br&gt;{&lt;br&gt;dwErr = GetLastError();&lt;br&gt;return FALSE;&lt;br&gt;}&lt;/p&gt;&lt;p&gt;// Load the resource&lt;br&gt;&lt;span style="color: red"&gt;hRes = LoadResource(hInst , hResInfo);&lt;/span&gt;&lt;br&gt;if (hRes == NULL)  &lt;br&gt;{&lt;br&gt;dwErr = GetLastError();&lt;br&gt;return FALSE;&lt;br&gt;}&lt;br&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;&lt;strong&gt;基于對話框程式添加菜單:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;</code>

在VC中建立一個基于對話框的MFC程式,要在其中添加菜單總共分三步:

1、首先插入一個菜單資源IDR_MENU,然後可以編輯修改菜單;

2、 然後在為對話框添加一個CMenu類型的成員變量m_Menu;

3、在OnInitDialog()中添加如下的代碼:

      m_Menu.LoadMenu(IDR_MENU);    //載入菜單       SetMenu(&amp;m_Menu);                    //顯示菜單

經過這三步以後菜單就可以顯示出來了。

菜單退出項消息映射:

 BEGIN_MESSAGE_MAP(CXMLApp, CWinApp)    ON_COMMAND(ID_HELP, &amp;CWinApp::OnHelp)    ON_COMMAND(ID_EXIT, &amp;CWinApp::OnAppExit) END_MESSAGE_MAP()

四,基于對話框程式添加工具欄:

1、添加工具欄資源ID為IDR_TOOLBAR 2、在對話框的類定義中加:  CToolBar m_ToolBar; 3、在OnInitDialog中或其它合适的消息響應中加如下代碼:

 m_ToolBar.Create(this);  m_ToolBar.LoadToolBar(IDR_TOOLBAR1);  //控件條定位  RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0); 

4、手工添加處理函數  

   afx_msg void OnBtnXXX();//消息響應函數聲明     ON_COMMAND(ID_BTN_XXX/*工具按鈕ID*/,OnBtnXXX/*函數名*/)//消息映射       void CXXXDlg::OnBtnXXX(){}//消息處理函數

RichEdit初始化,不然不會顯示(程式會沒有界面彈出來):

AfxEnableControlContainer();  //原有  AfxInitRichEdit();                 //richedit的初始化  在app類InitInstance中

對話框右上角?号圖示:

隻需要在對話框屬性上選中Context Help這個選項就OK了,把對話框顯示出來就能發現右上角的小問号按鈕。

應用程式隻有一個執行個體:

在app類的InitInstance()中添加如下代碼:

 BOOL bAlreadyRunning = FALSE;

 HANDLE hMutexOneInstance = ::CreateMutex( NULL, FALSE, _T("SnowParentWindow"));  bAlreadyRunning = ( ::GetLastError() == ERROR_ALREADY_EXISTS || ::GetLastError() == ERROR_ACCESS_DENIED);

 if(bAlreadyRunning)   return FALSE;

圖示菜單(菜單圖示)的實作:

一、單文檔的菜單圖示實作:  1、建立一個位圖資源,大小為13*13(#add暫時必須滿足這個條件,大的圖示不會顯示),假設ID為IDB_BITMAP1,畫好圖示  2、在CMainFrame中添加成員變量:CBitmap bitmap  3、在CMainFrame的OnCreate中加入:  bitmap.LoadBitmap(IDB_BITMAP1);  GetMenu()-&gt;GetSubMenu(0)-&gt;SetMenuItemBitmaps(0,MF_BYPOSITION, &amp;bitmap, &amp;bitmap);//具體哪個菜單項為圖示,可自己設定  4、編譯,實作圖示菜單。

二、多文檔的菜單圖示實作:  1、建立一個位圖資源,大小為13*13,假設ID為IDB_BITMAP1,畫好圖示  2、在CMaoyeah_comDoc(你程式中的CDocument子類)中添加成員變量:CBitmap bitmap  3、在CMaoyeah_comDoc的OnNewDocument中加入:  bitmap.LoadBitmap(IDB_BITMAP1);  CMenu *pMenu;  pMenu = CMenu::FromHandle(((CMultiDocTemplate *)m_pDocTemplate)-&gt;m_hMenuShared);  CMenu *pSubMenu = pMenu-&gt;GetSubMenu(0);  pSubMenu-&gt;SetMenuItemBitmaps(0,MF_BYPOSITION, &amp;bitmap, &amp;bitmap);  4、編譯,實作圖示菜單。

CEdit控件限定隻輸入數字:

如果在對話框上建立,可直接在style屬性裡指定為number,如果動态建立的則

設定Edit的屬性為:ES_NUMBER  比如m_SpeedEdit.ModifyStyle(0,ES_NUMBER,TRUE);

或者

 DWORD     dwStyle   =   m_SpeedEdit.GetStyle();

 dwStyle   |=   ES_NUMBER;   SetWindowLong(m_SpeedEdit.m_hWnd, GWL_STYLE, dwStyle);

在一個對話框上顯示出一條凹下去的線:

把picture控件拉成直線,設定color屬性為etched

或者選擇sunken屬性 為true

右鍵彈出菜單的實作:

通常是響應WM_CONTEXTMENU消息

void CRMenuView::OnContextMenu(CWnd* pWnd, CPoint point) {     // TODO: Add your message handler code here     CMenu m_popMenu;     m_popMenu.LoadMenu(IDR_MENU1);     CMenu*   pSubMenu=m_popMenu.GetSubMenu(0);     pSubMenu-&gt;TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this); }

基于對話框程式大小調整相關:

對話框border屬性改為resizing即為可調大小.

控件跟随視窗大小一起變化,響應WM_SIZE消息

限制大小的範圍   重載WM_GETMINMAXINFO消息  OnGetMinMaxInfo(MINMAXINFO   FAR*   lpMMI)    {

        lpMMI-&gt; ptMinTrackSize.x   =   400   ;          lpMMI-&gt; ptMinTrackSize.y   =   400   ;

        lpMMI-&gt; ptMaxTrackSize.x   =   500   ;          lpMMI-&gt; ptMaxTrackSize.y   =   500   ;

        CDialog::OnGetMinMaxInfo(lpMMI);  }

對話框滾動條屬性後的響應:

//水準滾動響應 void CChildDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {  // TODO: 在此添加消息處理程式代碼和/或調用預設值  SCROLLINFO scrollinfo;    GetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);    switch (nSBCode)    {    case SB_LEFT:     ScrollWindow((scrollinfo.nPos-scrollinfo.nMin)*10,0);     scrollinfo.nPos = scrollinfo.nMin;     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     break;    case SB_RIGHT:     ScrollWindow((scrollinfo.nPos-scrollinfo.nMax)*10,0);     scrollinfo.nPos = scrollinfo.nMax;     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     break;    case SB_LINELEFT:     scrollinfo.nPos -= 1;     if (scrollinfo.nPos&lt;scrollinfo.nMin)   {      scrollinfo.nPos = scrollinfo.nMin;      break;     }     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     ScrollWindow(10,0);     break;    case SB_LINERIGHT:     scrollinfo.nPos += 1;     if (scrollinfo.nPos&gt;scrollinfo.nMax)     {      scrollinfo.nPos = scrollinfo.nMax;      break;     }     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     ScrollWindow(-10,0);     break;    case SB_PAGELEFT:     scrollinfo.nPos -= 5;     if (scrollinfo.nPos&lt;scrollinfo.nMin)   {      scrollinfo.nPos = scrollinfo.nMin;      break;     }     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     ScrollWindow(10*5,0);     break;    case SB_PAGERIGHT:     scrollinfo.nPos += 5;     if (scrollinfo.nPos&gt;scrollinfo.nMax)     {      scrollinfo.nPos = scrollinfo.nMax;      break;     }     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     ScrollWindow(-10*5,0);     break;    case SB_THUMBPOSITION:     break;    case SB_THUMBTRACK:     ScrollWindow((scrollinfo.nPos-nPos)*10,0);     scrollinfo.nPos = nPos;     SetScrollInfo(SB_HORZ,&amp;scrollinfo,SIF_ALL);     break;    case SB_ENDSCROLL:     break;    } 

 CDialog::OnHScroll(nSBCode, nPos, pScrollBar); }

//垂直滾動響應 void CChildDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {  // TODO: 在此添加消息處理程式代碼和/或調用預設值

 if (pScrollBar == NULL)  {   //MessageBox("33333333");  }  SCROLLINFO scrollinfo;  GetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);  switch (nSBCode)  {  case SB_BOTTOM:   ScrollWindow(0,(scrollinfo.nPos-scrollinfo.nMax)*10);   scrollinfo.nPos = scrollinfo.nMax;   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   break;  case SB_TOP:   ScrollWindow(0,(scrollinfo.nPos-scrollinfo.nMin)*10);   scrollinfo.nPos = scrollinfo.nMin;   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   break;  case SB_LINEUP:   scrollinfo.nPos -= 1;   if (scrollinfo.nPos&lt;scrollinfo.nMin)   {    scrollinfo.nPos = scrollinfo.nMin;    break;   }   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   ScrollWindow(0,10);   break;  case SB_LINEDOWN:   scrollinfo.nPos += 1;   if (scrollinfo.nPos&gt;scrollinfo.nMax)   {    scrollinfo.nPos = scrollinfo.nMax;    break;   }   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   ScrollWindow(0,-10);   break;  case SB_PAGEUP:   scrollinfo.nPos -= 5;   if (scrollinfo.nPos&lt;scrollinfo.nMin)   {    scrollinfo.nPos = scrollinfo.nMin;    break;   }   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   ScrollWindow(0,10*5);   break;  case SB_PAGEDOWN:   scrollinfo.nPos += 5;   if (scrollinfo.nPos&gt;scrollinfo.nMax)   {    scrollinfo.nPos = scrollinfo.nMax;    break;   }   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   ScrollWindow(0,-10*5);   break;  case SB_ENDSCROLL:   break;  case SB_THUMBPOSITION:  //拖動   ScrollWindow(0,(scrollinfo.nPos-nPos)*10);   scrollinfo.nPos = nPos;   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   break;  case SB_THUMBTRACK:   ScrollWindow(0,(scrollinfo.nPos-nPos)*10);   scrollinfo.nPos = nPos;   SetScrollInfo(SB_VERT,&amp;scrollinfo,SIF_ALL);   break;  }

 CDialog::OnVScroll(nSBCode, nPos, pScrollBar); }

響應WM_MOUSEWHELL消息 BOOL CScrollDemoDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)    {        // TODO: 在此添加消息處理程式代碼和/或調用預設值        //向下滾        if (zDelta == -120)        {                     nVscroll += 10;          OnVScroll(SB_PAGEDOWN, nVscroll, &amp;m_vScroll);        }        else if (zDelta == 120)        {            nVscroll -= 10;            OnVScroll(SB_PAGEUP, nVscroll, &amp;m_vScroll);                                }                m_vScroll.MoveWindow(rt_mvScroll, TRUE);        return CDialog::OnMouseWheel(nFlags, zDelta, pt);    } 

 屏蔽ENTER和ESC按鍵:

/******************************************************************* 函數名稱: PreTranslateMessage 描    述: 重載函數,屏蔽Enter鍵 輸入參數: 無 輸出參數: 無 返    回: 無 說     明:無 *******************************************************************/ BOOL CSystemConfig::PreTranslateMessage(MSG* pMsg) {     // TODO: 在此添加專用代碼和/或調用基類     if   (pMsg-&gt; message   ==   WM_KEYDOWN)      {          if   (pMsg-&gt; wParam   ==   VK_ESCAPE)              return   TRUE;          if   (pMsg-&gt; wParam   ==   VK_RETURN)              return   TRUE;      } 

    return CDialog::PreTranslateMessage(pMsg); }

我們看電視時,看到的螢幕稱為OSD層,也就是說,隻有在OSD層上顯示圖像我們才能看到。現在,我需要建立一個虛拟的、看不見但是可以在上面畫圖(比如說畫點、線)的OSD層,我稱之為offscreen(背景緩沖區)。這個offscreen存在于記憶體中,我們在上面畫圖,這個offscreen上面的東西可以顯示在OSD層上,需要一個建立這個offscreen的函數,傳回這個offscreen的句柄(整型指針)、寬度、高度、指向建立offscreen資料緩沖區的指針,該緩沖區是一個在函數外建立的offscreen的資料緩沖區,大小是offscreen的高度*寬度*每個像素點資料的大小。閃爍是圖形程式設計的一個常見問題。需要多重複雜繪制操作的圖形操作會導緻呈現的圖像閃爍或具有其他不可接受的外觀。雙緩沖的使用解決這些問題。雙緩沖使用記憶體緩沖區來解決由多重繪制操作造成的閃爍問題。當啟用雙緩沖時,所有繪制操作首先呈現到記憶體緩沖區,而不是螢幕上的繪圖圖面。所有繪制操作完成後,記憶體緩沖區直接複制到與其關聯的繪圖圖面。因為在螢幕上隻執行一個圖形操作,是以消除了由複雜繪制操作造成的圖像閃爍。

CClientDC dc(this);     CDC memdc;     memdc.CreateCompatibleDC(&amp;dc);

CRect rc;     GetClientRect(rc);     CBitmap bmp;     Bmp.CreateCompatibleBitmap(&amp;dc,rc.Width(),rc.Height());     CBitmap *oldbmp=memdc.SelectObject(&amp;bmp);

memDC.MoveTo(0,0);     memDC.LineTo(100,100);

dc.BitBlt(0,0,rc.Width(),rc.Height(),&amp;memdc,0,0,SRCCOPY);

上邊示範一段初始時候的例子.

首先給出實作的程式,然後再解釋,同樣是在OnDraw(CDC *pDC)中:

//首先定義一個顯示裝置對象

CDC MemDC;    

                   

//定義一個位圖對象

CBitmap MemBitmap; 

//随後建立與螢幕顯示相容的記憶體顯示裝置

//這時還不能繪圖,因為沒有地方畫 ^_^

MemDC.CreateCompatibleDC(NULL/*pDc一般用這個,不用NULL*/);

  //下面建立一個與螢幕顯示相容的位圖,至于位圖的大小嘛,可以用視窗的大小,也可以自己定義(如:有滾動條時就要大于目前視窗的大小,在BitBlt時決定拷貝記憶體的哪部分到螢幕上)

MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);

  //将位圖選入到記憶體顯示裝置中

  //隻有選入了位圖(#add一定要bitmap?)的記憶體顯示裝置才有地方繪圖,畫到指定的位圖上

CBitmap *pOldBit=MemDC.SelectObject(&amp;MemBitmap);

  //先用背景色将位圖清除幹淨,這裡我用的是白色作為背景

  //你也可以用自己應該用的顔色

MemDC.FillSolidRect(0,0,nWidth,nHeight,#ffffff);

  //繪圖

  MemDC.MoveTo(……);

MemDC.LineTo(……);

  //将記憶體中的圖拷貝到螢幕上進行顯示

pDC-&gt;BitBlt(0,0,nWidth,nHeight,&amp;MemDC,0,0,SRCCOPY);

  //繪圖完成後的清理

  MemBitmap.DeleteObject();

  MemDC.DeleteDC();

/////////////////////////////////////////////////////////////////////

 下面的代碼是一個最簡單的雙緩沖的模闆。可以根據需要,做簡單的修改即可。

Bitmap CacheImage( [Width], [Height] );

Graphics CacheGraphics( &amp;CacheImage );

// 對CacheImage進行描畫

// ......

// 獲得視窗的Graphics對象

Graphics Graphic( [ Window’s HDC ] );

// 将描畫好的CacheImage畫到視窗上

Graphic.DrawImage( &amp;CacheImage, [Left], [Top] );

根據一些簡單的測試,雙緩沖可以有效的改善圖像的處理速度。不過最明顯的效果還是降低畫面的閃爍程度。

另(推薦):

1、在記憶體中建立一塊“虛拟畫布”:

Bitmap bmp = new Bitmap(600, 600);

2、擷取這塊畫布的Graphics 對象指針:

Graphics *gBuf = Graphics.FromImage(bmp);

3、在這塊記憶體畫布上繪圖:

gBuf-&gt;FillEllipse(brush, i * 10, j * 10, 10, 10);

4、将記憶體畫布畫到視窗中

HDC hdc = GetDC(hwnd);  Graphics g(hdc);  g.DrawImage(bmp, 0, 0, 100, 200); ReleaseDC(hwnd, hdc); delete gBuf;    // 必不可少,否則會記憶體洩漏

另:

2、擷取這塊記憶體畫布的Graphics引用:

Graphics g = Graphics.FromImage(bmp);

g.FillEllipse(brush, i * 10, j * 10, 10, 10);

this-&gt;CreateGraphics().DrawImage(bmp, 0, 0);  

另外還可以使用CachedBitmap類來做雙緩沖。Graphic也有專門的DrawCachedBitmap方法來描畫CachedBitmap。但沒有上述的方法靈活。如下:

*C++ code*/

RECT rc;

GetClientRect(g_hwnd,&amp;rc);

Bitmap bmp(int(rc.right),int(rc.bottom));

Graphics bmpGraphics(&amp;bmp);

bmpGraphics.SetSmoothingMode(SmoothingModeAntiAlias);

/*Drawing on bitmap*/

SolidBrush bkBrush(Color(0,0,0));

bmpGraphics.FillRectangle(&amp;bkBrush,0,0,rc.right,rc.bottom);

/*Drawing on DC*/

Graphics graphics(hdc);

/*Important! Create a CacheBitmap object for quick drawing*/

CachedBitmap cachedBmp(&amp;bmp,&amp;graphics);

graphics.DrawCachedBitmap(&amp;cachedBmp,0,0);

以上的繪制代碼最差別于網絡上其他GDI+實作的一處就是,在最後添加了一個CacheBitmap對象用于快速繪制。

CacheBitmap是一個包含了bmp全部象素,并且針對graphics所關聯的DC做過特别優化的位圖對象。這點可以從其構造參數上看到。 

 讓CSpinButtonCtrl控件嵌入edit控件裡邊:

如圖風格

MFC經驗 GDI和 GDI+實作雙緩存

調整edit和cspin控件的tab order 順序為相鄰, 設定cspin 的auto buddy 屬性為true即可.

我的函數注釋:

 類頭檔案中用

//功能說明

類的cpp檔案中則用:

//================================================================================== // 功能:    裝載指定皮膚 // 參數:    strPath:皮膚路徑 // 傳回值:  無 // 備注 //==================================================================================

GDI一些重要差別:

ReleadDC,是和GetDC()配套使用;  而DeleteDC,和CreateCompatibleDC配套使用;

DeleteObject,是對用Create_為字首建立的GDI對象使用的。   (#add,即 分兩部分,一部分是CDC有關,另一部分則CGdiObject有關) 比如CreateBitmap(),CreateSolidBrush()等等。。 

對話框透明:

SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE)^0x80000); //0x80000 : WS_EX_LAYERED  HINSTANCE hInst = LoadLibrary("User32.DLL"); // 顯式加載DLL  if (hInst != NULL)  {  typedef BOOL (WINAPI *MYFUNC)(HWND, COLORREF, BYTE, DWORD);  // 取得SetLayeredWindowAttributes函數指針  MYFUNC pFunc = (MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");  if (pFunc != NULL)  {  pFunc(m_hWnd,#ece9d8, 256, 1); // 2 : LWA_ALPHA  }  FreeLibrary(hInst);  hInst = NULL;  }

繼續閱讀