65.9K
CodeProject 正在变化。 阅读更多。
Home

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

2002 年 3 月 10 日

CPOL

6分钟阅读

viewsIcon

120141

downloadIcon

3786

显示带徽标和图案背景的自动滚动文本。适用于关于对话框、杂项内容。

Scroller
CScrollerCtrl 测试应用程序,在 Windows XP 下运行。

目录

动机

嗯……有一天我感到很无聊,又不想做任何有必要的事情,于是决定写一个小小的自动滚动控件。结果它做得相当不错,所以我把它发在这里,万一别人也能用得上呢。

描述

自动滚动控件是一种自动以预设速度滚动显示文本的控件。它们通常用于在关于对话框中显示鸣谢名单,或其他类似的琐碎任务;根据设计,它们不够友好,不适合显示重要内容,因为用户如果阅读速度快于或慢于文本滚动速度,会感到沮丧。我的滚动控件有一个可选的滚动条,只是为了让那些可能需要阅读文本的用户更容易一些。

特点

  • 平滑滚动,速度可配置。
  • 可选的手动滚动,通过滚动条、鼠标滚轮或键盘。
  • 可配置滚动完成前后以及手动滚动后的延迟。
  • 可选的位图徽标标题:用于在关于对话框等地方显示公司徽标。
  • 可选的位图背景图案,可平铺或居中显示。
  • 可配置字体、背景和文本颜色。

用途

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 渲染器并用它替换当前的文本渲染器。
  • 去找点披萨和啤酒。
© . All rights reserved.