当前位置: > 执迷古镇 > 文章内容
传奇私服无闪烁刷屏技术的实现
作者:时间:2021-4-17 14:24:46标签:热血传奇1 76
当我们需要在用户区显示一些图形时,先把图形在客户区画上,虽然已经画好但此时我们还无法看到,还要通过程序主动地刷新用户区,强制Windows发送一条WM_PAINT消息,这将引发视类OnDraw函数简单地将所有的图形对象重画,这样才完成了图形的显示工作,但在刷新的同时会引起较明显的闪烁尤其是当画面面积较大、图像元素过多时尤为明显甚至达到无法正常工作的地步。因此,我们需要做相应的处理。本文介绍了采用先在内存中绘制图形,然后再把绘好的图形以位图方式从内存拷贝到窗口客户的消除刷屏闪烁的一种方法。一、WM_PAINT消息和无效区当以下情况之一发生时,就要求应用程序一定刷新其用户区的一部分或全部:1.在用户移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见。2.用户改变窗口的大小。3.滚动窗口用户区。4.程序调用InvalidateRect或InvalidateRgn函数显式地发送一条WM_PAINT消息。此时Windows会向窗口函数发送一条WM_PAINT消息。另外,当Windows删除覆盖窗口部分区域的对话框或消息框时和菜单下拉出来又被释放时窗口用户区被临时覆盖,系统会试图保存显示区域,但是不一定能成功,可能向窗口函数发送一条WM_PAINT消息,要求应用程序刷新其用户区。需要说明的是:光标或图符穿过窗口用户区时,也可能覆盖显示内容,但这种情况下,系统一定能保留并恢复被覆盖的区域,所以此时并不会发送WM_PAINT消息来要求应用程序去刷新其显示区。在W天堂传奇indows应用程序的窗口函数中,对WM_PAINT消息的处理就是刷新其用户区,这是一种固定的程序结构。为提高刷新效率,我们可以只刷新用户区的一小部分,其余没有发生变化的我们可以不予刷新,窗口函数可以通过调用函数InvalidateRect显式地使用户区内的一个矩形无效。而且只有当窗口客户区的某一部分失效时,其窗口函数才会收到WM_PAINT消息。二、刷屏闪烁的产生原因与解决方法当客户区有所改动,而又要将改动显示出来,就必然要强制Windows发送一条WM_PAINT消息,从而引发OnDraw函数的重画,这样虽完成了图形的显示,却也会引起较明显的闪烁,当画面上数据不是很多时尚不明显,当客户区有成千上万个点的时候刷新一次会引起整幅画面的剧烈跳动,尤其是对于许多实时监控软件和矢量电子地图软件,此类软件通常在屏幕上都会动辄几千、几万个要素点,很明显单靠发送WM_PAINT消息引发OnDraw的重画根本满足不了实际需求。为了解决上述问题,我们需要做一些相应的处理。首先要先检取无效区,然后创建一个与原设传奇外传私服发布备环境句柄pDC相兼容的内存设备环境,之后就可以采用在内存中绘制图形并把绘好的图形以位图方式从内存拷贝到窗口客户的方法来消除刷屏时引起的闪烁。这还需要创建一个与原设备环境句柄pDC相兼容的、大小为整个客户区的位图。然后再使新的设备环境dc与pDC具有同样的映射关系,将位图选入内存环境。再使dc的整个客户区都成无效区,再与上所检取的无效区,使内存环境与pDC检取的无效区相等。之后便可以进行绘图工作了,绘图完毕之后应当释放所获取的设备环境句柄pDC。否则会造成系统资源的浪费。三、程序示例本示例程序通过打开任意存档文件,将其ASCII码码值当作要显示的数据,并通过一图画控件将其数据以图形的形式依次显示出来。本程序要处理的数据量较大,如不采用本文所述方法将会有很明显的闪烁。(1)新建一基于CFormView的单文档应用程序WaveShower。(2)在Form上添加一picture控件,设置其ID为IDC_SCREEN、Type为Rectangle、Color为Black。在ExtendedStyles属性页里选中ModalFrame检查框。(3)添加一菜单打开数据文件,并生成其响应函数OnOpenData()。(4)在视类中添加如下成员变量:intm_BufLen;//数据长度unsignedchar*buffer;//数据缓存intm_dx;//数据偏移量intm_DY;//数据显示区的幅度CPoint*value;//将要显示的数值intm_DX;//数据显示区的宽度intm_Y0;//数据显示区参照点位置CRectrect;//数据显示区矩形(5)在视类中添加函数GetScreenRect()用以获取数据显示区的大小及其他参数;添加函数CleanScreen()完成清除数据显示区的功能;添加函数DrawPoint()以便在数据显示区画点:voidCWaveShowerView::GetScreenRect(){CWnd*pStatic=GetDlgItem(IDC_SCREEN);pStatic-〉GetWindowRect(rect);ScreenToClient(rect);rect.top+=4;rect.left+=4;rect.bottom-=4;rect.right-=4;m_Y0=(rect.bottom-rect.top)/2+rect.top;m_DX=rect.Width();m_DY=rect.Height()/2;value=newCPoint[m_DX];}voidCWaveShowerView::CleanScreen(){CDC*pDC=GetDC();CPenpen1(PS_SOLID,1,RGB(0,0,0));CPen*oldPen1=pDC-〉SelectObject(pen1);for(inti=rect.top;i{pDC-〉MoveTo(rect.left,i);pDC-〉LineTo(rect.right,i);}pDC-〉SelectObject(oldPen1);CPenpen2(PS_SOLID,1,RGB(0,0,255));CPen*oldPen2=pDC-〉SelectObject(pen2);pDC-〉MoveTo(rect.left,m_Y0);pDC-〉LineTo(rect.right,m_Y0);pDC-〉SelectObject(oldPen2);ReleaseDC(网安传奇pDC);}voidCWaveShowerView::DrawPoint(CPointpt,COLORREFcolor){CDC*pDC=GetDC();pDC-〉SetPixel(rect.left+pt.x,m_Y0-pt.y,color);ReleaseDC(pDC);}(6)在视类的OnInitialUpdate()初始化函数中添加代码以进行数据显示的各项前期准备工作,并在打开数据文件菜单的响应函数中添加代码以读取文件的内码。voidCWaveShowerView::OnInitialUpdate(){CFormView::OnInitialUpdate();GetParentFrame()-〉RecalcLayout();ResizeParentToFit();GetScreenRect();for(inti=0;ivalue[i].x=value[i].y=0;SetTimer(0,10,NULL);}voidCWaveShowerView::OnOpenData(){CStringFileName=;CFilefile;CFileDialogdlg(TRUE,*,*.*,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,所有文件(*.*)|*.*||,NULL);if(dlg.DoModal()==IDOK){KillTimer(1);FileName=dlg.GetPathName();file.Open(FileName,CFile::modeReadWrite);m_BufLen=file.GetLength();buffer=newunsignedchar[m_BufLen+m_DX+10];file.Read(buffer,m_BufLen);file.Close();SetTimer(1,10,NULL);}}(7)下面添加的定时器响应函数正是本文的重点,为方便对比起见,笔者写了两个OnTimer响应函数,前一个是采用常规的普通方法描点的,运行起来可以很明显地看到画面的闪烁跳动。而后一种则是采用本文所述方法采用的内存画图的方法,运行后几乎画面无闪烁。下面便是两段对比代码的原码部分://代码一:有闪烁的代码voidCWaveShowerView::OnTimer(UINTnIDEvent){if(nIDEvent==0){CleanScreen();for(inti=0;iDrawPoint(value[i],RGB(0,255,0));}if(nIDEvent==1){m_dx+=2;for(inti=0;i{value[i].x=i;if(m_dx+i〈0)buffer[m_dx+i]=128;if(m_dx+i〈-m_DX)m_dx-=2;if(m_dx+i〉m_BufLen)buffer[m_dx+i]=1180星王合击发布网28;if(m_dx+i〉m_BufLen+m_DX)m_dx-=2;value[i].y=m_DY*(buffer[m_dx+i]-128)/256;}}CFormView::OnTimer(nIDEvent);}//代码二:无闪烁的代码voidCWaveShowerView::OnTimer(UINTnIDEvent){if(nIDEvent==0){CDC*pDC=GetDC();CDCdc;CBitmapbitmap;CBitmap*pOldBitmap;CRectclient;pDC-〉GetClipBox(client);//检取无效区//创建一个与pDC兼容的内存设备环境if(dc.CreateCompatibleDC(pDC)){//创建一与pDC兼容的位图,大小为整个客户区if(bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height())){//使dc与pDC具有同样的映射关系OnPrepareDC(dc,NULL);//将位图选入内存环境pOldBitmap=dc.SelectObject(bitmap);//使dc的整个客户区都成无效区dc.SelectClipRgn(NULL);//再与上检取的无效区,使内存环境与//pDC检取的无效区相等dc.IntersectClipRect(client);}}CleanScreen();for(inti=0;iDrawPoint(value[i],RGB(0,255,0));dc.SelectObject(pOldBitmap);ReleaseDC(pDC);}if(nIDEvent==1){m_dx+=2;for(inti=0;i{value[i].x=i;if(m_dx+i〈0)buffer[m_dx+i]=128;if(m_dx+i〈-m_DX)m_dx-=2;if(m_dx+i〉m_BufLen)buffer[m_dx+i]=128;if(m_dx+i〉m_BufLen+m_DX)m_dx-=2;value[i].y=m_DY*(buffer[m_dx+i]-128)/256;}}CFormView::OnTimer(nIDEvent);}(8)虽然通过上述几步可以实现所有的功能,但为了防止内存泄露和养成良好的编程习惯,我们还须做些工作,在视类的构造函数中释放我们曾经申请过的内存以及定时器:CWaveShowerView::~CWaveShowerView(){delete[]value;KillTimer(0);KillTimer(1);}轻变传奇私服四、编译运行编译运行此程序,通过菜单选取需要显示的文件(任意文件均可),如在定时器响应代码中采用的是第一种代码,则会看到数据显示的同时伴随着明显的闪烁而采用后一种代码编码则会很平稳的将数据显示出来。结论:本文介绍的这种方法适用于各种牵扯到数组数据图形显示的程序,比如监控软件、数据分析软件、测量软件等等,具有广泛的应用前景。
- 上一篇: 传奇时间点卡程序的设置方法
- 下一篇: 游戏最高等级限制脚本(blue)
推荐文章
- 天庭后宫省钱养小号背后的游戏智慧
- 传奇世界似服传说暗殿鸡爆落魄神兵那暗殿鹿爆什么呢
- 英雄合击传奇神奇风云的死对头江南风暴曾经也是天下第一会长
- 热血传奇新开私服全属性都是三位数的未知装备雪玉戒指
- 最新传奇私服发布站产出特戒又多又好的三大BOSS赤月恶魔才是王者
- 热血传奇私服网站两根运6白色虎齿项链光芒那根50%运6的真假难辨
- 月卡传奇四顶大极品战士头盔两顶热门两顶低调
- 传奇登陆器实力碾压魔龙教主号称传奇最强BOSS火龙
- 新开传奇sf发布网比攻175泰坦更强的神戒攻击208真魂戒指
- 免费传奇终结小虾米多年称霸沙巴克神话的战士小雨情人
- 176传奇死亡棺材另一端的洞口通往哪里有隐藏地图吗
- 新开传奇私服合击版比天龙圣剑还稀有的顶级神兵攻47开天
- 好私服比奇铁匠一直没有送出去的礼物生铁戒指
- 999sf带刀护卫也出自虎卫堂因为天尊的施救才成了带刀护卫
- sf1.76移动的补给站半兽勇士
- 新开传奇私服网适合土豪法师的练级打宝大范围群攻神技地狱雷光
- 变态传奇网站准确+217敏捷+17盘点四根极品琥珀项链
- 原始传奇盘点四个非名牌极品攻3手镯最后一个是孤品
- 新开sf发布网天尊道袍原是定情信物只不过天尊错过了这段好姻缘
- www.999sf.com盘点那些让老玩家心心念念的入口真的有隐藏地图吗
相关游戏
解析法师赚钱和升级的一些方法
寂静之城
传奇挑战地图添加传奇私发变态传奇下载方法说都市2046sf明
战士和道士哪个更传奇3发布网厉害一些
网通超变英雄合击传奇传奇团战核心输出位置是法师?
传圣天传奇奇服务端快速提升传奇私服180飞龙版网通传奇sf发布网自己等级脚本
sf网站合击发布网外面开放的‘合击’怎么
我的法师生涯
野外地图给玩家带传奇私服有毒吗来激情和提升
游戏中玩家称号系统的详细说明
传奇3sf发布网游戏祝福油获取及使用攻略
选择玩同职业组合要谨慎防范好自己的发至尊精品176展方向
从300多w降到一杯奶茶的价格浅析麻痹戒指的心酸历程
传奇手游下载三顶法师最强极品道士头盔安徽热线魔6道头属性逆天
荣誉勋章配戴起来还是有难度的
在游戏中如何进行交易
首战首区行会的招兵买马设定
宠物的进化和提升设定
一条龙女道士传奇超变态私服所拥有的独特技能
皇城悬传奇私服挂机网赏到底要不要组队玩