VC防止窗口和控件闪烁的方法

o哼哼哈嘿

o哼哼哈嘿

2016-02-19 21:04

每个人都希望每天都是开心的,不要因为一些琐事扰乱了心情还,闲暇的时间怎么打发,关注图老师可以让你学习更多的好东西,下面为大家推荐VC防止窗口和控件闪烁的方法,赶紧看过来吧!

  1、将Invalidate()替换为InvalidateRect()

  Invalidate()会导致整个窗口的图象重画,需要的时间比较长,而InvalidateRect()仅仅重画Rect区域内的内容,所以所需时间会少一些。虫虫以前很懒,经常为一小块区域的重画就调用Invalidate(),不愿意自己去计算需要重画的Rect,但是事实是,如果你确实需要改善闪烁的情况,计算一个Rect所用的时间比起重画那些不需要重画的内容所需要的时间要少得多。

  2、禁止系统搽除你的窗口

  系统在需要重画窗口的时候会帮你用指定的背景色来搽除窗口。可是,也许需要重画的区域也许非常小。或者,在你重画这些东西之间还要经过大量的计算才能开始。这个时候你可以禁止系统搽掉原来的图象。直到你已经计算好了所有的数据,自己把那些需要搽掉的部分用背景色覆盖掉(如:dc.FillRect(rect,&brush);rect是需要搽除的区域,brush是带背景色的刷子),再画上新的图形。要禁止系统搽除你的窗口,可以重载OnEraseBkgnd()函数,让其直接返回pUE就可以了。如

BOOL CMyWin::OnEraseBkgnd(CDC* pDC)
{
  return pUE;
  //return CWnd::OnEraseBkgnd(pDC);//把系统原来的这条语句注释掉。
}

  3、有效的进行搽除

  搽除背景的时候,不要该搽不该搽的地方都搽。比如,你在一个窗口上放了一个很大的Edit框,几乎占了整个窗口,那么你频繁的搽除整个窗口背景将导致Edit不停重画形成剧烈的闪烁。事实上你可以CRgn创建一个需要搽除的区域,只搽除这一部分。如

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

GetClientRect(rectClient);
rgn1.CreateRectRgnIndirect(rectClient);
rgn2.CreateRectRgnIndirect(m_rectEdit);
if(rgn1.CombineRgn(&rgn1,&rgn2,RGN_XOR) == ERROR)//处理后的rgn1只包括了Edit框之外的客户区域,这样,Edit将不会被我的背景覆盖而导致重画。
{
  ASSERT(FALSE);
  return ;
}
brush.CreateSolidBrush(m_clrBackgnd);
pDC-FillRgn(&rgn1,&brush);
brush.DeleteObject();

  注意:在使用这个方法的时候要同时使用方法二。别忘了,到时候又说虫虫的办法不灵。

  4、使用MemoryDC先在内存里把图画好,再复制到屏幕上

  这对于一次画图过程很长的情况比较管用。毕竟内存操作比较快,而且复制到屏幕又是一次性的,至少不会出现可以明显看出一个东东从左画到右的情况。

void CMyWin::OnPaint()
{
  CPaintDC dc1(this); // device context for painting
  dcMemory.CreateCompatibleDC(&dc1);
  CBitmap bmp;//这里的Bitmap是必须的,否则当心弄出一个大黑块哦。
  bmp.CreateCompatibleBitmap(&dc1,rectClient.Width(),rectClient.Height());
  dcMemory.SelectObject(&bmp);
  //接下来你想怎么画就怎么画吧。
  //dcMemory.FillRect(rectClient,&brush);
  dc1.BitBlt(0,0,rectClient.Width(),rectClient.Height(),&dcMemory,0,0,SRCCOPY);
  dcMemory.DeleteDC();
  // Do not call CWnd::OnPaint() for painting messages
}  争议
上述方法确实有效,但在有很多控件的情况下,计算一个窗口中需要擦除并重绘的“空白区域”是一件很麻烦的事情。为了方便这种方法的实际应用,我写了一组宏来完成”计算空白区域“的功能:

/*************************************************************************/
/************************************************************************/
/* 宏功能: 界面刷新时仅刷新指定控件以外的空白区域;可有效避免窗口闪烁
/* 使用于: WM_ERASEBKGND 消息处理函数 OnEraseBkgnd();
/************************************************************************/
#define ERASE_BKGND_BEGIN
CRect bgRect;
GetWindowRect(&bgRect);
CRgn bgRgn;
bgRgn.CreateRectRgnIndirect(bgRect);
//#define ERASE_BKGND_BEGIN
// Marco parameter 'IDC' specifies the identifier of the control
#define ADD_NOERASE_CONTROL(IDC)
{
  CRect controlRect;
  GetDlgItem(IDC)-GetWindowRect(&controlRect);
  CRgn controlRgn;
  controlRgn.CreateRectRgnIndirect(controlRect);
  if(bgRgn.CombineRgn(&bgRgn, &controlRgn, RGN_XOR)==ERROR)
   return false;
}
// Marco parameter 'noEraseRect' specifies a screen coordinates based RECT,
// which needn't erase.
#define ADD_NOERASE_RECT(noEraseRect)
{
  CRgn noEraseRgn;
  noEraseRgn.CreateRectRgnIndirect(noEraseRect);
  if(bgRgn.CombineRgn(&bgRgn, &noEraseRgn, RGN_XOR)==ERROR)
   return false;
}
// Marco parameter 'pDC' is a kind of (CDC *) type.
// Marco parameter 'clBrushColor' specifies the color to brush the area.
#define ERASE_BKGND_END(pDC, clBrushColor)
CBrush brush;
brush.CreateSolidBrush(clBrushColor);
CPoint saveOrg = (pDC)-GetWindowOrg();
(pDC)-SetWindowOrg(bgRect.TopLeft());
(pDC)-FillRgn(&bgRgn, &brush);
(pDC)-SetWindowOrg(saveOrg);
brush.DeleteObject();
//#define ERASE_BKGND_END
/*************************************************/

  说明:

  1)宏 ERASE_BKGND_BEGIN 和 ERASE_BKGND_END(pDC, clBrushColor) 搭配使用。

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  2)宏 ADD_NOERASE_CONTROL(IDC) 和 ADD_NOERASE_RECT(noEraseRect) 根据需要放在上面两个宏的中间,用来添加不需要重绘背景的区域(正是这些区域导致了闪烁),使用次数不限。其中参数noEraseRect是一个屏幕坐标系的RECT类型或CRect类型。

  使用举例1:

  在当前窗体的类中重写WM_ERASEBKGND消息处理函数如下:

BOOL CMyWnd::OnEraseBkgnd(CDC* pDC)
{
  ERASE_BKGND_BEGIN;
  ADD_NOERASE_RGN(IDC_BUTTON2);
  ADD_NOERASE_RGN(IDC_BUTTON1);
  ADD_NOERASE_RGN(IDC_LIST_STAT);
  ERASE_BKGND_END(pDC, GetSysColor(COLOR_3DFACE));
  return false;
}
  上面的IDC_BUTTON2,IDC_BUTTON1,IDC_LIST_STAT即窗体上的控件。

  你可以指定其他已存在的控件。本文发表于http://bianceng.cn(编程入门网)

  这样,窗口在擦除背景时,将只对上述控件以后的”空白区域“使用系统色重绘,有效避免了闪烁。

  备注:

  重载WM_ERASEBKGND消息处理函数OnEraseBkgnd的方法,选择View-ClassWizard-classinfo选项卡:message filter下拉框:

  选择window,然后再选择message maps选项卡,在messages下拉框应该可以找到wm_erasebkgnd.双击添加.

  使用举例2:防止CListCtrl在拉动窗口时闪烁。

/* * No further full-erasing is required,
* to prevent screen flashing caused by background erase and view repaint.
* Only erase the blank area.
*/
BOOL CExListCtrl::OnEraseBkgnd(CDC* pDC) {
  //compute the holding-data-items area of this list control CRect rect;
  CPoint dataRgnTopLeftPoint;
  CPoint dataRgnBottomRightPoint;
  GetItemPosition(0 , &dataRgnTopLeftPoint);
  GetItemPosition(GetItemCount() , &dataRgnBottomRightPoint);
  if(!GetHeaderCtrl()-GetItemRect(GetHeaderCtrl()-GetItemCount()-1, rect)) return
  CListCtrl::OnEraseBkgnd(pDC);
  dataRgnBottomRightPoint.x = rect.right;
  rect.SetRect(dataRgnTopLeftPoint, (CPoint)(dataRgnBottomRightPoint - CPoint(2,2)));
  ClientToScreen(dataRgnRect);
  //compute and erase the blank area. Using the Marco. ERASE_BKGND_BEGIN;
  ADD_NOERASE_RECT(dataRgnRect);
  ERASE_BKGND_END(pDC, GetBkColor());
  return false;
}

  说明:CListCtrl在拉动的时候,会前以背景色重刷背景,再在上面绘制有数据的Items, 而没有数据的区域则保持背景色。因此,如果在BOOL CExListCtrl::OnEraseBkgnd(CDC* pDC) 函数中简单的return false,那么没有数据的区域将显示不正常。 故举例2中先计算出有数据的items的区域,这是不需要以背景重刷的区域。 再使用本文的宏,就可以有效避免CListCtrl在拉动时候的闪烁。

展开更多 50%)
分享

猜你喜欢

VC防止窗口和控件闪烁的方法

编程语言 网络编程
VC防止窗口和控件闪烁的方法

强制和防止窗口重画

编程语言 网络编程
强制和防止窗口重画

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

VC使用CComboBox控件

编程语言 网络编程
VC使用CComboBox控件

VC无闪烁刷屏技术的实现

编程语言 网络编程
VC无闪烁刷屏技术的实现

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

VC通用控件编程之CSlider控件

编程语言 网络编程
VC通用控件编程之CSlider控件

VC启动窗口画面制作方法研究

C语言教程 C语言函数
VC启动窗口画面制作方法研究

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

Win10双系统设置默认启动操作系统和等待时间的方法

Win10双系统设置默认启动操作系统和等待时间的方法

Win7指定的杀毒软件包括哪些?

Win7指定的杀毒软件包括哪些?
下拉加载更多内容 ↓