CScrollCtrl:一个自动滚动的文本控件






3.83/5 (8投票s)
显示带徽标和图案背景的自动滚动文本。适用于关于对话框、杂项内容。
CScrollerCtrl 测试应用程序,在 Windows XP 下运行。
目录
- 动机
- 描述
- 特点
- 用途
- 演示
- CScrollerTestDlg::OnInitDialog()
- CTipsDialog::OnInitDialog()
- CTipsDialog::SwitchTip()
- 实现
- 兼容性
- 待办事项
动机
嗯……有一天我感到很无聊,又不想做任何有必要的事情,于是决定写一个小小的自动滚动控件。结果它做得相当不错,所以我把它发在这里,万一别人也能用得上呢。
描述
自动滚动控件是一种自动以预设速度滚动显示文本的控件。它们通常用于在关于对话框中显示鸣谢名单,或其他类似的琐碎任务;根据设计,它们不够友好,不适合显示重要内容,因为用户如果阅读速度快于或慢于文本滚动速度,会感到沮丧。我的滚动控件有一个可选的滚动条,只是为了让那些可能需要阅读文本的用户更容易一些。
特点
- 平滑滚动,速度可配置。
- 可选的手动滚动,通过滚动条、鼠标滚轮或键盘。
- 可配置滚动完成前后以及手动滚动后的延迟。
- 可选的位图徽标标题:用于在关于对话框等地方显示公司徽标。
- 可选的位图背景图案,可平铺或居中显示。
- 可配置字体、背景和文本颜色。
用途
CScrollerCtrl
的公共 API 包含以下方法
// create the window; remove WS_VSCROLL to avoid showing scrollbar, // remove WS_TABSTOP to disable keyboard scrolling. BOOL Create(const RECT& rect, CWnd* pParentWnd, UINT uStyle = WS_CHILD|WS_VISIBLE|WS_VSCROLL| WS_TABSTOP|WS_GROUP, UINT nID = 0); // activate/deactivate wrapping mode: void SetWrapping(BOOL bWrap); // Sets the color used for the background (if no pattern is set) or margins // (if pattern is set and not tiled) void SetBgColor(COLORREF clrBg); // Sets the color used for text void SetFgColor(COLORREF clrBg); // Sets the font; size is in points, // see LOGFONT documentation for weight constants void SetFont(const CString& strName, int nSize, int nWeight); // Sets the text to be displayed void SetText(const CString& strText); // Sets the bitmap to be displayed above the text CBitmap* SetLogo(CBitmap* pbmpLogo); // Sets the background pattern CBitmap* SetPattern(CBitmap* pbmpPattern, BOOL bTile); // Sets the time (in milliseconds) between frames (autoscrolling speed) // (will revert to default if less than 0) void SetScrollDelay(int nScrollDelay); // Sets the delay (in milliseconds) when autoscrolling pauses // (will disable pausing if set less than scroll delay) void SetScrollPause(int nScrollPause);
调用 Create()
会为控件设置初始大小和位置,以及生效的样式。要禁用滚动条,请移除 WS_VSCROLL
样式;要禁用所有手动滚动,请移除 WS_VSCROLL
和 WS_TABSTOP
样式。
所有其他方法都可以在控件创建之前或之后调用;如果控件已创建,它们将立即生效,否则将在调用 Create()
时生效。所有属性都有默认值,所以你只需要设置你需要的那些。大多数属性都很容易理解,但有几点需要注意
- 如果设置了背景图案,文本将带有阴影以提高可见性。阴影颜色根据前景和背景颜色计算。阴影偏移量为字体大小的 1/10。
SetPattern()
的第二个参数是一个布尔值;如果为 false,则会居中显示位图而不是平铺。SetWrapping()
更改换行模式。默认开启,这意味着当文本(或在没有文本时显示徽标)滚动到屏幕底部时,紧接着会显示徽标(或在没有徽标时显示文本)的开头。如果调用SetWrapping()
并将参数设置为 false,则内容将完全滚动出屏幕后再重新滚动进来。查看演示中的两个对话框之间的区别;这比听起来简单得多。
演示
演示包含一个主对话框和一个子对话框。主对话框显示上面的介绍,以及一个徽标位图,在一个带滚动条的自动滚动窗口中。子对话框通过显示一个滚动提示窗口来说明如何动态更改文本。
演示大部分是自动生成的,所以你可以安全地忽略大部分代码。重要部分在 CScrollerTestDlg::OnInitDialog()
、CTipsDialog::OnInitDialog()
和 CTipsDialog::SwitchTip()
中。
CScrollerTestDlg::OnInitDialog()
在这里,我首先用两组背景图案和颜色中的一组来初始化滚动控件。
if ( ::GetTickCount()%2 ) // lazy man's rand() { m_scroller.SetPattern(CBitmap::FromHandle( (HBITMAP)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_BACKGROUND), IMAGE_BITMAP, 0,0, LR_SHARED)), FALSE); // this background should be centered over a white background m_scroller.SetBgColor(RGB(255,255,255)); m_scroller.SetFgColor(RGB(0,127,0)); } else { m_scroller.SetPattern(CBitmap::FromHandle( (HBITMAP)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_BACKGROUND2), IMAGE_BITMAP, 0,0, LR_SHARED)), TRUE); m_scroller.SetFgColor(RGB(255,255,225)); }
请注意,在第一种情况下,位图是居中的,而在第二种情况下,它是平铺的。
接下来,我设置了徽标位图和文本。
// logo bitmap m_scroller.SetLogo(CBitmap::FromHandle( (HBITMAP)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_SCROLLER), IMAGE_BITMAP, 0,0, LR_SHARED))); // text CString strIntro; strIntro.LoadString(IDS_INTRO); m_scroller.SetText(strIntro);
最后,我创建了滚动控件以填充整个客户区。
CRect rect;
GetClientRect(&rect);
m_scroller.Create(rect, this);
这里值得一提的是,这个对话框是可调整大小的,并且滚动控件在 OnSize()
中被调整大小以始终填充客户区。我为对话框设置了 WS_CLIPCHILDREN
样式,以防止调整大小时闪烁。
创建滚动控件后,我创建并显示提示对话框。
// create tips dialog, and show at top-left of screen m_dlgTips.Create(CTipsDialog::IDD, this); m_dlgTips.SetWindowPos(NULL,0, 0, 0,0, SWP_NOZORDER |SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW);
CTipsDialog::OnInitDialog()
在这里,我首先用自定义字体、消息初始化滚动控件,并关闭了换行。我稍后会解释关闭换行的原因。
m_scroller.SetFont("Microsoft Sans Serif", 10, FW_SEMIBOLD); m_scroller.SetText("\tHello!"); m_scroller.SetWrapping(FALSE);
这个滚动控件中显示的消息不够长,不需要在滚动时就能读懂,所以我让它们尽可能快地滚动,在提示完全显示时暂停。
// short messages, read while paused, not scrolling // so scroll quickly and pause for a 6 secs. m_scroller.SetScrollDelay(0); m_scroller.SetScrollPause(6000);
最后进行创建。请注意,我为控件指定了一个 ID (1),并且省略了 WS_VSCROLL
和 WS_TABSTOP
样式;我不希望用户能够手动滚动它。
// short messages, read while paused, not scrolling // so scroll quickly and pause for a 6 secs. m_scroller.SetScrollDelay(0); m_scroller.SetScrollPause(6000);
好的,现在解释一下关闭换行模式的原因。这个对话框的目的是一个接一个地显示提示,并通过在适当的时候更改文本来实现。如果启用了换行,文本将永远不会完全离开屏幕,切换时效果不会很好。现在弄清楚了,接下来是如何实际切换文本的……
CTipsDialog::SwitchTip()
CScrollerCtrl
是一个仅输出控件;它唯一接受的用户输入是手动滚动,并且它会在内部处理。然而,当内容完全滚动出屏幕时,它会向其父窗口发送一个命令消息。有一个常量(CScrollerCtrl::SC_SCROLL_COMPLETE
)用于标识此命令消息,但由于它是此控件发送的唯一命令消息,因此实际上不必检查它。SwitchTip()
在收到命令消息时处理它,并更改文本。然后新文本会滚动到屏幕上,生活继续。
实现
这是一个相当简单的控件……输出是双缓冲的,以确保平滑更新。使用两个定时器:第一个在窗口生命周期内活动,以滚动速率滴答。第二个用于在自动滚动因任何原因暂停时清除暂停状态;它在触发后立即被销毁。所有绘图都包含在三个方法中的一个中。
FillBackground()
在开始绘制新帧时清除后备缓冲区。如果您希望拥有更花哨的背景(动画等),可以在此处进行。DrawLogo()
绘制徽标位图(如果已设置)。它接受一个参数指定绘制的偏移量,以及另一个参数指定是实际绘制还是仅计算绘制所需的大小。DrawBodyText()
绘制实际文本。它还接受参数指定绘制的偏移量,以及是绘制还是仅计算所需大小。
这些方法都是虚拟的,所以如果您创建一个派生类,可以覆盖其中任意一个或全部来做一些有趣的事情。(例如显示富文本等)
兼容性
我在 Windows XP、2000 和 98 上测试过。它可以使用 Visual Studio 6 和 Visual Studio .NET 进行编译。
待办事项
- 没有。它本身就完美无缺。
- 编写某种简单的 HTML 渲染器并用它替换当前的文本渲染器。
- 去找点披萨和啤酒。