Click here to Skip to main content
15,890,946 members
Articles / Desktop Programming / MFC
Article

XPrintHeader - Choose page header format using "More like this" popup menus

Rate me:
Please Sign up or sign in to vote.
4.65/5 (16 votes)
30 Jul 2003CPOL5 min read 56.3K   819   21   3
XPrintHeader implements a dialog that allows the user to choose the formatting for a page header by dynamically created popup menus.

Introduction

One day my Product Manager asked me to update the page header dialog that we display so our users can customize the header that gets printed on the top of each page. This was something many of our users complained about - they had to enter obscure codes to get the date format, and there was no easy way to check what they entered, except to print a page. I had been thinking about this for a while, and I had a pretty good idea of what I wanted to do. There was just one hitch: my Product Manager wanted to display all of the commonly used date/time formats in a list, and the user could choose from that list. This had the advantage that the user would not have to enter the individual format codes. The problem: it was a long list, and to be comprehensive, it had to include 11/21/01, 11-21-01, 11.21.01, and other day/month/year orders.

The first thing I did was to gather the complete list of date/time formats that I had ever seen or heard of anyone using. More than 100! The next thing I did was to go over the list with my Product Manager. We got it down to less than 60, but decided that the list should also include selections for individual date/time elements, like "day of month", "year with century", etc. This way, the user could choose one of the standard formats, or he could construct his own, using the date/time elements. Total number of list items: 72.

OK, at this point I knew I had a problem. There was no way to fit 72 items into any kind of reasonable dialog, unless I used a listbox of some kind. And I kept thinking that it would be nice to group together similar standard formats, to make it easier for the user. At some point I began to think of popup menus - easy to use, and they had separator lines for groupings. So I entered all the items into a table, and created a popup menu:

screenshot


Unfortunately, I had this on the screen when my Product Manager came by. He looked at it, looked at me, then walked away. But I had already decided how to fix it. At this point, the table of menu IDs and format strings already contained -1 entries for the separator lines. Being actively lazy, I realized I could trivially extend this to accommodate sub-popup menus. At the same time, I thought of the web sites that encouraged me to keep shopping with handy "See more like this" buttons. Putting the two together, I used -2 entries in the table to signal the start of sub-popup menus. The idea was to show a few entries in each group, and then use a "More like this" popup menu to show the rest. Here is the result:

screenshot


When the user hovers on Date/Time Elements, he sees:

screenshot


The next submenu shows date formats that begin with the day of the month:

screenshot


Then the submenu that shows formats that begin with the month:

screenshot


And finally the submenu that shows formats that begin with the year:

screenshot


Implementation Notes

It is likely that you will want to make changes to this implementation to meet your own requirements. Most of the code that supports the menu button and the menu handler is in XPrintHeader.cpp. Besides this code, you will need to insert
ON_COMMAND_RANGE(ID_INSERT_FIRST, ID_INSERT_LAST, OnInsert)
ON_BN_CLICKED(IDC_HEADER_BUTTON, OnHeaderButton)
ON_EN_CHANGE(IDC_HEADER, OnChangeHeader)
in the dialog's message map.

The ON_COMMAND_RANGE causes all the menu selections to be routed to the OnInsert() function, where the two edit fields are updated.

HeaderFormats[] is defined as an array of Format structs:

typedef struct
{
    UINT nID;                   // menu ID, or:
                                //    0 = end of table
                                //   -1 = separator
                                //   -2 = beginning of submenu
    TCHAR *pszFormat;           // format string
    TCHAR *pszDescription;      // optional description
} Format;
With this array, it is very easy to rearrange items and insert separators and submenus. As you saw, I first collected all the items in one menu, then added separators, and then added submenus at appropriate places.

When the user makes a menu selection, the contents of the pszFormat member is appended to the writable edit field, and the read-only edit field shows an example. The read-only edit field is updated immediately if any changes are made to the format string. Non-format text is displayed as is.

Demo App

The XPrintHeaderTest.exe demo shows how to use XPrintHeader.cpp.

screenshot


Summary

The technique presented in this article is applicable to a wide variety of UI requirements, where it is necessary to organize and present many different options. Through the use of "More like this" popup menus - with an example displayed on the menu - the user can quickly drill down to the selection he is looking for, without having to wade through a long list.

Possible Enhancements

  • Read menus from file - Since the popup menus are created dynamically, it is possible to read the menu table from a file or database. This would also allow end users to customize the order or contents of the menus.

  • Adjust menus according to usage - This enhancement would shift the most-used selections to the top of the menu group, so that they would be displayed on the main menu, rather than a submenu. This would be very nice if also coupled with saving the new menu order.

Revision History

Version 1.0 - 2003 July 30

  • Initial public release.

Usage

This software is released into the public domain. You are free to use it in any way you like. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.

Recently, I have moved to Los Angeles where I am doing consulting and development work.

For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions

 
QuestionWould you make this into a dll please!! Pin
aaroncampf28-Dec-10 13:49
aaroncampf28-Dec-10 13:49 
I cannot get the darned thing work when i open it D'Oh! | :doh:

Could you make it a DLL please i really want to use it in my vb.net project!!!

Thank You!!!
JokeCool Pin
Wes Aday17-Oct-07 12:03
professionalWes Aday17-Oct-07 12:03 
GeneralGood job! Pin
Cloaca19-Dec-03 4:21
Cloaca19-Dec-03 4:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.