dcget keyblock

This forum is for eXpress++ general support.
Message
Author
Zdeno Bielik
Posts: 147
Joined: Thu Jan 28, 2010 9:24 am
Location: Nitra, Slovakia
Contact:

dcget keyblock

#1 Post by Zdeno Bielik »

Hi Roger,

is it possible add new additional parameter e.g. called KB_DELAY <nSeconds>, which will work with KEYBLOCK parameter, and associated <bKeyBlock> of current DCGET object will be performed only if delay between typing of characters are equal or more as <nSeconds>?

e.g. examaple:

nMyDelay := 0.25 // 0.5 or any other needed values

DCGET cName ;
KEYBLOCK { |a,b,o| My_Set_Scope_Or_Filter_Or_Something( a, b, o, oBrowse, @cName ) } ;
KB_DELAY nMyDelay

Problem is, when in database are more records and/or KEYBLOCK clause must do more actions(e.g. set filter/scope, check/find some other needed info/validations etc...), continuously refreshing of browse object is huge slowdown and sometimes in not needed immediatelly.
So I want(and I think this will appreciate more/most eXpress users) while end-user typing some characters into get, only when there is delay(default value will be 0, so like it is now - immediately) more then <nDelay>, keyblock clause will be done.

Or have someone else any other solution for this?

Many thanks
Zdeno

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

Re: dcget keyblock

#2 Post by rdonnay »

Zdeno -

I agree that this can be useful but it is not something that I would want to add to eXpress++. This can be done in your own code as shown below.

I suggest adding the function MyKeyDelay() to your library, then you can use it whenever you need it in your KEYBLOCK clauses.

Compile and run the below code. It will function as you requested.

Roger

Code: Select all

#INCLUDE "dcdialog.CH"

FUNCTION Main()

LOCAL GetList[0], cGet := Space(50), aDir := Directory(), oBrowse

@ 0,0 DCGET cGet KEYBLOCK {|n,x,oGet|MyKeyDelay(n,.3), MyKeyboard(n,oBrowse,oGet)}

@ 2,0 DCBROWSE oBrowse DATA aDir SIZE 60,10

DCBROWSECOL ELEMENT 1 HEADER 'File Name' WIDTH 50 PARENT oBrowse

DCREAD GUI FIT

RETURN nil

* ----------

FUNCTION MyKeyDelay( nKey, nDelay )

LOCAL nEvent, oXbp, mp1, mp2, nSeconds := Seconds()

DEFAULT nDelay := 0

IF nDelay > 0
  DO WHILE Seconds() - nSeconds < nDelay .AND. nKey < 60000
    nEvent := AppEvent(@mp1,@mp2,@oXbp,.1)
    IF Valtype(oXbp) == 'O'
      oXbp:handleEvent(nEvent,mp1,mp2)
    ENDIF
  ENDDO
ENDIF

RETURN nil

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

STATIC FUNCTION MyKeyboard( nKey, oBrowse, oGet )

LOCAL cBuffer := Trim(oGet:get:buffer), nArrayElement

nArrayElement := AScan(oBrowse:dataSource,{|a|Upper(a[1])=Upper(cBuffer)})

IF nArrayElement > 0
  oBrowse:arrayElement := nArrayElement
ENDIF

oBrowse:refreshAll()

RETURN nil

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

PROC appsys ; return
The eXpress train is coming - and it has more cars.

Zdeno Bielik
Posts: 147
Joined: Thu Jan 28, 2010 9:24 am
Location: Nitra, Slovakia
Contact:

Re: dcget keyblock

#3 Post by Zdeno Bielik »

Hi Roger,

many thanks for workaround, it works, but not exactly, how I thinked/want/need.
There is one little problem:
after wanted nDelay(in your sample 0.3) next MyKeyboard() action is performed N times,
where N is number of characters typed into get while MyKexDelay() waits for suspended typing into get.

You can simple simulate this in your sample,
just change 0.3 to e.g. 1.5 like parameter into MyKeyDelay(n,1.5)
and add in function MyKeyboard() line dcdebug nArrayElement after nArrayElement := AScan(oBrowse:data ...

now start typing any file name from oBrowse list, minimal e.g. 4 or 5 file characters

as you can now see, code in MyKeyboard() is done 4 or 5 times(== number of entered chars), not only once

It looks like events in MyKeyboard() must be any proccessed, characters typed into get must be still continuously showing, and after nDelay only once keyblock's action must be done. Or may be I am wrong...
But I have no idea, how do it in your code.
Please, can you look at this?

Many thanks
Zdeno

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

Re: dcget keyblock

#4 Post by rdonnay »

Try this:

Code: Select all

#INCLUDE "dcdialog.CH"

FUNCTION Main()

LOCAL GetList[0], cGet := Space(50), aDir := Directory(), oBrowse

@ 0,0 DCGET cGet KEYBLOCK {|n,x,oGet|MyKeyDelay(n,.3,oGet,{|oGet|MyKeyboard(oBrowse,oGet)})}

@ 2,0 DCBROWSE oBrowse DATA aDir SIZE 60,10

DCBROWSECOL ELEMENT 1 HEADER 'File Name' WIDTH 50 PARENT oBrowse

DCREAD GUI FIT

RETURN nil

* ----------

FUNCTION MyKeyDelay( nKey, nDelay, oGet, bBlock )

LOCAL nEvent, oXbp, mp1, mp2, nSeconds := Seconds()

wtf nKey

DEFAULT nDelay := 0

IF nDelay > 0
  DO WHILE Seconds() - nSeconds < nDelay .AND. nKey < 60000
    nEvent := AppEvent(@mp1,@mp2,@oXbp,.1)
    IF Valtype(oXbp) == 'O'
      oXbp:handleEvent(nEvent,mp1,mp2)
    ENDIF
  ENDDO
ENDIF

Eval(bBlock,oGet)

RETURN nil

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

STATIC FUNCTION MyKeyboard( oBrowse, oGet )

LOCAL cBuffer := Trim(oGet:get:buffer), nArrayElement

nArrayElement := AScan(oBrowse:dataSource,{|a|Upper(a[1])=Upper(cBuffer)})

IF nArrayElement > 0
  oBrowse:arrayElement := nArrayElement
ENDIF

oBrowse:refreshAll()

RETURN nil

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

PROC appsys ; return
The eXpress train is coming - and it has more cars.

Zdeno Bielik
Posts: 147
Joined: Thu Jan 28, 2010 9:24 am
Location: Nitra, Slovakia
Contact:

Re: dcget keyblock

#5 Post by Zdeno Bielik »

Hi Roger,

unfortunately, with your updated code result is the same.
If you add debug line
dcdebug cBuffer, Len( cBuffer ), nArrayElement
in fnc. MyKeyboard(),
you will see, that this function is executed N times and not only once.
It looks like keyboard's action is only stopped for that time
(more better for tests will be value e.g. 1.5 then your 0.3),
but then it is evaluated N times for all entered characters at once.
Hmmm, may be there is something internal code in eXpress++
for KEYBOARD cluase, which overwrites this your new code.

I kindly ask you for any next idea - thanks

Zdeno

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

Re: dcget keyblock

#6 Post by rdonnay »

Are you sure you are compiling the code sample I gave you?

I do not get such a result as you.
The eXpress train is coming - and it has more cars.

Zdeno Bielik
Posts: 147
Joined: Thu Jan 28, 2010 9:24 am
Location: Nitra, Slovakia
Contact:

Re: dcget keyblock

#7 Post by Zdeno Bielik »

Hi Roger,

as you can see in attached video, function MyKeyboard() is evaluated N times(lenght of just entered text).
What do I wrong?

http://www.acesystem.sk/domain/programy/keyblock.zip

Zdeno

skiman
Posts: 1185
Joined: Thu Jan 28, 2010 1:22 am
Location: Sijsele, Belgium
Contact:

Re: dcget keyblock

#8 Post by skiman »

Hi Zdeno,

It will be very difficult to implement this. I think it can't be added to the KEYBLOCK.

What in the following case: Enter 5 characters fast and stop typing.

You expect that the keyblock isn't avaluated, because you typed fast.
The moment you stop the typing, the KEYBLOCK isn't called anymore.

Result: nothing happened.
Best regards,

Chris.
www.aboservice.be

Zdeno Bielik
Posts: 147
Joined: Thu Jan 28, 2010 9:24 am
Location: Nitra, Slovakia
Contact:

Re: dcget keyblock

#9 Post by Zdeno Bielik »

Zdeno Bielik wrote: as you can see in attached video, function MyKeyboard() is evaluated N times(lenght of just entered text).
What do I wrong?

http://www.acesystem.sk/domain/programy/keyblock.zip
Hi Roger,

if you will have a little free time, can you look at my video and sample?

Thanks
Zdeno

User avatar
jdsoft
Posts: 113
Joined: Thu Jan 28, 2010 1:13 pm
Location: Overberg
Contact:

Re: dcget keyblock

#10 Post by jdsoft »

Hello,

Assuming you want a delayed auto-seek.
Typing quicly 5 charachters, and then if no charcacter is pressed for 0.5 seconds, or [Enter] is pressed, the seek comences.

In your keyblock, insert the code:

Code: Select all

Procedure _MyKeyblock(....)
LOCAL oTimer  := Sy_Timer():New()
LOCAL nDelay  := 0.5
LOCAL nEvent := 0
LOCAL mp1, mp2, oXbp
LOCAL cSeek  := o:EditBuffer()  // Content of current DCGET object

         .......
         oTimer:Mark(nDelay)
         do while !oTimer:Timeout()
            nEvent   := NextAppEvent( @mp1, @mp2, @oXbp )
            if nEvent <> xbe_None
               nEvent   := AppEvent( @mp1, @mp2, @oXbp )
               if ValType(oXbp) = "O"
                  if nEvent = xbeP_Keyboard                                   // a Key was hit
                     oTimer:Mark(nDelay)                                      // Reset timeout
                     do case
                        case mp1 = 13
                           nKey  := xbeK_ENTER
                           exit
                        case mp1 = xbeK_BS
                           if !Empty(oXbp:EditBuffer())
                              oXbp:HandleEvent(nEvent,mp1,mp2)
                           endif
                        case mp1 <> 10
                           oXbp:HandleEvent(nEvent,mp1,mp2)
                     endcase
                  else
                     oXbp:HandleEvent(nEvent,mp1,mp2)
                  endif
               endif
            endif
         enddo
      endif
      cSeek := o:editbuffer()
      lSoftSeek := Set(_SET_SOFTSEEK,.t.)
      SEEK AllTrim(cSeek))
      Set(_SET_SOFTSEEK,lSoftSeek)
   endif
....
below the code for Sy_Timer():New()

Code: Select all

/*
 Timer class
 By Jack Duijf
 Date 17-09-2005

 This simple timer class prodvides a simple mechanism determin timeouts on a max 24h basis
 ::Mark() sets the starting point.
 ::TimeOut() checks if timeout has occured

 Procedure Sample
 LOCAL oTimout    := Sy_Timer():New()

 oTimeOut:Mark(20)   // 20 second timeout
 Do while .T.
   if oTimeOut:Timeout()
      exit
   endif
   ....
 Enddo
 Return
*/


CLASS Sy_Timer
HIDDEN:
VAR      nStartTime
VAR      nStopTime
VAR      dStart
VAR      lEnable
INLINE METHOD Now ; Return ((Date() - ::dStart) * 86400) + Seconds()          // Current elapsed in seconds

EXPORTED:
METHOD   Init
METHOD   Mark                                                                 // Mark timerout in seconds
METHOD   TimeOut                                                              // Check timout elapsed
METHOD   MarkTime                                                             // Mark timout in hh:mm:ss
METHOD   EndTime                                                              // Date and time of timeout moment
INLINE METHOD   Enable ; ::lEnable := TRUE   ; Return                         // Enable Timer
INLINE METHOD  Disable ; ::lEnable := FALSE  ; Return                         // Disable Timer
VAR      Cargo
ENDCLASS

METHOD   Sy_Timer:Init()
::dStart                := Date()                                             // Date of instance create
::Mark()                                                                      // Set marker
Return SELF

METHOD   Sy_Timer:Mark(nTimeout)                                               // Mark start-time
Default nTimeOut  To 0
::nStartTime            := ::Now()                                            // Save current time
::nStopTime             := ::nStartTime + nTimeOut                            // Calculate stop time
::Enable()                                                                    // Enable Time-out
Return

METHOD   Sy_Timer:TimeOut(nTimeOut)
LOCAL nNow              := ::Now()                                            // Capcure now in seconds
if ValType(nTimeOut) = "N"                                                    // Alternative timeout in seconds
   Return (nNow >= (::nStartTime + nTimeOut))                                 // nTimeout passed marker ?
endif
Return ::lEnable .and. (nNow >= ::nStopTime)

METHOD   Sy_Timer:EndTime()                                                    // Text persentation of timout moment
LOCAL cRet              := ""
LOCAL nSecs             := ::nStopTime                                        // Current timeout in seconds
LOCAL nDays             := 0
LOCAL nHours            := 0
LOCAL nMins             := 0

nDays                   := Int(nSecs /86400)   ; nSecs -= (nDays   * 86400)
nHours                  := Int(nSecs / 3600)   ; nSecs -= (nHours  *  3600)
nMins                   := Int(nSecs /   60)   ; nSecs -= (nMins   *    60)

if nDays > 0
   cRet                 := Dtoc(::dStart + nDays) + " "
endif
cRet                    += StrZero(nHours,2)    + ":"
cRet                    += StrZero(nMins,2)
if nSecs > 0
   cRet                 += ":" + StrZero(nSecs,2)
endif
Return cRet

METHOD   Sy_Timer:MarkTime(cTime,dDate)
//
// cTime = HH:MM:SS
// dDate = Date() (Optional)
//
LOCAL nSecs             := 0
Default dDate To Date()
cTime                   := Padr(cTime,8,"0")                                  // Add "0" if absent
nSecs                   := Val(Substr(cTime,1,2)) * 3600                      // Hours
nSecs                   += Val(SubStr(cTime,4,2)) * 60                        // Minutes
nSecs                   += Val(SubStr(cTime,7,2))                             // Seconds
::nStopTime             := ((dDate - ::dStart) * 86400) + nSecs               // Stop-time
::Enable()                                                                    // Enable Time-out
Return


I hope this works for you.

Regards,
Jack Duijf
Regards,
Jack Duijf

Post Reply