Combo control

This forum is for eXpress++ general support.
Message
Author
User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Combo control

#1 Post by sfsltd »

We need to improve the way we find records in a table and select them to fill in a field on a form.

Ideally we are looking for a 'combo' type control with 'Google type' functionality.
i.e. after the user clicks-on (or tabs-into) a field and starts typing, the characters entered are used to look for matches in a table, either:

a) from the beginning of the field.
b) against any part of the field string.

When the user types the first character, a drop down list of matching records should appear under the field.
As more characters are typed, the list of matching records should shrink.
When only one record matches, then this is becomes the field value.

Our solution:
We currently achieve this by displaying a browse below a input field.

The problem:
Using two controls, a DCGET() and DCBROWSE() creates a workable but 'disjointed' solution where the focus can switch between the controls if the user (say) stops typing and clicks on the browse.

Is there an Express++ 'combo' type control, or some sample code that might help us do this more efficiently?

Thx
Michael

User avatar
rdonnay
Site Admin
Posts: 4729
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: Combo control

#2 Post by rdonnay »

Michael -

The below code is from the "Scoped Dropdown" sample in Sample Group 6 of Xdemo.

Code: Select all

FUNCTION XSample_187()

/* This example demonstrates how to use the KEYBLOCK clause
   and COMBO clause  @..DCSAY..GET to drop down a list of
   valid names and scope the list based on the characters
   entered.  If names are in a database, use dbSeek() and
   DC_SetScope() in place of Ascan(). */

LOCAL GetList[0], GetOptions, cName, aNames, cPerformer, lImmediate

cPerformer := Space(30)

aNames := PerformerNames()

@ 0,0 DCSAY 'Enter Performer Name' GET cPerformer ;
      SAYSIZE 0 SAYBOTTOM ;
      KEYBLOCK {|a,b,o|DropDownNames(a,b,o,@cPerformer,aNames)} ;
      COMBO HEIGHT 10 DATA aNames

lImmediate := DC_GetComboImmediate(.t.)
DCREAD GUI FIT TITLE 'Scoped Drop-Down' MODAL
DC_GetComboImmediate(lImmediate)

RETURN nil

* -----------

STATIC FUNCTION DropDownNames( nKey, mp2, oGet, cPerformer, aNames )

LOCAL nFound, cName, nLen := Len(cPerformer), aPerformers

IF Chr(nKey) < 'A' .OR. Chr(nKey) > 'z'
  RETURN nil
ENDIF

oGet:getData()

cName := Alltrim(Upper(cPerformer))

ASize(aNames,0)

aPerformers := PerformerNames()
nFound := AScan( aPerformers, {|c|Alltrim(Upper(c)) = cName} )

IF nFound > 0
  DO WHILE nFound <= Len(aPerformers) .AND. Alltrim(Upper(aPerformers[nFound])) = cName
    AAdd( aNames, aPerformers[nFound])
    nFound++
  ENDDO
  oGet:comboData := aNames  // store scoped array to datasource
  PostAppevent(xbeP_Activate,,,oGet:popupButton) // popup scoped dropdown
  DC_CompleteEvents()
ENDIF

oGet:comboData := aPerformers // store full array to datasource

IF Empty(aNames)
  AAdd(aNames,'')
ENDIF

RETURN nil
The eXpress train is coming - and it has more cars.

User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Re: Combo control

#3 Post by sfsltd »

Thanks Roger, will give it a go.
Michael

Cliff Wiernik
Posts: 605
Joined: Thu Jan 28, 2010 9:11 pm
Location: Steven Point, Wisconsin USA
Contact:

Re: Combo control

#4 Post by Cliff Wiernik »

I also use the following, to keep control always in the separate input dcget. You can navigate the browse with the cursor or mouse, but focus always returns to the seek box.

Code: Select all

  @ .2,1 DCSAY 'Enter Secured Party' GET cSeek  ;      
          SAYRIGHTBOTTOM PICTURE '@!' ;                                         // defines seek key for auto seek
          GETOBJECT d_oSeekkey ;
          PARENT d_oTabstatic1  ;
          SAYSIZE 0  ;
          EDITPROTECT {|| .F.}   ;
          LOSTFOCUS {|| cSeek := space(20), d_oSeekkey:setdata() }     ;
          KEYBLOCK {|a,b,o| iif(LB_CheckForPlusMinus(a,b,o),NIL,       ;                             
                                DC_BrowseAutoSeek(a,o,d_oBrowse,,,'',  ;
                                {|a| iif(empty(a),'',LB_RightAdj(a,4,'0',,.T.))}))}

  @ 1.3,.4 DCSTATIC TYPE XBPSTATIC_TYPE_RECESSEDBOX OBJECT d_oPagegroup1       ;
            SIZE nTPWidth-1.2,nTPHeight-2.9 PARENT d_oTabstatic1 ;
            COLOR GRA_CLR_BLACK,m->G_nBGColor 
    
  @ .2,.5 DCBROWSE d_oBrowse ALIAS 'TEMPLATE' SIZE nTPWidth-2,nTPHeight-3.4 ;
            EVAL {|o| LB_VisualStyle(o,.T.) }    ;
            HEADLINES 1 ;
            PARENT d_oPagegroup1       ;
            PRESENTATION DC_BrowPres() ;
            FIT ;
            CURSORMODE XBPBRW_CURSOR_ROW ;
            GROUP 'BROWSE' ;
            ID 'OBROWSE' ;
            NOHSCROLL ;
            GOTFOCUS {|| SetAppFocus(d_oSeekkey)} ;
            ITEMMARKED {|| d_oDialog:SetTitle(d_cTitle+' - '+TEMPLATE->sec_name), ;
                           DC_GetRefresh(GetList,,,,{'TOOLBAR'})}  ;
            ITEMSELECTED {|| PostAppEvent(xbeP_Keyboard,xbeK_F3,,d_oDialog)}

User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Re: Combo control

#5 Post by sfsltd »

Thanks Cliff

Was going to ask about how to keep focus on the dcget after we have opened the browse.
When we dropped the list in our old control, focus changed so the user could not continue typing into the dcget.

Michael

User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Re: Combo control

#6 Post by sfsltd »

Cliff

Would you please clarify these externals, are they trapping keys:

Code: Select all

LB_CheckForPlusMinus
LB_RightAdj
Thanks
Michael

User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Re: Combo control

#7 Post by sfsltd »

Cliff

one more thing..
... is the browse part of the same dialogue ... or is it a pop-up?

Michael

User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Re: Combo control

#8 Post by sfsltd »

Cliff / Roger

This looks like a good fit for what we are trying to do provided the dcbrowse() appears as a "pop-up".

If the browse element is not a pop-up ... can the code be amended to do so... without changing the way the focus stays with the DCGET()?

I can see another external ... LB_VisualStyle... any more info on this, so we can get this working?

Thanks, again
Michael

Cliff Wiernik
Posts: 605
Joined: Thu Jan 28, 2010 9:11 pm
Location: Steven Point, Wisconsin USA
Contact:

Re: Combo control

#9 Post by Cliff Wiernik »

Did you get the information I emailed you.

Cliff

User avatar
sfsltd
Posts: 28
Joined: Sat Jan 30, 2010 7:23 am
Location: UK

Re: Combo control

#10 Post by sfsltd »

Cliff

Yes thankyou, I got the attachments when I got back from my trip.

The way you keep the focus on the dcget() seems to be just what we are looking to achieve.
I can see from your screenshot that you have the 'parent' dcget() & 'child' dcbrowse() on the same form.

The difference we see to our needs, is we are looking to have the dcbrowse() appear as a modal "pop-up" object...
... this raises the question of if/how the focus can be returned to the dcget() on the original form.

Michael

Post Reply