在Visual C++ 6.0中创建一个具有固定背景图像的滚动文本视图是一个有趣的挑战。本文将指导如何通过MFC框架实现这一功能。请注意,本教程仅在Windows XP操作系统上进行了测试。
首先,需要创建一个MFC文档/视图项目,并选择CScrollView
作为基础视图类。这是因为CScrollView
类能够处理所有的滚动逻辑。接下来,添加一个想要作为窗口背景的位图资源。然后在框架窗口类中创建一个CBitmap
变量来加载位图资源。
class CMainFrame : public CFrameWnd {
protected:
// 仅通过序列化创建
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
CBitmap m_bmBG;
};
在PreCreateWindow()
虚函数中,需要改变窗口的扩展样式,以便使用双缓冲技术进行绘制。
cs.dwExStyle |= WS_EX_COMPOSITED;
WS_EX_COMPOSITED
是一个Windows扩展样式,它使得窗口的所有子窗口按照从下到上的顺序进行绘制,这正是所需要的。
在OnCreate()
处理函数中,加载位图资源。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_bmBG.LoadBitmap(IDB_BITMAP1);
return 0;
}
在这里,将从位图创建一个图案画刷,并将其选择到设备上下文中,然后填充客户区域。
BOOL CMainFrame::OnEraseBkgnd(CDC* pDC) {
CBrush hbr, *phbrOld;
CRect rect;
hbr.CreatePatternBrush(&m_bmBG);
phbrOld = pDC->SelectObject(&hbr);
GetClientRect(▭);
pDC->FillRect(▭, &hbr);
pDC->SelectObject(phbrOld);
hbr.DeleteObject();
return TRUE;
}
不要忘记在Mainfrm.h
中添加以下行:
#define WS_EX_COMPOSITED 0x02000000L
在视图类中处理WM_CREATE
消息,并在处理函数中添加以下代码:
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;
}
创建了一个50点的Times New Roman字体,并将其选择到客户端设备上下文中。计算行高并存储它。不要忘记创建CFont m_ftTimes
和int m_nLineHt
类变量。
只需在消息处理函数中返回TRUE
。
在OnInitialUpdate()
函数中,改变代码以创建足够大的视图以显示25行文本。
void CTransscrollView::OnInitialUpdate() {
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: 计算此视图的总大小
sizeTotal.cx = 500;
sizeTotal.cy = 25 * m_nLineHt;
SetScrollSizes(MM_TEXT, sizeTotal);
}
在OnDraw()
中,只绘制当滚动时变得可见的那些行。最初,所有行都会被绘制。
void CTransscrollView::OnDraw(CDC* pDC) {
CTransscrollDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: 在此处添加原生数据的绘制代码
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);
}
如所知,在滚动时,ScrollWindow()
会滚动窗口内容,只需要绘制那些变得可见的行。已经计算了起始行号和将要可见的结束行号。只绘制了这些行。请注意,最初所有行都会被绘制。