How to make a Visual FoxPro listbox read-only

Although the listbox control has no ReadOnly property, you can still achieve the desired effect.

By Mike Lewis

In my Visual FoxPro forms, I aim to make all the editable controls read-only by default. The user has to explicitly click an Edit button to interact with the controls. When they do, the form sets the controls' ReadOnly property to false. When the user clicks Save or Cancel, the property is reset to true.

Figure 1

Figure 1: A normal listbox. You can
scroll it and pick a value.

This works well enough with textboxes, editboxes, spinners and many other controls - but not with listboxes. That's because listboxes don't have a ReadOnly property. To get round that, I use the Enabled property instead. Disabling a listbox - that is, setting Enabled to false - has the same effect as making it read-only.

But not quite. A user recently requested the ability to scroll through a listbox to see all the available values - but not necessarily to select one - even when the form was not in edit mode. That's not possible with a disabled listbox.

A simple solution

The solution is a simple one. Instead of disabling the entire listbox, you disable each of the individual items. When you do, you can still use the scrollbars, but you can't make a selection.

To disable individual list items in this way, you precede their values with a backslash. You can do that if the RowsourceType is 0 (items added programmatically), 1 (comma-delimited) or 5 (array). You can add the backslash either to the source data (before you populate the listbox) or to the list items themselves. The latter is more generic, as you can simply apply the following code any time after setting the Rowsource and RowsourceType:

FOR lnI = 1 TO this.ListCount 
    this.ListItem(lnI) = "\" + this.ListItem(lnI) 

The technique does not work for cursor-based row sources, for example where the RowsourceType is 2 (alias), 3 (SQL) or 6 (fields). In those cases, one solution would be to copy the relevant data to an array, and then to use a RowsourceType of 5 to populate the listbox.

Figure 2

Figure 2: You can still scroll the listbox
but you can no longer pick a value.

Reversing the process

What about reversing the process - that is, resetting the control to read-write? You might think that you can simply loop through the list items (as in the above code), removing the backslash in each case. That won't work, because the backslash isn't actually stored with the item's value.

To reset a listbox to read-write, you must first clear its existing contents. You do that by calling its Clear method. You then have to re-populate it, by resetting its Rowsource and RowsourceType properties.

Existing backslashes

If a list item already starts with a backslash, then adding a second backslash won't disable it. Rather, it will display it with a single backslash. The rule is that any multiple of two backslashes at the start of an item will display as one backslash, without disabling the item. In these cases, you need to precede the item with a backslash and a closing square bracket (\]).

To improve the appearance of the control, you might want to experiment with its DisabledItemForeColor and DisabledItemBackColor properties. You can't set DisabledItemForeColor to black, as that has the effect of graying the item out. But you can set it to RGB(1,1,1), which is virtually the same as black.

If you're likely to frequently use the technique described in this article, you can make it part of your base listbox class. Add a custom ReadOnly property to the class. In its Assign method, call a custom EnableItems or DisableItems method, to enable or disable the items respectively. You will then be able to simply toggle ReadOnly to get the desired effect: a generic solution which will be avaiable for all the listboxes in your application.

March 2013

Please note: The information given on this site has been carefully checked and is believed to be correct, but no legal liability can be accepted for its use. Do not use code, components or techniques unless you are satisfied that they will work correctly with your sites or applications.

If you found this article useful, please tell your friends: