CTextWnd轻松实现文字的滚动

时间:2022-02-26 16:38:31

//========================================================================
//TITLE:
//    CTextWnd轻松实现文字的滚动
//AUTHOR:
//    norains
//DATE:
//    Wednesday  27-February-2008
//Environment:
//    VS2005  + SDK-WINCE5.0-MIPSII
//    EVC 4.0 + SDK-WINCE5.0-MIPSII
//========================================================================

    本文是我另一篇《文字滚动的技术实现》的实例补充,因为在该文已经详细解释技术实现的原理,所以本文的重点仅仅是如何调用CTextWnd实现文字的滚动。
   
    首先我们来通览一遍CTextWnd的完整源代码: 


///////////////////////////////////////////////////////////////////// /    
//  TextWnd.h: interface for the CTextWnd class.
//
// Version:
//     0.1.4
//
// Date:
//     2008.02.27
//
// Description:
//     The base window version:
//         CWndBase        -    0.1.8
//         CMemDC            -    0.1.0
//         CStrStore        -    1.0.0
///////////////////////////////////////////////////////////////////// /

#pragma  once
#include 
" wndbase.h "
#include 
" StrStore.h "
#include 
" MemDC.h "

// ----------------------------------------------------------
// Enum value type
enum  DirectionValue
{
    DRT_NULL,
    DRT_LEFT,
    DRT_RIGHT,
    DRT_UP,
    DRT_DOWN
};
// ----------------------------------------------------------
class  CTextWnd :
    
public  CWndBase
{
    
public :
    
virtual   ~ CTextWnd( void );
    CTextWnd(
void );

    
virtual  BOOL Create(HINSTANCE hInst, HWND hWndParent,  const  TCHAR  * pcszWndClass,  const  TCHAR  * pcszWndName,BOOL bMsgThrdInside  =  FALSE);

    BOOL Move(
const  RECT  *  prcWnd);
    BOOL SetText(
const  TCHAR  *  pcszText);
    BOOL SetTxtPath(
const  TCHAR  *  pcszPath);
    BOOL Play(
void );
    BOOL Pause(
void );
    BOOL Stop(
void );
    
void  SetDirection(DirectionValue dtValue);
    
void  SetInterval(DWORD dwInterval);
    
void  SetMovePixel( int  iPixel);
    
void  SetTxtColor(COLORREF crColor);
    
void  SetTxtPointSize( int  iPointSize);
    
void  SetTxtWeight( int  iWeight);
    
void  SetBkColor(COLORREF crColor);
    BOOL SwitchNext(
void );
    BOOL SwitchPrevious(
void );


private :
    
static  BOOL CheckFile( const  TCHAR  *  pszFileName);
    BOOL ReadCurTxt(
void );
    
void  OnPaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
    
void  OnWindowPosChanged(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
    BOOL ResetTxtInfoRect(
void );    
    BOOL InitDCTxtInfo(
void );
    BOOL FindFile(
const  TCHAR  * pszPath,CStrStore  * pStore,BOOL ( * pCheckFunc)( const  TCHAR  * pcszPath));

private :
    
// Callback function
     virtual  LRESULT WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
    
virtual   void  DrawBackground(HDC hdc);

private :
    CStrStore m_FileStore;
    
int  m_iIndexCurTxt;
    TCHAR 
* m_pszTxtInfo;
    
int  m_iWndWidth;
    
int  m_iWndHeight;
    
int  m_iTxtInfoX;
    
int  m_iTxtInfoY;
    
int  m_iTxtInfoWidth;
    
int  m_iTxtInfoHeight;
    
int  m_iMovePixel;
    
int  m_iTxtInfoPointSize;    
    COLORREF m_crTxtInfoColor;
    COLORREF m_crBkColor;
    
int  m_iTxtInfoWeight;
    CMemDC m_DCTxtInfo;
    BOOL m_bInited;

    

private :    
    
// The value type is for the TimerThread,meaning the action
     enum  TimeoutAction
    {
        TA_NULL,
        TA_MOVE,
        TA_EXIT,
        TA_STOP
    };
    HANDLE m_hEventTimer;
    TimeoutAction m_taCurAction;
    DWORD m_dwInterval;
    DirectionValue m_dtValue;
    
static  DWORD TimerThread(PVOID pArg);    
    
};

/////////////////////////////////////////////////////////////////////
// TextWnd.cpp
////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TextWnd.h"


//----------------------------------------------------------------------
//Macro define
#define DEFAULT_BKGND_COLOR  RGB(128,128,128)

//For the text move
#define DEFAULT_INTERVAL  100 //500ms
#define DEFAULT_MOVE_PIXEL  1 //pixel

//The text information
#define DEFAULT_TEXT_COLOR  RGB(255,255,255)
#define DEFAULT_TEXT_POINTSIZE  0
#define DEFAULT_TEXT_WEIGHT  0
//----------------------------------------------------------------------


//----------------------------------------------------------------------
//Description:
// Construction
//-----------------------------------------------------------------------
CTextWnd::CTextWnd(void):
m_iIndexCurTxt(0),
m_pszTxtInfo(NULL),
m_taCurAction(TA_NULL),
m_dwInterval(DEFAULT_INTERVAL),
m_hEventTimer(CreateEvent(NULL,FALSE,FALSE,NULL)),
m_dtValue(DRT_NULL),
m_iWndWidth(0),
m_iWndHeight(0),
m_iTxtInfoX(0),
m_iTxtInfoY(0),
m_iTxtInfoWidth(0),
m_iTxtInfoHeight(0),
m_iMovePixel(DEFAULT_MOVE_PIXEL),
m_iTxtInfoPointSize(DEFAULT_TEXT_POINTSIZE), 
m_crTxtInfoColor(DEFAULT_TEXT_COLOR),
m_iTxtInfoWeight(DEFAULT_TEXT_WEIGHT),
m_bInited(FALSE),
m_crBkColor(DEFAULT_BKGND_COLOR)

 
 //Create the timer thread to move the text 
 HANDLE hdThrd = CreateThread(NULL,NULL,TimerThread,this,NULL,NULL);
 CloseHandle(hdThrd);
}

//----------------------------------------------------------------------
//Description:
// Destruction
//----------------------------------------------------------------------
CTextWnd::~CTextWnd(void)
{
 if(m_hEventTimer != NULL)
 {
  CloseHandle(m_hEventTimer);
  m_hEventTimer = NULL;
 }

 if(m_DCTxtInfo.IsOK() == TRUE)
 {
  m_DCTxtInfo.Delete();
 }
}

 


//----------------------------------------------------------------------
//Description:
// Move the window
//----------------------------------------------------------------------
BOOL CTextWnd::Move(const RECT * prcWnd)
{
 return MoveWindow(GetWindow(),
      prcWnd->left,
      prcWnd->top,
      prcWnd->right - prcWnd->left,
      prcWnd->bottom - prcWnd->top,
      FALSE);
}

//----------------------------------------------------------------------
//Description:
// Set the text information.
// It would take effect in next calling Play().
//----------------------------------------------------------------------
BOOL CTextWnd::SetText(const TCHAR * pcszText)
{
 if(m_pszTxtInfo != NULL)
 {
  delete [] m_pszTxtInfo;
  m_pszTxtInfo = NULL;
 }

 m_pszTxtInfo = new TCHAR[_tcslen(pcszText) + 1];
 _tcscpy(m_pszTxtInfo,pcszText);


 //Set the flag to reinitialize the memory DC
 m_bInited = FALSE;

 return TRUE;
}


//----------------------------------------------------------------------
//Description:
// Set the text file path
//----------------------------------------------------------------------
BOOL CTextWnd::SetTxtPath(const TCHAR * pcszPath)
{

 if(pcszPath == NULL)
 {
  return FALSE;
 }

 m_FileStore.DeleteAllData();

 WIN32_FIND_DATA fd = {0};
 HANDLE hFind = FindFirstFile(pcszPath,&fd);
 if(hFind == INVALID_HANDLE_VALUE)
 {
  return FALSE;
 }
 
 if(fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
 {
  FindFile(pcszPath,&m_FileStore,CheckFile);
 }
 else
 {
  m_FileStore.Add(pcszPath);
 }

 FindClose(hFind);

 //Open the first text file 
 m_iIndexCurTxt = 0;
 ReadCurTxt();

 return TRUE;
}


//----------------------------------------------------------------------
//Description:
// Play the text. If first using, it would be very slow bacause must initialize the memory DC.
// It would be quickly next time when the setting has not changed since first using
//----------------------------------------------------------------------
BOOL CTextWnd::Play(void)
{
 if(m_DCTxtInfo.IsOK() == FALSE || m_bInited == FALSE)
 {
  //Create the memory DC for text information  
  InitDCTxtInfo();

  m_bInited = TRUE;
 }

 m_taCurAction = TA_MOVE;
 SetEvent(m_hEventTimer);

 return TRUE;
}


//----------------------------------------------------------------------
//Description:
// Pause the text
//----------------------------------------------------------------------
BOOL CTextWnd::Pause(void)
{
 m_taCurAction = TA_NULL;
 SetEvent(m_hEventTimer);

 return TRUE;
}


//----------------------------------------------------------------------
//Description:
// Check the file
//----------------------------------------------------------------------
BOOL CTextWnd::CheckFile(const TCHAR * pszFileName)
{
 TCHAR szSuffix[MAX_PATH] = {0};
 
 int iLen = _tcslen(pszFileName);
 if(iLen == 0)
 {
  return FALSE;
 }

 int iPos = iLen - 1;
 while(iPos >= 0)
 {
  if(pszFileName[iPos] == '.')
  {
   break;
  }

  iPos --;
 }

 if(iPos < 0)
 {
  return FALSE;
 }

 _tcscpy(szSuffix, pszFileName + iPos);
 _tcslwr(szSuffix);
 

 if(_tcscmp(szSuffix,TEXT(".txt")) == 0)
 {
  return TRUE;
 }

 return FALSE;
}


//----------------------------------------------------------------------
//Description:
// Read the text information base on the current index
//----------------------------------------------------------------------
BOOL CTextWnd::ReadCurTxt(void)
{
 if(m_iIndexCurTxt >= m_FileStore.GetAmount() || m_iIndexCurTxt < 0 || m_FileStore.GetAmount() == 0)
 {
  return FALSE;
 }

 if(m_pszTxtInfo != NULL)
 {
  delete [] m_pszTxtInfo;
  m_pszTxtInfo = NULL;
 }

 TCHAR szFile[MAX_PATH] = {0};
 if(m_FileStore.GetData(m_iIndexCurTxt,szFile,MAX_PATH) == TRUE)
 {
  HANDLE hFile = CreateFile(szFile,
         GENERIC_READ,
         FILE_SHARE_READ,
         NULL,
         OPEN_EXISTING,
         FILE_ATTRIBUTE_NORMAL,
         NULL);

  DWORD dwSize = GetFileSize(hFile,NULL);
  BYTE *pReadBuf = (BYTE*)malloc(dwSize);
  DWORD dwRead = 0;
  ReadFile(hFile,pReadBuf,dwSize,&dwRead,NULL);
#ifdef UNICODE
  if(dwSize >= 2 && pReadBuf[0] == 0xFF && pReadBuf[1] == 0xFE)
  {
   //It must be the UNICODE file
   DWORD dwNum = (dwSize - 2) / sizeof(TCHAR) + 1; //Must be end with '/0', so add 1
   m_pszTxtInfo = new TCHAR[dwNum];
   memset(m_pszTxtInfo,0,sizeof(TCHAR) * dwNum);
   if(m_pszTxtInfo != NULL)
   {
    _tcscpy(m_pszTxtInfo,reinterpret_cast<TCHAR *>(pReadBuf + 2));
   }   
   
  }
  else
  {
   //It must be the ASCII file
   DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, reinterpret_cast<char *>(pReadBuf), -1, NULL, 0);
   m_pszTxtInfo = new TCHAR[dwNum];
   memset(m_pszTxtInfo,0,sizeof(TCHAR) * dwNum);
   if(m_pszTxtInfo != NULL)
   {
    // Convert string from ASCII to Unicode.
    MultiByteToWideChar (CP_ACP, 0, reinterpret_cast<char *>(pReadBuf), -1, m_pszTxtInfo, dwNum);
   }   
  }
  
 
#else
 #error "There is not the completed code here when the UNICODE macor is not defined. :-("
#endif

  free(pReadBuf);

  CloseHandle(hFile);
 }

 
 

 return TRUE;
}

 

//----------------------------------------------------------------------
//Description:
//    Actual WndProc
//
//----------------------------------------------------------------------
LRESULT CTextWnd::WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
 switch(wMsg)
 {
  case WM_PAINT:
   OnPaint(hWnd,wMsg,wParam,lParam);
   return 0;
  case WM_ERASEBKGND:
   return 0;
  case WM_WINDOWPOSCHANGED:
   OnWindowPosChanged(hWnd,wMsg,wParam,lParam);
   break;
 }

 return CWndBase::WndProc(hWnd,wMsg,wParam,lParam);
}


//----------------------------------------------------------------------
//Description:
//    On message WM_PAINT
//
//----------------------------------------------------------------------
void CTextWnd::OnPaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{


 PAINTSTRUCT ps;
 HDC hdc = BeginPaint(hWnd,&ps);

 //Create the memory DC
 CMemDC memDC;
 SIZE size = {m_iWndWidth,m_iWndHeight};
 memDC.Create(hdc,&size);

 DrawBackground(memDC.GetDC());
 
 //Draw the text
 if(m_DCTxtInfo.IsOK() == TRUE)
 {
  TransparentBlt(memDC.GetDC(),
      m_iTxtInfoX,
      m_iTxtInfoY,
      m_iTxtInfoWidth,
      m_iTxtInfoHeight,
      m_DCTxtInfo.GetDC(),
      0,
      0,
      m_DCTxtInfo.GetWidth(),
      m_DCTxtInfo.GetHeight(),
      m_crBkColor);
 }
 

 //Draw the device context
 BitBlt(hdc,0,0,m_iWndWidth,m_iWndHeight,memDC.GetDC(),0,0,SRCCOPY);

 //Delete the memory DC
 memDC.Delete();
 
 EndPaint(hWnd,&ps);
}

 

//----------------------------------------------------------------------
//Description:
//    The timer thread
//
//----------------------------------------------------------------------
DWORD CTextWnd::TimerThread(PVOID pArg)
{
 CTextWnd *pObject = (CTextWnd *)pArg;

 

 while(TRUE)
 {
  if(WaitForSingleObject(pObject->m_hEventTimer,pObject->m_dwInterval) == WAIT_TIMEOUT)
  {
   if(pObject->m_taCurAction == TA_MOVE)
   {
    switch(pObject->m_dtValue)
    {
     case DRT_NULL:
     {
      //Do nothing
      break;
     }
     case DRT_LEFT:
     {
      pObject->m_iTxtInfoX -= pObject->m_iMovePixel;  
      if(pObject->m_iTxtInfoX + pObject->m_iTxtInfoWidth <= 0)
      {
       pObject->m_iTxtInfoX = pObject->m_iWndWidth;
      }
      break;
     }
     case DRT_RIGHT:
     {
      pObject->m_iTxtInfoX += pObject->m_iMovePixel; 
      if(pObject->m_iTxtInfoX >= pObject->m_iWndWidth)
      {
       pObject->m_iTxtInfoX =  - pObject->m_iTxtInfoWidth;
      }
      break;
     }
     case DRT_UP:
     {
      pObject->m_iTxtInfoY -= pObject->m_iMovePixel;
      if(pObject->m_iTxtInfoY + pObject->m_iTxtInfoHeight <= 0)
      {
       pObject->m_iTxtInfoY = pObject->m_iWndHeight;
      }
      break;
     }
     case DRT_DOWN:
     {
      pObject->m_iTxtInfoY += pObject->m_iMovePixel;
      if(pObject->m_iTxtInfoY >= pObject->m_iWndHeight)
      {
       pObject->m_iTxtInfoY = -pObject->m_iTxtInfoWidth;
      }
      break;
     }
    }
    
    //Redraw the text information
    InvalidateRect(pObject->GetWindow(),NULL,FALSE);     

   }
   else if(pObject->m_taCurAction == TA_EXIT)
   {
    break;
   }
   else if(pObject->m_taCurAction == TA_STOP)
   {
    switch(pObject->m_dtValue)
    {
     case DRT_NULL:
     {
      //Do nothing
      break;
     }
     case DRT_LEFT:
     {   
      pObject->m_iTxtInfoX = pObject->m_iWndWidth;   
      break;
     }
     case DRT_RIGHT:
     {
      pObject->m_iTxtInfoX =  - pObject->m_iTxtInfoWidth;   
      break;
     }
     case DRT_UP:
     {   
      pObject->m_iTxtInfoY = pObject->m_iWndHeight;  
      break;
     }
     case DRT_DOWN:
     {
      pObject->m_iTxtInfoY = -pObject->m_iTxtInfoWidth;    
      break;
     }
    }

    pObject->m_taCurAction = TA_NULL;
    InvalidateRect(pObject->GetWindow(),NULL,FALSE);
   }
  }
 }

 

 return 0;
}

//----------------------------------------------------------------------
//Description:
//    Set the direction for the text information displayed
//
//----------------------------------------------------------------------
void CTextWnd::SetDirection(DirectionValue dtValue)
{
 if(m_dtValue == dtValue)
 {
  //Do nothing
  return;
 }

 m_dtValue = dtValue;

}
//----------------------------------------------------------------------
//Description:
//    Set the interval for text moving
//
//----------------------------------------------------------------------
void CTextWnd::SetInterval(DWORD dwInterval)
{
 m_dwInterval = dwInterval;
}


//----------------------------------------------------------------------
//Description:
// Create the window
//
//Parameters:
// You should see the explanation of the parameters in CWndBase
//
//----------------------------------------------------------------------
BOOL CTextWnd::Create(HINSTANCE hInst, HWND hWndParent, const TCHAR *pcszWndClass, const TCHAR *pcszWndName,BOOL bMsgThrdInside)
{
 if(CWndBase::Create(hInst,hWndParent,pcszWndClass,pcszWndName,bMsgThrdInside) == FALSE)
 {
  return FALSE;
 }

 //Get the window area
 RECT rcWnd = {0};
 GetWindowRect(GetWindow(),&rcWnd);
 m_iWndWidth = rcWnd.right - rcWnd.left;
 m_iWndHeight = rcWnd.bottom - rcWnd.top;

 return TRUE;
}

//----------------------------------------------------------------------
//Description:
// On message WM_WINDOWPOSCHANGED
//
//----------------------------------------------------------------------
void CTextWnd::OnWindowPosChanged(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
 //Get the window area
 WINDOWPOS wp = *((WINDOWPOS *) lParam);
 
 if(m_iWndWidth != wp.cx || m_iWndHeight != wp.cy)
 {
  m_iWndWidth = wp.cx;
  m_iWndHeight = wp.cy;

  //Set the flag to reinitialize the memory DC
  m_bInited = FALSE;
  
 }

 

}


//----------------------------------------------------------------------
//Description:
// Caculate the text informat rectangle.
//
//----------------------------------------------------------------------
BOOL CTextWnd::ResetTxtInfoRect(void)
{
 HWND hWnd = GetWindow();
 if(hWnd == NULL || m_pszTxtInfo == NULL)
 {
  return FALSE;
 }


 
 HDC hdc = GetDC(hWnd); 
 
 //Set the font to caculate
 LOGFONT lf = {0};
 HFONT hFontNew, hFontOld;
 lf.lfQuality = CLEARTYPE_QUALITY;
 lf.lfCharSet = DEFAULT_CHARSET;
 lf.lfHeight = -1 * (m_iTxtInfoPointSize * GetDeviceCaps(hdc,LOGPIXELSY) / 72);
 lf.lfWeight = m_iTxtInfoWeight;
 
 //Create the new font
 hFontNew = CreateFontIndirect(&lf);
 hFontOld = (HFONT) SelectObject(hdc, hFontNew);

 //Get the size of the string
 SIZE size = {0};
 GetTextExtentPoint(hdc,m_pszTxtInfo,_tcslen(m_pszTxtInfo),&size);

 //Restore the font
 SelectObject(hdc, hFontOld);
 DeleteObject(hFontNew);
 
 ReleaseDC(hWnd,hdc);

 

 if(m_dtValue == DRT_NULL)
 {
  m_iTxtInfoWidth = m_iWndWidth;
  m_iTxtInfoHeight = m_iWndHeight;
 }
 else if(m_dtValue == DRT_LEFT || m_dtValue == DRT_RIGHT)
 {
  m_iTxtInfoWidth = size.cx;
  m_iTxtInfoHeight = size.cy;
 }
 else if(m_dtValue == DRT_UP || m_dtValue == DRT_DOWN)
 {
  //Get the amount of the "/n"
  TCHAR *pFind = m_pszTxtInfo;
  int iCountLine = 1;
  while(TRUE)
  {
   pFind = _tcsstr(pFind,TEXT("/n"));
   
   if(pFind != NULL)
   {
    pFind += 1;
    iCountLine ++;
   }
   else
   {
    break;
   }
  }

  m_iTxtInfoWidth = m_iWndWidth;
  m_iTxtInfoHeight = size.cy * iCountLine;

 }

 //The begin position of X and Y
 switch(m_dtValue)
 {
  case DRT_NULL:
   m_iTxtInfoX = (m_iWndWidth - m_iTxtInfoWidth) / 2;
   m_iTxtInfoY = (m_iWndHeight - m_iTxtInfoHeight) / 2;
   break;
  case DRT_LEFT:
   m_iTxtInfoX = m_iWndWidth;
   m_iTxtInfoY = (m_iWndHeight - m_iTxtInfoHeight) / 2;
   break;
  case DRT_RIGHT:
   m_iTxtInfoX = -m_iTxtInfoWidth;
   m_iTxtInfoY = (m_iWndHeight - m_iTxtInfoHeight) / 2;
   break;
  case DRT_UP:
   m_iTxtInfoX = (m_iWndWidth - m_iTxtInfoWidth) / 2;
   m_iTxtInfoY = m_iWndHeight;
   break;
  case DRT_DOWN:
   m_iTxtInfoX = (m_iWndWidth - m_iTxtInfoWidth) / 2;
   m_iTxtInfoY = -m_iTxtInfoHeight;
   break;
 }

 return TRUE;
}

//----------------------------------------------------------------------
//Description:
// Draw the background
//
//----------------------------------------------------------------------
void CTextWnd::DrawBackground(HDC hdc)
{

 //Create the pen
 HPEN hPen = CreatePen(PS_SOLID,1,m_crBkColor);
 HPEN hOldPen = NULL;
 hOldPen = (HPEN)SelectObject(hdc,hPen);
 
 //the rect color
 HBRUSH hBrush = CreateSolidBrush(m_crBkColor);
 HGDIOBJ hOldBrush = SelectObject(hdc,hBrush);
 
 //Draw
 Rectangle(hdc,0,0,m_iWndWidth + 1, m_iWndHeight + 1);
 
 //Realse the resource
 SelectObject(hdc,hOldBrush);
 DeleteObject(hBrush);
 SelectObject(hdc,hOldPen);
 DeleteObject(hPen);

 
}

 

//----------------------------------------------------------------------
//Description:
// Initialize the memory DC for storing the current text information
//
//----------------------------------------------------------------------
BOOL CTextWnd::InitDCTxtInfo(void)
{
 if(ResetTxtInfoRect() == FALSE)
 {
  return FALSE;
 }

 HDC hdc = GetDC(GetWindow());

 //If existing the memory DC, delete it.
 m_DCTxtInfo.Delete();

 //Create the memory DC
 SIZE size = {m_iTxtInfoWidth,m_iTxtInfoHeight};
 m_DCTxtInfo.Create(hdc,&size);

 //Draw the background with the transparent color
 HPEN hPen = CreatePen(PS_SOLID,1,m_crBkColor);
 HPEN hOldPen = NULL;
 hOldPen = (HPEN)SelectObject(m_DCTxtInfo.GetDC(),hPen);
 //the rect color
 HBRUSH hBrush = CreateSolidBrush(m_crBkColor);
 HGDIOBJ hOldBrush = SelectObject(m_DCTxtInfo.GetDC(),hBrush);
 //Draw
 Rectangle(m_DCTxtInfo.GetDC(),0,0,m_iTxtInfoWidth + 1, m_iTxtInfoHeight + 1);
 //Realse the resource
 SelectObject(m_DCTxtInfo.GetDC(),hOldBrush);
 DeleteObject(hBrush);
 SelectObject(m_DCTxtInfo.GetDC(),hOldPen);
 DeleteObject(hPen);
 
 //Set the background mode
 ::SetBkMode(m_DCTxtInfo.GetDC(),TRANSPARENT);

 //Draw the text
 RECT rcDraw = {0, 0, m_iTxtInfoWidth, m_iTxtInfoHeight};
 UINT uFormat = 0;
 switch(m_dtValue)
 {
  case DRT_NULL:
   uFormat = DT_LEFT | DT_TOP | DT_WORDBREAK;
   break;
  case DRT_LEFT:
   uFormat = DT_VCENTER | DT_SINGLELINE | DT_LEFT;
   break;
  case DRT_RIGHT:
   uFormat = DT_VCENTER | DT_SINGLELINE | DT_RIGHT;
   break;
  case DRT_UP:
  case DRT_DOWN:
   uFormat = DT_CENTER | DT_WORDBREAK;
   break;
 }

 //Set the text color
 COLORREF crOldTextColor = ::SetTextColor(m_DCTxtInfo.GetDC(),m_crTxtInfoColor);

 //Set the font to caculate
 LOGFONT lf = {0};
 HFONT hFontNew, hFontOld;
 lf.lfQuality = CLEARTYPE_QUALITY;
 lf.lfCharSet = DEFAULT_CHARSET;
 lf.lfHeight = -1 * (m_iTxtInfoPointSize * GetDeviceCaps(m_DCTxtInfo.GetDC(),LOGPIXELSY) / 72);
 lf.lfWeight = m_iTxtInfoWeight;
 
 //Create the new font
 hFontNew = CreateFontIndirect(&lf);
 hFontOld = (HFONT) SelectObject(m_DCTxtInfo.GetDC(), hFontNew);

 if(m_dtValue == DRT_RIGHT)
 {
  //Reverse the string
  int iLen = _tcslen(m_pszTxtInfo);
  TCHAR *pszReverse = new TCHAR[iLen + 1];
  for(int i = 0; i < iLen; i ++)
  {
   pszReverse[i] = m_pszTxtInfo[iLen - i - 1];
  }
  pszReverse[iLen] = '/0';

  DrawText(m_DCTxtInfo.GetDC(),pszReverse,-1,&rcDraw,uFormat);

  delete []pszReverse;
 }
 else
 {
  DrawText(m_DCTxtInfo.GetDC(),m_pszTxtInfo,-1,&rcDraw,uFormat);
 }

 //Restore the font
 SelectObject(m_DCTxtInfo.GetDC(), hFontOld);
 DeleteObject(hFontNew);

 //Restore the color
 ::SetTextColor(m_DCTxtInfo.GetDC(),crOldTextColor);

 ReleaseDC(GetWindow(),hdc);

 return TRUE;
 
}

//----------------------------------------------------------------------
//Description:
// Set the move distance once, base on pixel.
//
//----------------------------------------------------------------------
void CTextWnd::SetMovePixel(int iPixel)
{
 m_iMovePixel = iPixel;
}


//----------------------------------------------------------------------
//Description:
// Set the text color. Don't set the same color with the background.
// It would take effect in next calling Play().
//
//----------------------------------------------------------------------
void CTextWnd::SetTxtColor(COLORREF crColor)
{
 m_crTxtInfoColor = crColor;

 //Set the flag to reinitialize the memory DC
 m_bInited = FALSE;
 
}

//----------------------------------------------------------------------
//Description:
// Set the text point size.
// It would take effect in next calling Play().
//
//----------------------------------------------------------------------
void CTextWnd::SetTxtPointSize(int iPointSize)
{
 m_iTxtInfoPointSize = iPointSize;

 //Set the flag to reinitialize the memory DC
 m_bInited = FALSE;
}

//----------------------------------------------------------------------
//Description:
// Set the text weight. See LOGFONT for a list of value.
// It would take effect in next calling Play().
//
//----------------------------------------------------------------------
void CTextWnd::SetTxtWeight(int iWeight)
{
 m_iTxtInfoWeight = iWeight;

 //Set the flag to reinitialize the memory DC
 m_bInited = FALSE;
}

//----------------------------------------------------------------------
//Description:
// Set the color for the background of window
//
//----------------------------------------------------------------------
void CTextWnd::SetBkColor(COLORREF crColor)
{
 m_crBkColor = crColor;
}

//----------------------------------------------------------------------
//Description:
// Switch to next image
//----------------------------------------------------------------------
BOOL CTextWnd::SwitchNext(void)
{
 if(m_FileStore.GetAmount() == 0)
 {
  return FALSE;
 }

 m_iIndexCurTxt ++;
 if(m_iIndexCurTxt >= m_FileStore.GetAmount())
 {
  m_iIndexCurTxt = 0;
 }

  
 ReadCurTxt();

 return TRUE;
}

//----------------------------------------------------------------------
//Description:
// Switch to previous image
//----------------------------------------------------------------------
BOOL CTextWnd::SwitchPrevious(void)
{
 if(m_FileStore.GetAmount() == 0)
 {
  return FALSE;
 }

 m_iIndexCurTxt --;
 if(m_iIndexCurTxt < 0 )
 {
  m_iIndexCurTxt = m_FileStore.GetAmount() - 1;
 }

  
 ReadCurTxt();

 return TRUE;
}

 


//---------------------------------------------------------------------
//Description:
// Find the file in the specified directory
//
//Parameters:
// pszPath : [in] The path to find file
// pStore : [in] The buffer for storing the file path
// pCheckFunc : [in] Pointer to the function for checking the file
//---------------------------------------------------------------------
BOOL CTextWnd::FindFile(const TCHAR *pszPath,CStrStore *pStore,BOOL (*pCheckFunc)(const TCHAR *pcszPath))
{
 if(_tcslen(pszPath) >= MAX_PATH || pszPath == NULL || pStore == NULL || pCheckFunc == NULL)
 {
  return FALSE;
 }

 
 TCHAR szFindDir[MAX_PATH] = {0};
 _tcscpy(szFindDir,pszPath);
 //the last 4 elememts must be like as "/*.*"
 ULONG ulLen = _tcslen(szFindDir);
 if(ulLen != 0 && szFindDir[ulLen - 1]=='//')
 {
  _tcscat(szFindDir,TEXT("*.*"));
 } 
 else
 {
  _tcscat(szFindDir,TEXT("//*.*"));
 }


 WIN32_FIND_DATA fd;
 HANDLE hFind;
 hFind=FindFirstFile(szFindDir,&fd);
 if(hFind != INVALID_HANDLE_VALUE)
 {
  do{
   if(fd.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
   {  
    //it must be directory
    TCHAR szNextDir[MAX_PATH] = {0};
    _tcscpy(szNextDir,pszPath);
    ULONG ulLenNext = _tcslen(pszPath);
    if(ulLenNext != 0 && szNextDir[ulLenNext - 1] != '//')
    {
     _tcscat(szNextDir,TEXT("//"));
    }
    _tcscat(szNextDir,fd.cFileName);
    FindFile(szNextDir,pStore,pCheckFunc);
   }
   else
   { 
    //it is file
    
    if((*pCheckFunc)(fd.cFileName) == TRUE)
    {
     TCHAR szPathFile[MAX_PATH] = {0};
     _tcscpy(szPathFile,pszPath);
     ULONG ulLenFile = _tcslen(szPathFile);
     if(ulLenFile != 0 && szPathFile[ulLenFile - 1] != '//')
     {
      _tcscat(szPathFile,TEXT("//"));
     }
     _tcscat(szPathFile,fd.cFileName);
     pStore->Add(szPathFile);
    }
    
   }
  }while(FindNextFile(hFind,&fd));
 }
 FindClose(hFind);

 return TRUE;
}

//---------------------------------------------------------------------
//Description:
// Stop playing
//
//---------------------------------------------------------------------
BOOL CTextWnd::Stop(void)
{
 m_taCurAction = TA_STOP;
 SetEvent(m_hEventTimer);

 return TRUE;
}


    在CTextWnd中还用到了三个类,分别是CMemDC、CWndBase和CStrStore,其作用依次是创建内存DC、父类窗口和存储文件路径。
   
    CWndBase的相关信息可参考这边文章: http://blog.csdn.net/norains/archive/2007/11/10/1878218.aspx
   
    CMemDC和CStrStore的代码比较简单,没有什么难点需要描述的,其代码分别如下:
   
   
    CMemDC:

///////////////////////////////////////////////////////////////////// /
//  MemDC.h: interface for the CCommon class.
//
// Version:
//     0.1.0
// Date:
//     2008.02.20
///////////////////////////////////////////////////////////////////// /

#pragma  once

class  CMemDC
{
public :
    CMemDC(
void );
    
~ CMemDC( void );

    BOOL Create(HDC hdc, 
const  SIZE  * pSize);
    BOOL Delete(
void );
    HDC GetDC(
void );
    LONG GetWidth(
void );
    LONG GetHeight(
void );
    BOOL IsOK(
void );


private :
    HDC m_hdcMem;
    HBITMAP m_hBitmap;
    HGDIOBJ m_hOldSel;
    SIZE m_Size;

    
};


///////////////////////////////////////////////////////////////////// /
//  MemDC.cpp
//
///////////////////////////////////////////////////////////////////// /
#include  " stdafx.h "
#include 
" MemDC.h "

// ----------------------------------------------------------------------
// Description:
//     Construction
// -----------------------------------------------------------------------
CMemDC::CMemDC( void ):
m_hdcMem(NULL),
m_hBitmap(NULL),
m_hOldSel(NULL)
{
    memset(
& m_Size, 0 , sizeof (m_Size));
}

// ----------------------------------------------------------------------
// Description:
//     Destruction
// -----------------------------------------------------------------------
CMemDC:: ~ CMemDC( void )
{
}


// ----------------------------------------------------------------------
// Description:
//     Create the memory DC. After succeed in calling the function ,you should
// call Delete() to release resource.
//
// Parameters:
//     hdc : [in] Handle to an existing device context. 
//     pSize : [in] The size of the memory DC to create.
//         If NULL, the function uses the screen size.
// -----------------------------------------------------------------------
BOOL CMemDC::Create(HDC hdc,  const  SIZE  * pSize)
{
    BOOL bResult 
=  FALSE;

    
if (hdc  ==  NULL  ||  m_hdcMem  !=  NULL)
    {
        
goto  EXIT;
    }

    
if (pSize  !=  NULL)
    {
        m_Size 
=   * pSize;
    }
    
else
    {
        m_Size.cx 
=  GetSystemMetrics(SM_CXSCREEN);
        m_Size.cy 
=  GetSystemMetrics(SM_CYSCREEN);
    }

    
// Create a DC that matches the device
    m_hdcMem  =  CreateCompatibleDC(hdc);
    
if (m_hdcMem  ==  NULL)
    {
        
goto  EXIT;
    }

    m_hBitmap 
=  CreateCompatibleBitmap(hdc,m_Size.cx,m_Size.cy);
    
if (m_hBitmap  ==  NULL)
    {
        
goto  EXIT;
    }

    
// Select the bitmap into to the compatible device context
    m_hOldSel  =  SelectObject(m_hdcMem,m_hBitmap);

    bResult 
=  TRUE;

EXIT:
    
if (bResult  ==  FALSE)
    {
        DeleteObject(m_hBitmap);
        m_hBitmap 
=  NULL;
        
        DeleteDC(m_hdcMem);
        m_hdcMem 
=  NULL;
    }

    
return  bResult;
}



// ----------------------------------------------------------------------
// Description:
//     Delete the memory DC
//
// -----------------------------------------------------------------------
BOOL CMemDC::Delete( void )
{
    
if (m_hdcMem  ==  NULL  ||  m_hOldSel  ==  NULL  ||  m_hBitmap  ==  NULL)
    {
        
return  FALSE;
    }

    
// Restore original bitmap selection and destroy the memory DC
    SelectObject(m_hdcMem,m_hOldSel);
    DeleteObject(m_hBitmap);    
    DeleteDC(m_hdcMem);

    m_hdcMem 
=  NULL;
    m_hOldSel 
=  NULL;
    m_hBitmap 
=  NULL;

    memset(
& m_Size, 0 , sizeof (m_Size));

    
return  TRUE;
}


// ----------------------------------------------------------------------
// Description:
//     Get the handle of the memory DC. You COULDN'T release the DC by window api funtion ReleaseDC() !
// Instead, you should call CMemDC::Delete().
//     Null incdicates failed
//
// -----------------------------------------------------------------------
HDC CMemDC::GetDC( void )
{
    
return  m_hdcMem;
}

// ----------------------------------------------------------------------
// Description:
//     Get the width of the memory DC
//
// -----------------------------------------------------------------------
LONG CMemDC::GetWidth( void )
{
    
return  m_Size.cx;
}

// ----------------------------------------------------------------------
// Description:
//     Get the height of the memory DC
//
// -----------------------------------------------------------------------
LONG CMemDC::GetHeight( void )
{
    
return  m_Size.cy;
}

// ----------------------------------------------------------------------
// Description:
//     Check the memory DC. 
//
// Parameters:
//     NULL
//
// Return Values:
//     TRUE - ready.
//     FALSE - Not ready.
//
// -----------------------------------------------------------------------
BOOL CMemDC::IsOK( void )
{
    
return  (m_hdcMem  !=  NULL);
}

    CStrStore:   
///////////////////////////////////////////////////////////////////// /
//  StrStore.h: interface for the CStrStore class.
//
// Version:
//     1.0.0
// Date:
//     2008.02.26
///////////////////////////////////////////////////////////////////// /

#pragma  once



// -----------------------------------------------------------------------
class  CStrStore  
{
public :
    
int  GetDataLength( int  iIndex);
    
int  FindData( const  TCHAR  * pcszFind);
    BOOL GetData(
int  iIndex,TCHAR  * pszOut,  int  iSize);
    
int  GetAmount();
    
void  DeleteAllData();
    BOOL Add(
const  TCHAR  *  pszIn);
    CStrStore();
    
virtual   ~ CStrStore();
protected :

    typedef 
struct  _StoreData
    {
        TCHAR 
* pszString;
        _StoreData 
* pNextData;
    }STOREDATA,
* PSTOREDATA;
    PSTOREDATA m_pFirstData;
    PSTOREDATA m_pEndData;

    
int  m_iAmount;

};


///////////////////////////////////////////////////////////////////// /
//  StrStore.cpp: implementation of the CStrStore class.
//
///////////////////////////////////////////////////////////////////// /

#include 
" stdafx.h "
#include 
" StrStore.h "

///////////////////////////////////////////////////////////////////// /
//  Construction/Destruction
///////////////////////////////////////////////////////////////////// /

CStrStore::CStrStore()
{
    m_pFirstData 
=  NULL;
    m_pEndData 
=  NULL;
    m_iAmount 
=   0 ;
}

CStrStore::
~ CStrStore()
{
    DeleteAllData();
}


// ----------------------------------------------------------------------
// Description:
//     Add the TCHAR string
// ----------------------------------------------------------------------
BOOL CStrStore::Add( const  TCHAR  *  pszIn)
{
    PSTOREDATA pNewData 
=   new  STOREDATA();
    
    
if (pNewData  ==  NULL)
    {
        
return  FALSE;
    }

    
int  iLen  =  _tcslen(pszIn);
    pNewData
-> pszString  =   new  TCHAR [iLen  +   1 ];
    
if (pNewData -> pszString  ==  NULL)
    {
        delete pNewData;
        
return  FALSE;
    }
    _tcscpy(pNewData
-> pszString,pszIn);
    
    
    pNewData
-> pNextData  =  NULL;

    
if (m_pFirstData  ==  NULL)
    {
        m_pFirstData 
=  pNewData;
    }
    
else
    {
        m_pEndData
-> pNextData  =  pNewData;
    }

    m_pEndData 
=  pNewData;

    m_iAmount 
++ ;

    
return  TRUE;
}


// ----------------------------------------------------------------------
// Description:
//     Delete all the stored data
// ----------------------------------------------------------------------
void  CStrStore::DeleteAllData()
{
    
if (m_pFirstData  ==  NULL)
    {
        
return  ;
    }

    PSTOREDATA pDeleteData 
=  m_pFirstData;

    
while (m_pFirstData -> pNextData  !=  NULL)
    {
        m_pFirstData 
=  m_pFirstData -> pNextData;

        delete []pDeleteData
-> pszString;
        delete pDeleteData;
        
        pDeleteData 
=  m_pFirstData;
    }

    
// Delete the last one
    delete pDeleteData;

    m_pFirstData 
=  NULL;
    m_pEndData 
=  NULL;

    m_iAmount 
=   0 ;
}


// ----------------------------------------------------------------------
// Description:
//     Get the amount
// ----------------------------------------------------------------------
int  CStrStore::GetAmount()
{
    
return  m_iAmount;
}


// ----------------------------------------------------------------------
// Description:
//     Get the data base on the index. And the begin index is 0.
// ----------------------------------------------------------------------
BOOL CStrStore::GetData( int  iIndex, TCHAR  * pszOut,  int  iSize)
{
    
if (iIndex  <   0   ||  iIndex  >=  m_iAmount  ||  pszOut  ==  NULL)
    {
        
return  FALSE;
    }

    
int  iCount  =   0 ;
    PSTOREDATA pData 
=  m_pFirstData;

    
while (iCount  !=  iIndex)
    {
        pData 
=  pData -> pNextData;
        iCount 
++ ;
    }

    
int  iLen  =  _tcslen(pData -> pszString);
    
    
if (iSize  <  iLen  +   1 )
    {
        
return  FALSE;
    }

    _tcscpy(pszOut,pData
-> pszString);


    
return  TRUE;
}


// ----------------------------------------------------------------------
// Description:
//     Find the string data and return the index in the storage.
//
// Parameters:
//     pcszFind: [in] The string to find
//
// Return Values:
//     -1 : failed
//     others: succeed.
// ----------------------------------------------------------------------
int  CStrStore::FindData( const  TCHAR  * pcszFind)
{
    
int  iIndexFind  =   0 ;


    PSTOREDATA pData 
=  m_pFirstData;

    
while (iIndexFind  <  m_iAmount)
    {
        
if (_tcscmp(pData -> pszString,pcszFind)  ==   0 )
        {
            
break ;
        }

        pData 
=  pData -> pNextData;
        iIndexFind 
++ ;
    }

    
if (iIndexFind  >=  m_iAmount)
    {
        
// Failed in finding the string
        iIndexFind  =   - 1 ;
    }

    
return  iIndexFind;
}


// ----------------------------------------------------------------------
// Description:
//     Get the length of the string data base on the index. And the begin index is 0.
//
// Parameters:
//     iIndex : [in] The index in the stored data,and it's base on 0.
//
// Return Values:
//     -1 : failed
//     others: succeed.
// ----------------------------------------------------------------------
int  CStrStore::GetDataLength( int  iIndex)
{
    
if (iIndex  <   0   ||  iIndex  >=  m_iAmount)
    {
        
return   - 1 ;
    }

    
int  iCount  =   0 ;
    PSTOREDATA pData 
=  m_pFirstData;

    
while (iCount  !=  iIndex)
    {
        pData 
=  pData -> pNextData;
        iCount 
++ ;
    }

    
return   _tcslen(pData -> pszString);

}

  
    既然前戏已经过完,那么我们开始来干正活吧。 :-)
   
    如果我们想创建一个窗口,该窗口的文字有下往上滚动,则代码可以如此:
int  WINAPI WinMain(    HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR    lpCmdLine,
                    
int        nCmdShow)
{
     
//  TODO: Place code here.

    CTextWnd txtWnd;
    txtWnd.Create(hInstance,NULL,TEXT(
" TextWnd " ),TEXT( " TextWnd " ));
    txtWnd.SetDirection(DRT_UP);
    txtWnd.SetText(TEXT(
" 向上滚动第二行信息 " ));
    txtWnd.Play();
    txtWnd.ShowWindow(TRUE);

    MSG msg;
    
while (GetMessage( & msg,NULL, 0 , 0 ))
    {
        TranslateMessage(
& msg);
        DispatchMessage(
& msg);
    }

    
return   0 ;
}


   
    一个滚动窗口就出来了,是不是很简单?
   
    最后,我们来看看CTextWnd一些常用的函数:
   
   
    1.Create(HINSTANCE hInst, HWND hWndParent, const TCHAR *pcszWndClass, const TCHAR *pcszWndName,BOOL bMsgThrdInside = FALSE)
      在使用之前都必须创建一个窗口。
     
    2.SetText(const TCHAR * pcszText)
      设置显示的文本
     
    3.SetDirection(DirectionValue dtValue)
      设置文字的滚动方向,取值有五种:DRT_NULL,DRT_LEFT,DRT_RIGHT,DRT_UP,DRT_DOWN,其含义和字面意义一致。
     
    4.SetInterval(DWORD dwInterval)
      设置移动的时间间隔,默认为100ms
     
    5.SetMovePixel(int iPixel)
      设置每次移动的像素,默认为1
     
    6.SetTxtPath(const TCHAR * pcszPath)
      设置读取的文件名或文件夹。如果所给的路径为文件夹,则该函数默认将读取第一个文件,但可以通过调用SwitchNext和SwitchPrevious切换不同的文件。
      
   7.Play(void)
     开始播放。
    
     这里还有个函数需要留意的,CTextWnd会调用DrawBackground进行背景的绘制。因为在实际使用中,往往需要实现透明的效果或是绘制其它的背景画面,这时候只要创建一个派生自CTextWnd的类,然后重载DrawBackground函数即可。

    该文的例子可在此下载:http://download.csdn.net/source/362836