Saturday, August 25, 2012

Combobox Tricks - Part I


I actually posted this or some of this in the defunct www.junblogs.com and has intentionally did not forwarded it in this blog  thinking it is already read before by most of my followers, so they know this now.  But several times I am still seeing some quires regarding comboboxes that I decided to revive this plus add some more tutorials in the near future.

So let us start again on combobox tutorials with this trick, hiding columns and some other things.

The way some developers do to hide let us say the 2nd column from view is to change that 2nd column's width to zero.  While it is good, there will still be a space alloted and shown for that zero-width column:


loTest = Createobject("frmCombo")
loTest.Show(1)

Define Class frmCombo As Form
      AutoCenter = .T.

      Add Object combo1 As ComboBox With ;
            RowSourceType= 6,;
            RowSource = 'junkcbo',;
            Value = 0,;
            BoundColumn = 2,;
            BoundTo =.T.,;
            Style = 2,;
            top = 50,;
            left = 10,;
            Width = 200,;
            ListIndex = 1,;
            ColumnCount = 2,;
            ColumnWidths = '200,0'

      Procedure Load
            Create Cursor junkcbo (xName c(30), xCurrency c(3))
            Insert Into junkcbo Values ('Philippines','PHP')
            Insert Into junkcbo Values ('Papua New Guinea','PGK')
            Insert Into junkcbo Values ('Australia','AUD')
            Insert Into junkcbo Values ('United States','USD')
            Insert Into junkcbo Values ('Indonesia','IDR')
            Insert Into junkcbo Values ('India','INR')
      Endproc

Enddefine


So to fix that problem, you have to hide the column lines to make it appear that column1 and column2 are just one.  Under combo1 settings, you have to add this line:



ColumnLines = .F.

However, that approach works good only if you have two columns.  What if you have more?  And you wanted to have a column line separator?  Then we go back to that ugly last empty column.

The trick is, if you want to hide one or more columns, then do not include those among the ColumnCount and ColumnWidths anymore.  Here is the preferred approach:


loTest = Createobject("frmCombo")
loTest.Show(1)

Define Class frmCombo As Form
      AutoCenter = .T.

      Add Object combo1 As ComboBox With ;
            RowSourceType= 6,;
            RowSource = 'junkcbo',;
            Value = '',;
            BoundColumn = 2,;
            BoundTo =.T.,;
            Style = 2,;
            top = 50,;
            left = 10,;
            Width = 200

      *ColumnCount = 2,;
      *ColumnWidths = '200,0',;
      *ColumnLines = .F.

      Procedure Load
            Create Cursor junkcbo (xName c(30), xCurrency c(3))
            Insert Into junkcbo Values ('Philippines','PHP')
            Insert Into junkcbo Values ('Papua New Guinea','PGK')
            Insert Into junkcbo Values ('Australia','AUD')
            Insert Into junkcbo Values ('United States','USD')
            Insert Into junkcbo Values ('Indonesia','IDR')
            Insert Into junkcbo Values ('India','INR')
      Endproc

      Procedure Combo1.InteractiveChange
         Wait Window this.value 
      Endproc 

Enddefine


And if you noticed, we were able to remove 3 useless (just in this case) settings which are ColumnCount, ColumnWidths and ColumnLines.  Not only that, the dropdown width will try its best to be equal to the width of the combobox.


Question now is if you don’t show the other column, will the data also disappear?

No!

Can we therefore still get the value from that missing columns?

Of course, it is actually not missing.  It is just there but is hidden.  By default, value of combobox is bound to column1 or the first field of the RowSource property.  To tell VFP that what we want to get instead is the value of the hidden column, you simply have to change the BoundColumn property to your target source column, be it hidden or shown.  So to get the value of column 2, these two properties as shown are responsible for it:

.BoundTo = .T.    
.BoundColumn=2

And VFP will know that you are instructing it to get the value, not from Column1 but from that hidden Column2.

Can we get both values of Column1 and Column2 without changing the value of .BoundColumn back and forth?  

Still playing with our sample with only 2 columns, then here is how to get values:

.Value   &&  gets value based on .BoundColumn property.  If you don't touch this, the default value is 1 or Column1
.DisplayValue && always gets value from column 1  

Is there any other way to get values from other columns without resorting to .BoundColumn property?

Yes, via utilizing .ListIndex property:


GetValue = Thisform.Combo1.List(Thisform.Combo1.listindex,2) && 2 means the column number


I hope this sheds some light onto some of Combobox properties and some tricks to play with it.  Next will be some more scrutiny towards Combobox.