Click here to Skip to main content
15,894,303 members
Articles / Desktop Programming / MFC
Article

Scroll with Fixed Background

Rate me:
Please Sign up or sign in to vote.
3.53/5 (10 votes)
9 Oct 2008CPOL2 min read 34.6K   1.1K   9  
Scrolling text with background image fixed in MFC

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.

Image 1

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.

C++
class CMainFrame : public CFrameWnd
{
	protected: // create from serialization only
	CMainFrame();
	DECLARE_DYNCREATE(CMainFrame)

	.
	.
	.
	CBitmap m_bmBG;

In the PreCreateWindow() virtual function, change the extended style as follows:

C++
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.

C++
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:

C++
BOOL CMainFrame::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	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:

C++
#define WS_EX_COMPOSITED 0x02000000L

In the view class handle WM_CREATE message and in the handler, add the following code:

C++
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.

C++
void CTransscrollView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	// TODO: calculate the total size of this view
	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.

C++
void CTransscrollView::OnDraw(CDC* pDC)
{
	CTransscrollDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Valuelabs
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --