|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Contents
Motivation:Well... I was bored the other day, and not wanting to do anything necessary, decided to write a little autoscroller. It turned out quite nicely, so I'm posting it here in the off chance it might be useful to someone else. Description:An autoscroller is a control that displays text, scrolling it automatically at a pre-determined speed. They are generally used for displaying credits in about dialogs, or other such trivial tasks; by design they are not friendly enough to be used for displaying important things, since users will be frustrated if they read faster or slower than the text is scrolled. My scroller has an optional scrollbar though, just to make it easier for such users should it ever be used to display text they will actually want to read. Features:
Use:The public API for // 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); Calling All other methods can be called either before or after the control is
created; if the control has been created, they will take effect immediately,
otherwise they will be in effect when
The Demo:The demo consists of a main dialog and child dialog. The main dialog displays the introduction above, along with a logo bitmap, in an auto-scrolling window with a scrollbar. The child dialog illustrates changing the text on the fly by presenting a scrolling tips window. The demo is mostly autogenerated, so you can safely ignore most of the code.
The important bits are in CScrollerTestDlg::OnInitDialog():Here i begin by initializing the scroller with one of two sets of background patterns and colors: 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)); } Note that in the first case, the bitmap is centered, while in the second it is tiled. Next, I set the logo bitmap and text: // 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); Finally, I create the scroller to fill the entire client are: CRect rect;
GetClientRect(&rect);
m_scroller.Create(rect, this);
It's probably worth noting here that this dialog is resizeable, and that the
scroller is resized in After creating the scroller, I create and show the tips dialog: // 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():Here I begin by initializing the scroller with a custom font, a message, and turning off wrapping. I'll explain the reason for turning off wrapping shortly: m_scroller.SetFont("Microsoft Sans Serif", 10, FW_SEMIBOLD); m_scroller.SetText("\tHello!"); m_scroller.SetWrapping(FALSE); The messages displayed in this scroller aren't long enough that they need to be readable while scrolling, so I let them scroll as fast as possible, pausing when the tip is fully shown. // short messages, read while paused, not scrolling // so scroll quickly and pause for a 6 secs. m_scroller.SetScrollDelay(0); m_scroller.SetScrollPause(6000); Finally do the creation. Note that I give the control an ID (1) and omit the
// short messages, read while paused, not scrolling // so scroll quickly and pause for a 6 secs. m_scroller.SetScrollDelay(0); m_scroller.SetScrollPause(6000); Ok, now an explanation for turning off wrapping mode. The purpose of this dialog is to display tips, one after another, and to do this by changing the text at appropriate times. If wrapping is turned on, the text will never be completely off screen, and switching will not look good. Now that that's clear, on to how the text is actually switched... CTipsDialog::SwitchTip():
Implementation:This is a fairly simple control... Output is double-buffered to ensure smooth updates. Two timers are used: the first is active for the life of the window, ticking off at the scroll rate. The second is used to clear the paused state when autoscrolling is paused for whatever reason; it is killed as soon as it is triggered. All drawing is contained in one of three methods:
These methods are all virtual, so if you create a derived class, you can override any or all of them to do something interesting. (display rich text, etc.) Compatibility:I've tested this on Windows XP, 2000, and 98. It will compile with both Visual Studio 6 and Visual Studio .NET TODO:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||