#pragma once
class HDCMemo{public: HDCMemo(RECT rtImg); virtual ~HDCMemo(void);
void Record(HDC hDC); void Recover(HDC hDC); RECT getSize();private: HANDLE m_hMutex; RECT m_rtImg; HBITMAP m_bmpMemo;};
#pragma once#include "../CE600.h"#include "../HDCMemo.h"
class Cartoon{public: bool Run(LPVOID pPar); bool IsOver();
protected: Cartoon(CDialog* pDlg, HDCMemo* pHDCMemo); virtual ~Cartoon(void); virtual void Render(LPVOID pPar) = 0;
CDialog *m_pDlg; HDCMemo *m_pHDCMemo; HANDLE m_hMutex; ThreadEx* m_pThread; HANDLE m_hClose; LPVOID m_pRenderPar; friend DWORD CartoonThread(LPVOID pThis);};
#pragma once#include "Cartoon.h"
class CartoonPiece: public Cartoon{public: CartoonPiece(CDialog* pDlg, HDCMemo* pHDCMemo); virtual ~CartoonPiece(void);
private: virtual void Render(LPVOID pPar);};
使用:
BOOL CCartoonDlg::OnInitDialog(){ CDialog::OnInitDialog(); CRect rtImg; GetClientRect(rtImg); m_pMemo = new HDCMemo(rtImg); CDC* pDC = GetDC(); CDCBuf buf(pDC,&rtImg); buf.fillRect(RGB(0,0,255)); m_pMemo->Record(buf); m_pCartoon = new CartoonPiece(this,m_pMemo); m_pCartoon->Run(NULL);
return TRUE; // return TRUE unless you set the focus to a control}
void CCartoonPieceDlg::OnDestroy(){ // TODO: Add your message handler code here if( NULL != m_pCartoon) delete m_pCartoon; m_pCartoon = NULL; if( NULL != m_pMemo) delete m_pMemo; m_pMemo = NULL;
CDialog::OnDestroy();}
BOOL CCartoonPieceDlg::OnEraseBkgnd(CDC* pDC){ m_pMemo->Recover(*pDC);
return FALSE;}
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
png格式的渲染速度较慢,画一张480*272的图要200毫秒左右,而人眼的辨别能力为100毫秒左右,故会出现反应延迟现象。而这个现象试图通过画取部份空间来解决并不现实。因为这样会导致两种渲染逻辑:1,如果是首次画,需全画。 2, 如果是补画,需重画部份空间。但是判断是首画还是补画会比较麻烦,因为触发画图函数的消息可以是用户触发的,也可以是由系统触发的(例如窗口被遮挡住等)。而要对所有的触发情况做标志,并针对标志做相应的全画和补画,不现实也不可靠。安全的方法可能还是得每次都全画,只是在全画的过程中想办法提高效率。 另还有一个渲染动画的问题一直也没有很好的解决,因为渲染过程中系统无法响应其它消息, 所以如果是一个动画,那么只有等动画执行完毕了。 虽然还可以用线程等方法,但是目前却没有很好的打包和设计模式来解决,导致明明是一个连续的动作,却要分割成一个个图画,然后再添加相关消息处理过程控制在程序里四处散放等,导致实现不影响用户动作的一个动画很麻烦。
解决方案:通过线程,计时器和备忘录模式(带互斥作用)解决。流程如下:
客户端:
动作线程:
{
服务器->开启刷新定时器。
While(X)
{
渲染。
备忘录记录记录(画面)。
}
服务器->关闭刷新定时器。
}
服务器端:
OnPaint()
{
画图(获得备忘录记录)。
}
备: 通过备忘录模式,使每次修改扩展渲染功能都不用去服务器的OnPaint功能里修改(画图一定要经过OnPaint才行,不然一些重画的情况时,画面会丢失)。通过线程,使动画过程不影响其它消息的响应。通过定时器来刷新使动画的渲染速度稳定。另,备忘录需带互斥功能,以防画面读写过程出错。
/******************************************************************** created: 2011/03/01 created: 1:3:2011 10:52 filename: g:/20110221文件整理/源码/小工具_实现代码(20110221版)/CE600/HDCMemo.h file path: g:/20110221文件整理/源码/小工具_实现代码(20110221版)/CE600 file base: HDCMemo file ext: h author: Clark purpose: 用于动画渲染的备忘录模式*********************************************************************/
#include "StdAfx.h"#include "HDCMemo.h"
HDCMemo::HDCMemo(RECT rtImg){ CopyRect(&m_rtImg,&rtImg); HDC hDC = GetDC(NULL); m_bmpMemo = CreateCompatibleBitmap(hDC,m_rtImg.right-m_rtImg.left, m_rtImg.bottom-m_rtImg.top); ReleaseDC(NULL,hDC);
TCHAR szTemp[MAX_PATH]; _stprintf(szTemp,_T("MUTEX_FOR_HDCMEMO_%x"),this); m_hMutex = CreateMutex(NULL,FALSE,szTemp); }
HDCMemo::~HDCMemo(void){ DeleteObject(m_bmpMemo); if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,5000)) { ReleaseMutex(m_hMutex); } CloseHandle(m_hMutex);}
void HDCMemo::Record(HDC hDC){ if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,INFINITE)) { HDC dcBitmap = CreateCompatibleDC(hDC); HGDIOBJ hOldBitmap = SelectObject(dcBitmap, m_bmpMemo); BitBlt(dcBitmap,0,0,m_rtImg.right-m_rtImg.left, m_rtImg.bottom-m_rtImg.top,hDC,0,0,SRCCOPY); SelectObject(dcBitmap, hOldBitmap); DeleteDC(dcBitmap);
ReleaseMutex(m_hMutex); }}
void HDCMemo::Recover(HDC hDC){ if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,INFINITE)) { HDC dcBitmap = CreateCompatibleDC(hDC); HGDIOBJ hOldBitmap = SelectObject(dcBitmap,m_bmpMemo); BitBlt(hDC,0,0,m_rtImg.right-m_rtImg.left, m_rtImg.bottom-m_rtImg.top,dcBitmap,0,0,SRCCOPY); SelectObject(dcBitmap,hOldBitmap); DeleteDC(dcBitmap);
ReleaseMutex(m_hMutex); }}
RECT HDCMemo::getSize(){ return m_rtImg;}
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/******************************************************************** created: 2011/03/01 created: 1:3:2011 11:34 filename: g:/20110221文件整理/源码/小工具_实现代码(20110221版)/CE600/Cartoon.h file path: g:/20110221文件整理/源码/小工具_实现代码(20110221版)/CE600 file base: Cartoon file ext: h author: Clark purpose: 动画渲染*********************************************************************/
#include "StdAfx.h"#include "Cartoon.h"
DWORD CartoonThread(LPVOID pThis){ Cartoon* pCartoon = (Cartoon*)pThis; pCartoon->Render(pCartoon->m_pRenderPar); if( WAIT_OBJECT_0 == WaitForSingleObject(pCartoon->m_hMutex,INFINITE)) { pCartoon->m_pThread = NULL; ReleaseMutex(pCartoon->m_hMutex); } return 0;}
Cartoon::Cartoon(CDialog* pDlg, HDCMemo* pHDCMemo):m_pThread(NULL){ m_pDlg = pDlg; m_pHDCMemo = pHDCMemo; TCHAR szTemp[MAX_PATH]; _stprintf(szTemp,_T("MUTEX_FOR_CARTOON_%x"),this); m_hMutex = CreateMutex(NULL,FALSE,szTemp); }
Cartoon::~Cartoon(void){ if( NULL != m_pThread) delete m_pThread; m_pThread = NULL; if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,5000)) { ReleaseMutex(m_hMutex); } CloseHandle(m_hMutex);}
bool Cartoon::Run(LPVOID pPar){ bool bSign = false; if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,INFINITE)) { if( NULL == m_pThread) { m_pRenderPar = pPar; m_pThread = new ThreadEx(m_hClose,CartoonThread,this); bSign = true; } ReleaseMutex(m_hMutex); } return bSign;}
bool Cartoon::IsOver(){ bool bSign = false; if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,INFINITE)) { if( NULL == m_pThread) { bSign = true; } ReleaseMutex(m_hMutex); } return bSign;}
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/******************************************************************** created: 2011/03/01 created: 1:3:2011 11:34 filename: g:/20110221文件整理/源码/小工具_实现代码(20110221版)/CE600/Cartoon.h file path: g:/20110221文件整理/源码/小工具_实现代码(20110221版)/CE600 file base: Cartoon file ext: h author: Clark purpose: 动画渲染*********************************************************************/
#include "StdAfx.h"#include "CartoonPiece.h"#include "../CDCBuf.h"
CartoonPiece::CartoonPiece(CDialog* pDlg, HDCMemo* pHDCMemo):Cartoon(pDlg,pHDCMemo){ NULL;}
CartoonPiece::~CartoonPiece(void){ NULL;}
void CartoonPiece::Render(LPVOID pPar){ CRect rtDlg; m_pDlg->GetClientRect(rtDlg); CDC* pDC = m_pDlg->GetDC(); CDCBuf buf(pDC,&rtDlg); m_pDlg->ReleaseDC(pDC); buf.SetAuto(false); m_pMemo->Recover(buf);
const int iCount = 8; const int iROWS = 4; const int iLINES = 4; const int iUW = rtDlg.Width()/iLINES+0.5; const int iUH = rtDlg.Height()/iROWS+0.5; const int iUW_L = iUW/iCount+0.5; const int iUH_L = iUH/iCount+0.5; int iPosX, iPosY, iW, iH;
iW = iH = 0; for(int k=0; k<iCount; k++) { iPosX = iPosY = 0; iW += iUW_L; iH += iUH_L; for(int i=0; i<=iROWS; i++) { iPosX = 0; for(int j=0; j<=iLINES; j++) { CRect rtImg(iPosX,iPosY,iPosX+iW,iPosY+iH); if( NULL == pPar) buf.fillRect(RGB(0,255,0),&rtImg); else buf.drawBmp((CBitmap*)pPar,&rtImg,&rtImg); iPosX += iUW; } iPosY += iUH; } m_pMemo->Record(buf); m_pDlg->Invalidate(); Sleep(10); } if( NULL == pPar) buf.fillRect(RGB(0,255,0),&rtDlg); else buf.drawBmp((CBitmap*)pPar,&rtDlg,&rtDlg); m_pMemo->Record(buf); m_pDlg->Invalidate();}