No, IMHO it is not a better design to add an unnecessary field and index on it just to provide some sort of display in a listbox.
Using RowsourceType = 3 (SQL) have advantages like:
1) You can select, project, order, group etc in anyway you want w/o affecting the source.
2) Despite showing just a few columns (or simply default 1) you could have as many columns as you want in the listbox source (which is a cursor).
3) Unlike approaches that are not based on alias (additem, addlistitem ...) you don't need to make any conversion to retrieve a 'value' back. You simply get the value with an alias.fieldname and do not need any conversion of data types (if you use listbox's Value then you are tied to a single column plus you have the value as a character).
4) You don't need to be on your toes for VFP's default setting of Boundto = .F.
5) Items 3 and 4 make it a little problematic to get/set something from/to listbox. With alias based sources there is much wider flexibility IMHO.
6) And of course speed.
If we check these with a little (and maybe not so useful) sample:
Code:
Public oForm
oForm = Createobject('SampleForm')
oForm.Show()
Define Class SampleForm As Form
DataSession = 2
Height=400
Width=600
Add Object myList As ListBox With Top = 10, Left=10, Width = 150, Height=380
Add Object txt_EmpId As TextBox With Left=180,Top=10,Width=100
Add Object txt_First As TextBox With Left=180,Top=40,Width=100
Add Object txt_Last As TextBox With Left=180,Top=70,Width=100
Add Object txt_Bdate As TextBox With Left=180,Top=100,Width=100
Add Object txt_Hired As TextBox With Left=180,Top=130,Width=100
Add Object txt_Age As TextBox With Left=180,Top=160,Width=100
Add Object txtEmpId As TextBox With Left=290,Top=10,ControlSource='Employee.Emp_id'
Add Object txtFirst As TextBox With Left=290,Top=40,ControlSource='Employee.First_Name'
Add Object txtLast As TextBox With Left=290,Top=70,ControlSource='Employee.Last_name'
Add Object txtBdate As TextBox With Left=290,Top=100,ControlSource='Employee.Birth_date'
Add Object txtHired As TextBox With Left=290,Top=130,ControlSource='Employee.Hire_date'
Add Object imgPhoto As OleBoundControl With Left=290,Top=160,;
ControlSource='Employee.Photo', Height=200, Width = 200
Procedure Load
Use (_samples+'data\employee')
Endproc
Procedure Init
With This.myList
.RowSourceType = 3
.RowSource = "select Last_Name-(', '+First_name),*" +;
" from employee" +;
" order by 1"+;
" into cursor crsEmployees"
Endwith
Endproc
Procedure myList.InteractiveChange
With Thisform
=Seek(crsEmployees.emp_id, 'Employee', 'emp_id')
.txt_EmpId.Value = crsEmployees.emp_id
.txt_First.Value = crsEmployees.first_Name
.txt_Last.Value = crsEmployees.last_Name
.txt_Bdate.Value = crsEmployees.Birth_Date
.txt_Hired.Value = crsEmployees.Hire_Date
.txt_Age.Value = Year(Date()) - Year(crsEmployees.Birth_Date)
.Refresh()
Endwith
Endproc
Enddefine
If you run the code you get a simple employee form with a listbox navigator. If you examine the code:
-We haven't specified anything other than left,top,height,width, RowSourceType and RowSource for the listbox.
-Although we have single column on the listbox (we might have chosen more) we have access to any field in its source cursor.
-We chose to project lastName-(', '+FirstName) to have a fullName to show and also ordered on that column (why would we ever create a new field for this and index on it)
-Values on left textboxes come from Listbox' cursor.
-Values are not subject to any conversion. They have the data types whatever on the underlying source (a date is a date, an integer is an integer and so on - unlike all being a character with AddItem())
-Since the primary key is part of the cursor, positioning on the correct record in original source table (employee) is a simple seek().
I hope the difference is more clear now.
Cetin Basoz
MS Foxpro MVP, MCP