Currently viewing: GipsySoft » Front Page» Articles

News Ticker

A horizontally scrolling list of items in a simple, but flexible, control.

Motivation

This library was coded mostly for fun. It provides a simple Win32 control (just like any other control) that allows you to add/edit and remove horizontally scrolling news items or status updates.

Features

Here's a list of the main features of the library:
  • Items can be added and removed.
  • Items can have a multi-line tooltip.
  • Items can have independent text and background colours.
  • Items can use different fonts.
  • WM_NOTIFY messages for left-click, double-click, right-click, right-double-click and set cursor (NM_SETCURSOR).
  • Control responds to WM_SETFONT just like a normal windows control. Useful for placing the control onto a dialog.
  • All items can be removed in one go.
  • You can get, set and update individual items and individual item properties.
  • You can find the optimal height and width of the control.
  • Can set the horizontal gap between displayed items
  • Can set the speed of the scrolling
  • You can set the default font, text and background colours.
  • You can set the default scroll speed and the default gap between items.
  • Items can be owner drawn. The control will then send WM_MEASUREITEM and WM_DRAWITEM messages.
  • With owner drawn items the 'state' will be ODS_HOTLIGHT when the mouse is over the item.
  • Builds as a DLL or static LIB both as ansi and unicode.

Using the above features you can easily pretend the items are hyperlinks by responding to the NM_SETCURSOR and NM_CLICK notify messages.

Usage

Using the control is very similar to using a Tree or List view control. The basic steps are:

  1. Include the NewsTicker.h header file where required.
  2. Initialise the library.
  3. Create the control.
  4. Set optional attributes.
  5. Add/edit/remove items.

Initialise the library

Add a single call to the initialisation function at your application startup. In MFC this would be in the InitInstance member of your CWinApp derived class.

//	In MFC
	NewsTicker_Initialise( AfxGetInstanceHandle() );

Create the control

Creation of the control can be on a dialog. Using the dialog approach you can have an almost zero-code newsticker! To add the control to a dialog add a custom control and specify the class name as GS_NewsTicker_Class - See screen-shot on the right.

Creating the control using CreateWindow is no different to creating any other control. Just use the same window class as detailed above.


m_hwndNews = CreateWindowEx( WS_EX_TRANSPARENT, NEWS_TICKER_CLASSNAME
                   , NULL
				   , WS_CHILD | WS_VISIBLE
				   , x, y, cx, cy
				   , hwndParent
				   , (HMENU)1
				   , hInstance
				   , NULL );

Set optional attributes

NewsTicker has several attributes you can alter. Attributes such as:
  • Gap between items
  • Default background colour
  • Default foreground colour
  • Default font used for items (use WM_SETFONT just like any other control)
  • Scroll rate

Each attribute has it's own API. To change the background colour:


//	Windows API way (with the message cracker)
NEWSTICKER_SetBKColor( m_hwndNews, RGB( 0, 255, 0 ) );

//	MFC way
m_wndTicker.SetBKColor( RGB( 0, 255, 0 ) );

Add/edit/remove items

NewsTicker has an 'item' structure that allows you to add and edit items, and individual item attributes. It works in a similar way to other windows controls so you should be unsurprised by the way it works.

//	Windows API way of adding an item
NEWSTICKER_ITEM item = {
	sizeof( NEWSTICKER_ITEM )
	, NEWSTICKER_FLAGS_TEXT
		| NEWSTICKER_FLAGS_TOOLTIP_TEXT
		| NEWSTICKER_FLAGS_ID
	};
item.uID = uID;
item.pcszText = "Here is an item";
item.pcszTooltip = "And here is it's tooltip";
NEWSTICKER_AddItem( m_hwndNews, &item );

//	Using the MFC wrapper
NEWSTICKER_ITEM item = {
	sizeof( NEWSTICKER_ITEM )
	, NEWSTICKER_FLAGS_TEXT
		| NEWSTICKER_FLAGS_TOOLTIP_TEXT
		| NEWSTICKER_FLAGS_ID};
item.uID = uID;
item.pcszText = "Here is an item";
item.pcszTooltip = "And here is it's tooltip";
m_wndTicker.AddItem( &item );

It's the little things

It's the little things that make a difference. This control is a simple Win32 control and as such it should behave like one.

It's just one function call to get the library initialised. From there on you just create windows and send messages...just like buttons, statics, edit controls...

Once you've created the control you want to move/size it, maybe to the top of your window or maybe to the bottom. Use NEWS_TICKER_GET_IDEAL_SIZE to ask the NewsTicker what would be it's ideal size - you can then use this information to place the window where-ever you like.

Setting the style WS_EX_TRANSPARENT makes the control transparent. If you place it on a bitmapped background the background shows through...just as you would expect.

I was stuck for what to do with the window text that's sent at control creation time (either manually or on a dialog) so I ended up parsing the text for TAB characters and adding the values between the TABs as items. This actually works really well and allows zero-code NewsTickers on dialogs just by adding the items as the caption text.

Owner drawn items behave as expected. You measure the item and you get to draw it too. I did look at custom draw but it looked *so* complex I just thought "no-one will ever use this"

Try as I might I couldn't get the standard tooltip to behave the way I wanted. The control includes a second quick-hack tooltip control that pretty much behaves as a tooltip should. It's got a quirky interface specially designed for the NewsTicker but should serve as a fairly simple example of writing a similar control.

Tooltips can have multiple lines of text. And thanks to the fact that the windows tooltip control wouldn't do what I wanted you could even have formatted text in the tooltips if you wanted - just hack the code!

Thanks to owner draw and the WM_NOTIFY messages I could use QHTM and have HTML formatted items in both the NewsTicker and the tips.

Having message cracker wrappers for the messages makes life a little easier for us poor API programmers.

Look at the way the message crackers work. They have their own SendMessage macro - this means the same code will compile even when included in an MFC application.

A complete MFC CWnd class is provided too. Yup, it's a simple wrapper around the API and more could be done to make MFC usage even nicer...but I don't use MFC, sorry.

Lastly, it builds cleanly at level 4 warnings with warnings as errors and has both ansi and unicode builds.

What else could be added

As I was writing the control I did think of a few things to add or change. I only had a day and a half to play so I couldn't do everything I wanted *and* document it. Here's my list of things I could have added but didn't:

  • An easy way to have an icon or bitmap item - it should be just a property of the items. However, I also thought that owner draw was a more flexible approach and allowed the host application to decide how to draw such images.
  • Flashing items - this could be just an item style. The style is already in the control for use in owner drawn items so it's just a matter of adding a timer to then coerce the 'flashable' items to alter their state...and then redraw.
  • Custom draw support for the entire control. Could get messy but it's the right thing to do.
  • Depending on detected OS add the 'shadow' style to the tooltip window class.

Source code notes

Note the use of _NO_MULTIMON_SUPPORT in the static library version DSP file. This is there because exactly one project should create the multi-monitor stubs in a single build and when static linking with MFC it seems MFC already has this. If you get link errors relating to multi-mon then remove this from the project settings and rebuild.

I use the directory structure outlined here. You don't need to follow this but it's served me well for many years and I've had zero problems with it. All my stuff goes into this structure

Share any modifications you make with me so I can share them with others...help make this a better tool and let's help everyone else so they don't need to write the same thing again!