LISTEX.VBX - A Custom List Box

  If you have ever used CompuServe's WINCIM, you have probably wondered how 
they got those list boxes to do the things they do.  How do you change the 
text color of only one item in the list?  How do they add those check boxes?  
How do they keep an item from being selected?  The LISTEX.VBX custom list 
box control allows you to do all of those things and many more. 
  Accompanying this text is a program LISTEXD.MAK that shows how all of 
this is done.

Events, Methods, and Properties

  The ListEx control events and methods are identical to a standard list box 
control.  The following properties of the ListEx control are also identical 
to the properties in the standard list box control:

BackColor		Height			NewIndex
Columns			HelpContextID		Parent
DragIcon		hWnd			Selected
DragMode		Index			Sorted
Enabled			ItemData		TabIndex
FontBold		Left			TabStop
FontItalic		List			Tag
FontName		ListCount		Text
FontSize		ListIndex		Top
FontStrikethru		MousePointer		TopIndex
FontUnderline		MultiSelect		Visible
ForeColor		Name			Width

  The ListEx control has the following extended properties:

About			ItemForeColor()
Align			ItemImage()
BorderStyle		NumTabs
ImageOffset		SelectEnable()
ItemBackColor()		SelectStyle
ItemDefHeight()		TabStops()
ItemFontName()		TextOffset
ItemFontSize()	

About
  About tells you the version number of the control.

Align
  Align can be set to the following values:
0 - None		No Alignment
1 - Align Top		Align to the top of the form
2 - Align Bottom	Align to the bottom of the form

  When either Align Top or Align Bottom is selected, the list box will 
automatically size to the width of the container on which it is positioned 
and position itself to the top or the bottom of the container.  If more than
one ListEx control is loaded on the same container and are aligned the same,
they will position themselves stacked on top of each other.  You will not 
be able to alter the Width property.

BorderStyle
  BorderStyle can be set to the following values:
0 - None		No border
1 - Fixed Single	Standard border

ImageOffset
  ImageOffset is the distance from the left edge of the list box to start 
drawing the image.  This value depends on the ScaleMode of the container on 
which the ListEx control is placed.  For instance, if the ScaleMode is 3 
(Pixels) and ImageOffset is 20, the image will be drawn twenty pixels from 
the left edge of the ListEx control.  If you set ImageOffset from the 
properties window, the value will automatically change to reflect the new 
units if you change the ScaleMode of the container on which the ListEx 
control is placed.
  ImageOffset affects all items in the list.  You can change the ImageOffset
value at run time; however, to update any images that have already been 
added to the ListEx control you will have to invoke the Refresh method.

ItemBackColor()
  ItemBackColor allows you to set the BackColor of individual items in the 
list.

ItemDefHeight()
  ItemDefHeight allows you to set the height of individual items in the list.
Like ImageOffset, the units depend on the ScaleMode of the container on 
which the ListEx control is placed.
  On multi-column list boxes, the ItemDefHeight can not be set at run time 
and must be set from the properties window.

ItemFontName()
  ItemFontName allows you to set the font of individual items in the list.
The font will be created for each item in the list based on the FontBold, 
FontItalic, FontStrikethru, and FontUnderline properties.  If you want 
different font properties for each item, change the font properties to the 
new settings before setting ItemFontName.

ItemFontSize()
  ItemFontSize allows you to set the font size of individual items in the 
list.  This value is always in Pixels.

ItemForeColor()
  ItemForeColor allows you to set the ForeColor of individual items in the 
list.

ItemImage()
  ItemImage allows you to display Bitmaps, Icons, or Windows Metafiles in 
individual items in the list.  You can either use LoadPicture or the Picture
property of any control (i.e. ListEx1.ItemImage(0) = LoadPicture("myicon.ico")
or ListEx1.ItemImage(0) = Picture1.Picture).

NumTabs
  NumTabs is the number of tab stops that are to be set in the list box.

SelectEnable()
  SelectEnable allows you to set whether or not a particular item in the list 
can be highlighted.  Setting SelectEnable to FALSE for an item causes a 
focus rectangle to be drawn when that item is selected.  SelectEnable does
not affect the Selected property.  Selected will still show TRUE for that 
item if it is selected.

SelectStyle
  SelectStyle can be set to the following values:
0 - Invert	Invert the item when selected
1 - Standard	Use the standard system colors COLOR_HIGHLIGHTTEXT and 
		COLOR_HIGHLIGHT to highlight the selection

  If you are using colors other than the standard system colors in the list
box, you should set SelectStyle to 0.

TabStops()
  TabStops hold the individual tab stops that are to be set in the list box.
The values are always in Pixels.

TextOffset
  TextOffset is the distance from the left edge of the list box (not from 
the image) to place the text.  It is possible to place text over an image.  
TextOffset only applies if there is an image in the item.  This value depends
on the ScaleMode of the container on which the ListEx control is placed just
like ImageOffset.
  TextOffset affects all items in the list.  You can change the TextOffset 
value at run time; however, to update any images that have already been 
added to the ListEx control you will have to invoke the Refresh method.


LISTEX.VBX vs. Standard List Box
  LISTEX.VBX will perform exactly like a standard list box except that it will
not automatically size to keep from showing partial items.  The reason for 
this is because you can set the height of individual items to any height you
want; therefore, you might want to set the Height and the Width of the 
control to account for this.  If all of your items are going to be 200 TWIPS
high and you want ten items to show, set  ListEx.Height = 2000 + 2 * 
Screen.TwipsPerPixelY (200 * 10 + the width of the border).  If you plan to
use a multicolumn list box, use the same method to set the width.
  ListEx will also not automatically set the height of each item depending
on the FontSize like a standard list box does.


Using the ListEx VBX - LISTEXD.MAK

LISTEX.MAK is a demo program for using the ListEx VBX.  It contains one form
with four different examples of how the VBX can be used.

Adding Images and Setting Colors
  The first example (ListEx1) shows how to set images and text in the list box
as well as how to change the ItemBackColor and ItemForeColor of individual 
items in the list.  This example also shows the difference between using 
ICON images rather than BITMAP images.  When you use Icons, highlighted 
images that are highlighted when SelectStyle is set to 1 can have part of 
the image masked out.  To see the difference, comment out the line UI = 0 
and uncomment the line UI = 3 in the Cmd_Load event.

Tab Stops
  The first example also shows how to set tab stops.  The measurement system
for tab stops is always in PIXELS.  To make it easier, the ScaleMode of the
form is set to 3 (PIXELS).  This example uses the Label.Left positions to 
determine the tab stops to set for each column.  If you want to use TWIPS, 
use Screen.TwipsPerPixelsX as a conversion.
  All tab stops are left justified; however, you can right justify using the
following method: 
 
  Determine the width of the widest character you are going to use (W is 
  usually the widest)
  Determine the maximum length of the string in each column (length of 
  string * widest character)
  Set a tab stop at each character position
  Add leading spaces to make up difference in character widths
  Add leading tabs (Chr$(9)) to any string that is less than the maximum length

  The easiest way to accomplish this is to set the ScaleMode of the container
on which the ListEx control is placed to PIXELS and then set the font 
properties of the container the same as the font you want to use in the list
box.  The following statements determine the tab settings for a list of 
numbers with a maximum of twelve (12) characters (assuming that ListEx1 is
placed directly on a form):

ScaleMode = 3 ' Pixels
FontName = ListEx1.FontName
FontBold = ListEx1.FontBold
FontItalic = ListEx1.FontItalic
FontSize = ListEx1.FontSize
FontStrikethru = ListEx1.FontStrikethru
FontUnderline = ListEx1.FontUnderline
MaxWidth = TextWidth("0")	' Widest character to be used
If ((TextWidth(" ") Mod 2) And (MaxWidth Mod 2 = 0)) Or ((TextWidth(" ") Mod 2 = 0) And (MaxWidth Mod 2)) Then
    MaxWidth = MaxWidth - 1	' If width of space is odd and MaxWidth is even or vice
	' -versa, subtract 1 from MaxWidth
End If
ListEx1.NumTabs = 12
For I = 0 To 11
ListEx1.TabStops(I) = I * MaxWidth
Next I

Once the tab stops are set, you can use the following function to return a
string that will be right justified:

Function Right_Justify$ (Parm&, Lngth%, MaxWidth%)
    Dim A$, TotalLen%, SLen%, Tabs%
    
    A$ = Format$(Parm, "#,##0")
    TotalLen = MaxWidth * Lngth			 ' max tab stops * width
    SLen = TextWidth(A$)			 ' Width of string
    Do Until SLen Mod MaxWidth = 0		 ' Loop until SLen lines up on a tab stop
    If SLen >= TotalLen Then Exit D		 ' Stop if string is too long
    A$ = " " & A$				 ' Add a leading space to make up difference
	' in width
    SLen = TextWidth(A$)			 ' Get new width
    Loop
    Tabs = (TotalLen - TextWidth(A$)) / MaxWidth ' Determine how many tabs to add
    If Tabs > 0 Then A$ = String$(Tabs, 9) & A$  ' Add leading tabs
    Right_Justify$ = A$
End Function

Where:
	Parm&	  = Number to make a string out of
	Lngth%	  = Maximum characters to use
	MaxWidth% = Character width to use

  This function can easily be modified to accept strings rather than numbers.

Multicolumn List Boxes
  The second example (ListEx2) shows how to display a list of icons in a 
multicolumn list box.  The one difference that should be noted when using 
multicolumn listboxes is that ItemDefHeight can not be changed at run time.  
All items in the list must have the same height and can only be set through 
the properties window.

Using SelectEnable
  The third example (ListEx3) shows how to create a list of check boxes.  In 
this example, the first item in the list is disabled from being selected by
setting SelectEnable(0) to FALSE.  The first item in the list (Check Boxes)
will not be highlighted when it is clicked on (note: Selected will still 
show TRUE).  The ListEx3_MouseDown event contains the code for deciding if
the check boxes should be checked.

Setting Individual Item Fonts
  The fourth example (ListEx4) shows how to set individual font properties 
in each item of the list.  It is important to set all of the font properties
before setting ItemFontName.  ItemFontSize sets the font height in PIXELS.
The easiest way to determine this size is to set the container ScaleMode to
PIXELS and Font properties to the font you want to use, then use 
ItemFontSize = TextHeight("0"). 

  Questions or comments about the LISTEXD project can be sent to Joe Oliphant.  
E-Mail joe_oliphant@csufresno.edu or CompuServe 71742, 1451.
If you find this VBX useful, you may want to register it.  Registering it 
lets me know who you are so that I can send you bug fixes (bugs? there aren't
any bugs.) and info on any future improvements.  You must register it if you
plan on using it in any commercial application.  You can register it on-line
through CompuServe (GO SWREG ID# 5862) or by contacting me.




