Subject Re: combobox / msgbox
From Michel <mgomet@gmail.com>
Date Fri, 16 Feb 2024 09:05:10 -0500
Newsgroups dbase.getting-started

Mervyn Bick Wrote:

> On 2024/02/16 10:31, Lee Grant wrote:
> > Mervyn,
> >
> > Admittely, I'm not this advanced and especially in the use of Array and
> > especially not ArrayRowsets, but looking at this code, he seems to be
> > trying to use an Array, like an ArrayRowset, for a rowset.
> >
> > Correct me if I'm wrong, but I think he needs to check out the sample of
> > the ArrayRowset if that is what he is trying to do with a regular Array.
>
> A combobox has various options when it comes to assigning lists to its
> datasource property.  The most used option is to assign an array to the
> property although one can assign a field from a rowset.
>
> When a combobox opens the first value in the list, be it an array or a
> field in a rowset, assigned to the combobox's datasource property is
> displayed in the combobox's entryfield
>
> Michel has opted to build an array from the data in the field because he
> has more control.  He has added a blank element at the start of the
> array so that when the form opens nothing is displayed in the entryfield.
>
> Michel, it's not written on tablets of stone, but I prefer not to add a
> blank element to the array.  Sooner or later the user is going to select
> that blank element and is going to wonder why your program doesn't
> react.   I prefer to use the form's onOpen event handler to place a
> message in each combobox so that the user has an idea of what the
> combobox is for.
>
> I've made some changes to your form which is attached.
>
> I've added an entryfield to show what record is selected.  The
> entrifield's tabstop property is set false so as to keep it out of the
> z-order.
>
> Mervyn.
>
>
>
>
> clear
> ** END HEADER -- do not remove this line
> //
> // Generated on 2024-02-16
> //
> parameter bModal
> local f
> f = new wcombo1Form()
> if (bModal)
>    f.mdi = false // ensure not MDI
>    f.readModal()
> else
>    f.open()
> endif
>
> class wcombo1Form of FORM
>    set procedure to :wef1:\wcombo1\lgControls.cc additive
>    with (this)
>       onOpen = class::FORM_ONOPEN
>       onClose = class::FORM_ONCLOSE
>       open = class::FORM_OPEN
>       metric = 4        // Centimeters
>       height = 6.2442
>       left = 2.249
>       top = 2.9633
>       width = 17.78
>    endwith
>
>    this.VEND1 = new QUERY(this)
>    with (this.VEND1)
>       left = 30.0
>       top = 29.0
>       sql = 'select * from "VEND.DBF"'
>       active = true
>    endwith
>
>    this.MYCOMBOBOX1 = new MYCOMBOBOX(this)
>    with (this.MYCOMBOBOX1)
>       onChange = class::MYCOMBOBOX1_ONCHANGE
>       height = 0.8731
>       left = 0.8202
>       top = 1.1906
>       width = 7.5406
>       dropDownHeight = 5.0006
>       selectAll = true
>    endwith
>
>    this.MYENTRYFIELD1 = new MYENTRYFIELD(this)
>    with (this.MYENTRYFIELD1)
>       onGotFocus = class::MYENTRYFIELD1_ONGOTFOCUS
>       height = 0.8996
>       left = 10.2129
>       top = 1.4552
>       width = 5.8473
>    endwith
>
>    this.ENTRYFIELD1 = new ENTRYFIELD(this)
>    with (this.ENTRYFIELD1)
>       dataLink = form.vend1.rowset.fields["nom"]
>       height = 0.5821
>       left = 4.9477
>       top = 4.101
>       width = 4.5508
>       tabStop = false
>    endwith
>
>    this.TEXTLABEL1 = new TEXTLABEL(this)
>    with (this.TEXTLABEL1)
>       height = 0.5821
>       left = 2.5665
>       top = 4.0746
>       width = 2.2225
>       text = "Rowpointer at"
>    endwith
>
>    this.rowset = this.vend1.rowset
>
>    function MYCOMBOBOX1_onChange()
> //      mval = upper(this.value)  //findkey() will find partial match
>       mval = upper(this.value)+space(18-len(this.value))  //findkey() needs exact match
>      
>       if  form.rowset.findkey(mval)  
>          ?"ok",mval
>          this.before.setfocus()  //Move to next control
>       endif
>       if not form.rowset.findkey(mval)
>          ?"go to msgbox",mval
>          msgbox(mVal+" not found", "Check", 0 + 16)
>          this.value = '    '   //delete invalid name
>       endif
>       return
>
>    function MYENTRYFIELD1_onGotFocus()
>      //Move focus back to combobox if user enters invalid name
>       if empty(form.mycombobox1.value)
>           form.mycombobox1.setfocus()
>           form.mycombobox1.keyboard('{home}')
>           inkey(.01)  //Minimal delay otherwise next instruction is skipped
>           form.mycombobox1.keyboard('{ctrl+shift+end}') //select all
>       endif          
>       return
>
>    function form_onClose()
>       cCuaenter = form.cuaenter
>       set cuaenter &cCuaenter
>       return
>
>    function form_onOpen()
>       form.cuaenter = set('cuaenter')
>       set cuaenter off
>       return
>
>    function form_open()
>       form.rowset.indexname = "NOMVEND"
>      form.mvendarray = new array()
>       form.rowset.first()
> //     form.mvendarray.add("")
>       do while not form.rowset.endofset
>         form.mvendarray.add(form.rowset.fields["nom"].value)
>          form.rowset.next()
>       enddo
>       form.myComboBox1.datasource = 'array form.mvendarray'
>       form.mYCombobox1.value := 'Enter a name or select from dropdown list'
>       return FORM::open()
>
> endclass
>

Mervyn,
to let you know, I added a blank value at the biginning of the datasource because in my global form the user can choose a blank value.

and after reading your code I tried the change below in the OnChange event of the combobox.

   function MYCOMBOBOX1_onChange()
      mval = upper(this.value)
//      if  form.rowset.findkey(mval)
      if  form.rowset.findkey(mval) and form.rowset.fields["nom"].value == mval && for exact match
         ?"ok"
      else
         ?"go to msgbox"
         inkey() && added instruction
         msgbox("not found", "Check", 0 + 16)
      endif
      return

and it seems to give expected result.
Many thanks for support

Many thanks to Lee Grant too.

Michel