![]() |
Desktop Development »
Combo & List Boxes »
Listbox Controls
Intermediate
License: The Code Project Open License (CPOL)
Include/Exclude List BoxesBy Len HolgateHow to package lots of standard functionality into a CListBox derived class. |
VC6, MFC, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
The first time I ended up with all of the code to do this spread throughout the message handlers of the enclosing dialog box. Not very neat, but it worked. Then I needed to do something very similar and found myself reinventing the wheel, cutting and pasting from one dialog box to another. I stopped and pulled all of the code out and placed it where it should be, in classes especially designed to solve my problem.
The result was a set of classes that can be plugged into any dialog box with minimum fuss and do all of the work required for linked list boxes, and much more besides.
CListBox. We can introduce the concept of a
"list box item processor", an abstract class which provides an interface for performing
processing on a list box item. A processor can then be associated with the list box so
that double click handling can be performed inside the list box rather than outside of
it. By associating a list of buttons with the list box, the buttons can have their
enabled/disabled state managed by it. When items are added or removed the state of all
associated buttons can be automatically adjusted. Where the buttons are required to
perform an action on a selected item, when pressed, we can associate a list box item
processor with them to allow them to process the item.
There are some peculiarities with the standard CListBox
class that means that it's hard to write code that can work with both a single selection
box and a multiple selection box without change. We can wrap up these differences so that
we have a consistent interface to either.
We can use message reflection so that all of the code for
our extended list box exists inside our CListBox subclass. That way objects of our
subclass can handle their own messages rather than having the containing dialog box handle
them for us.
The end result is a list box that makes it easier to do most of the "standard" things that you might want to do with a list box. All the code is in one place, so it's easy to put it in a library and use it in lots of dialog boxes. Associated buttons are managed automatically by the list box, and as a user you just need to derive a class from the list box item processor to manipulate the items when they are double clicked or when an associated button is pressed.
To take advantage of the extended functionality of
CJBListBox simply use in place of a regular CListBox. The extended
list box offers the following member functions: (see the source code for more information!)
SetDefaultProcessor() - sets up a list processor to handle double clicks.
AssociateButton() - associates a button with the list. If a button ID is
supplied then the list box will create and manage the button. If a list processor is
supplied it will be used to handle clicking on the button otherwise the box's default
processor will be used. If a reference to an existing CButton is supplied,
rather than a button ID, then the list box will still manage the enabled state of the
button but the button can look after its own OnClicked() processing.
AddItem() - adds a string and optional data pointer to the list box and
updates the state of any associated buttons.
InsertItem() - inserts an item at a specific index and updates the state
of any associated buttons.
RemoveItem() - removes an item and any associated data pointer from the
list box and updates the state of any associated buttons.
GetSelectionCount() returns the number of items selected whether the box
is single or multi selection.
GetSelectedItems() - returns an array of indexes to selected items whether
the box is single or multi selection.
SelectItem() - selects an item and updates any associated buttons.
CancelSelection() - cancels either a particular selection, or any current
selection, and updates the state of any associated buttons.
MoveItemUp() - moves the specified item up one slot in the list box.
MoveItemDown() - moves the specified item down one slot in the list box.
ProcessSelectedItems() - apply the list box's default processor, or a
supplied processor, to all selected items.
The only other class that a user of the list box must be aware of is
CJBListBox::ItemProcessor. This is a very simple abstract base class.
class CJBListBox::ItemProcessor { public : // Destruction... virtual ~ItemProcessor() { } // Process an item virtual void ProcessSelectedItem( const int nIndex, const CString &theString, void *pData, PostProcessAction_e &action) = 0; };
ProcessSelectedItem() gets called to process the list box
item and gets passed the item's index, string and any data stored with it. The enum
returned can be set to indicate what should be done with the item after the function
returns (deselection, deletion, etc).
If multiple items are selected then each will be passed in turn to the list processor. This is possibly a weakness of the design, but I have yet to come across a situation where I needed to know about all of the items in a multi-selection before I could process any of them.
CJBListBox::TSimpleItemProcessor<CJBListBox::MoveDown> downProcessor; CJBListBox::TSimpleItemProcessor<CJBListBox::Delete> deleteProcessor;
CJBListBox class. I've yet to decide if this has added
complexity, or whether it was necessary, and I had to jump through a few hoops to keep
class wizard happy.
Nesting the classes has added a tighter level of coupling to the classes. In one way this is good because the classes that are coupled are implementation details of the classes they are coupled to. However, I dislike the way that more source files are dependant on each other.
CJBListBoxPair is a very simple class. It has two public
CJBListBox data members and a nested, private, list swap item processor. The
control can be simply added to a dialog box and hooked up to the controls by calling one
function: Create() which takes the control IDs of the two list boxes and the
two buttons which move items from one box to the other. The control can be extended by
associating more buttons with the list boxes if required.
The decision to make the two list boxes public data members was based on the fact that if we didn't make them publicly accessible then forwarding functions for each of the useful member functions would need to be written. These forwarding functions would also need to be able to determine which of the two boxes they should be applied to. This seemed unnecessary.
The list swap item processor was relatively easy to
create. The processor needs to be given a list box to add items to. When its
ProcessSelectedItem() function is called it simply adds the item to its list box and
returns "Delete" to delete the item from the box it was originally in.
See the article on Len's homepage for the latest updates.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 25 Feb 2000 Editor: Valerie Bradley |
Copyright 2000 by Len Holgate Everything else Copyright © CodeProject, 1999-2009 Web20 | Advertise on the Code Project |