天天看点

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 描    述: 重载函数,屏蔽回车键 输入参数: 无 输出参数: 无 返    回: 无 说     明:无 *******************************************************************/ 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;  }

继续阅读