Introduction
This article explains how to scroll text on a fixed image background in VC++ 6.0. I have searched the internet but could not find any simple article on this. So, I started experimenting on this and finally found a solution. Well, I have tested this on WinXP only.
Although the primary aim of this article is to display scrolling text on fixed background, it also covers how to draw a background with a bitmap brush.
Create an MFC Doc/View Project
Create an MFC doc/view project and select CScrollView
as the base view class. We have selected CScrollView
as base for our view class because it handles all the scrolling stuff. Now add a bitmap resource which you want as window background. Now create a CBitmap
variable to load your bitmap resource in your frame window class.
class CMainFrame : public CFrameWnd
{
protected:
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
.
.
.
CBitmap m_bmBG;
In the PreCreateWindow()
virtual function, change the extended style as follows:
cs.dwExStyle |= WS_EX_COMPOSITED;
WS_EX_COMPOSITED
is an Windows extended style and MSDN says that this style makes painting all descendants of a window in bottom-to-top painting order using double-buffering. It will serve our purpose. In OnCreate()
handler function, load our bitmap.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
.
.
m_bmBG.LoadBitmap(IDB_BITMAP1);
return 0;
}
Add WM_ERASEBKGND
Windows message handler. Here, we will be creating pattern brush from our bitmap and select it into the device context and fill the client area. The code looks like this:
BOOL CMainFrame::OnEraseBkgnd(CDC* pDC)
{
CBrush hbr,*phbrOld;
CRect rect;
hbr.CreatePatternBrush(&m_bmBG);
phbrOld= pDC->SelectObject(&hbr);
GetClientRect(&rect);
pDC->FillRect(&rect,&hbr);
pDC->SelectObject(phbrOld);
hbr.DeleteObject();
return TRUE;
}
Don't forget to add the following line in Mainfrm.h:
#define WS_EX_COMPOSITED 0x02000000L
In the view class handle WM_CREATE
message and in the handler, add the following code:
int CTransscrollView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CScrollView::OnCreate(lpCreateStruct) == -1)
return -1;
CClientDC dc(this);
m_ftTimes.CreatePointFont(500,"Times New Roman",&dc);
CFont *pOldFont;
pOldFont = dc.SelectObject(&m_ftTimes);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
m_nLineHt = tm.tmHeight + tm.tmExternalLeading;
dc.SelectObject(pOldFont);
return 0;
}
We have created 50 point Times New Roman font and selected into our client dc
. Calculate the line height and store it. Don't forget to create CFont m_ftTimes
and int m_nLineHt
class variables. Now handle WM_ERASEBKGND
message. Just return TRUE
in the message handler. Change the OnInitialUpdate()
function, change the code.
void CTransscrollView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
sizeTotal.cx = 500;
sizeTotal.cy = 25 * m_nLineHt;
SetScrollSizes(MM_TEXT, sizeTotal);
}
We are going to display 25 lines. We are creating a view large enough to show these lines.
In OnDraw()
, we are going to draw only those lines which will become visible when scrolling. Initially all the lines will be drawn.
void CTransscrollView::OnDraw(CDC* pDC)
{
CTransscrollDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CFont *pOldFont;
int ct;
pDC->SetBkMode(TRANSPARENT);
int start = GetDeviceScrollPosition().y /m_nLineHt -1;
if (start < 0) start =0;
CRect rcClient;
GetClientRect(&rcClient);
ct = start + rcClient.Height()/m_nLineHt + 3;
if( ct > 25) ct=25;
pOldFont = pDC->SelectObject(&m_ftTimes);
pDC->SetTextColor(RGB(255,12,146));
for(int i=start;i<ct;i++)
{
CString s;
s.Format("I am line %d on a fixed background",i+1);
pDC->TextOut(0,i * m_nLineHt,s);
}
pDC->SelectObject(pOldFont);
}
As we know on scrolling, ScrollWindow()
scrolls the window contents, we need to draw only the lines that come to visibility. So we have calculated the starting line number and the ending line that will be visible. We have drawn only those lines. Note that initially all lines will be drawn.
Enjoy.
History
- 9th October, 2008: Initial post