redisplay form on invalid input?

Discussion in 'Cadence' started by Erik Wanta, Jul 26, 2003.

  1. Erik Wanta

    Erik Wanta Guest

    I have a SKILL form. The user specifies a bunch of options and then
    hits OK. A callback (ftCB) is then called. I verify that the options
    are valid in the callback and redisplay the form if not to allow the
    user to fix the problem. After the form has been redisplayed, and the
    user puts correct options, the form callback is called the number of
    times they entered incorrenct options.

    I wrote some test code to show the problem (see below). Load it and
    click on bad input and then hit OK. Note that the form is displayed
    again. Now, uncheck bad input and hit OK. Note that hello is printed
    twice. I was expecting that the callback ftCB would only be run once.
    Why is it run twice? How would you suggest I handle the case where
    the user enters invalid input and then hits OK on the form? Note that
    I have a number of boolean buttons and the invalid case is when none
    of them are selected.

    printf("ft()\n")

    procedure(ft()
    let(()

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    )

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB(form)
    let(()

    when(form->bb->value
    hiDisplayForm(form)
    )

    ;this gets printed twice, why?
    dprint("hello")

    ) ; let
    ) ; procedure
     
    Erik Wanta, Jul 26, 2003
    #1
  2. Erik Wanta

    Erik Wanta Guest

    It seems ?unmapAfterCB is what I should be using. Does anyone have
    any examples on how to use this? Do I need to check for valid input
    and then set the callback status with hiSetCallbackStatus? In the
    following example, it only prints hello once after I set bad input and
    then unset bad input. However, it doesn't print t for the return as
    it does if I don't set bad input the first time, any ideas? In
    addition, form stays around as a global. hiFormUnmap(form),
    hiDeleteForm(form) doesn't make it go away after bad input is not
    enabled and OK is hit?

    printf("ft()\n")

    procedure(ft()
    let((form)

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    ?unmapAfterCB nil
    )

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB(form2)
    prog(()

    if(form->bb->value then
    dprint("helloinvalid")
    hiSetCallbackStatus(form nil)
    hiDisplayForm(form)
    )

    hiFormUnmap(form)
    hiDeleteForm(form)

    dprint("hello")

    return(t)

    ) ; let
    ) ; procedure
     
    Erik Wanta, Jul 28, 2003
    #2
  3. Quick answer, as I'm in catchup mode. Yes, you should be using
    hiSetCallbackStatus() (and use ?unmapAfterCB when you create the
    form). You should call hiSetCallbackStatus() on every invocation of
    the callback - i.e. set it to nil if it is invalid, or t if valid.

    Andrew.
     
    Andrew Beckett, Jul 28, 2003
    #3
  4. Erik Wanta

    Erik Wanta Guest

    I modified my test case, see below. When I do this, the callback gets
    executed twice if I enter invalid first and then valid. If I don't
    set hiSetCallbackStatus(form t), then it only gets executed once but
    it doesn't print the CB return status. Any ideas why the callback is
    getting executed twice?

    printf("ft()\n")

    procedure(ft()
    let((form)

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB()")
    ?unmapAfterCB nil
    )

    form->xx="2"

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB()
    prog(()

    if(form->bb->value then
    dprint("helloinvalid")
    hiSetCallbackStatus(form nil)
    hiDisplayForm(form)
    )

    hiSetCallbackStatus(form t)

    ;hiFormUnmap(form)
    ;hiDeleteForm(form)

    dprint(form->xx)

    dprint("hello")

    return(t)

    ) ; let
    ) ; procedure
     
    Erik Wanta, Jul 28, 2003
    #4
  5. Erik,

    My guess is because you are calling hiDisplayForm() within the callback. You
    should remove that, change the ?unmapAfterCB nil to ?unmapAfterCB t
    and also change the logic of the callback so that the stuff below the if gets
    done in the else clause of the if (instead of always).

    The hiDisplayForm within the callback will block until the form is OK'd
    and cancelled, at which point it will continue.

    Note, I've not tried the code (offline at the moment), but it certainly
    makes no sense to:

    a) call hiDisplayForm within the callback
    b) use hiSetCallbackStatus when you have unmapAfterCB turned off.

    Andrew.
     
    Andrew Beckett, Jul 29, 2003
    #5
  6. Erik Wanta

    Erik Wanta Guest

    Andrew:
    The following code works, thank you for your help. Note that if I use
    hiRegTimer("hiDisplayForm(form)" 1), my initial approach (no
    unmapAfterCB or setting of CB status) works.

    printf("ft()\n")

    procedure(ft()
    let((form)

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    ?unmapAfterCB t
    )

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB(form)
    prog(()

    if(!form->bb->value then
    printf("valid")
    hiSetCallbackStatus(form t)
    else
    printf("invalid")
    hiSetCallbackStatus(form nil)
    )

    return(t)

    ) ; prog
    ) ; procedure
     
    Erik Wanta, Jul 30, 2003
    #6
  7. Erik Wanta

    Erik Wanta Guest

    Andrew:
    The above code works, but in the real case, I execute a bunch of
    things after hiSetCallbackStatus(form t). Note below that I have it
    sleep 10 seconds after OK it hit. Why does the form still stick
    around for 10 seconds? Is there a way that I can get the form to
    disappear right after I hit OK and get an hourglass until the other
    operations are done?

    printf("ft()\n")

    procedure(ft()
    let((form)

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    ?unmapAfterCB t
    )

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB(form)
    prog(()

    if(!form->bb->value then
    printf("valid")
    hiSetCallbackStatus(form t)
    system("sleep 10")
    else
    printf("invalid")
    hiSetCallbackStatus(form nil)
    )

    return(t)

    ) ; prog
    ) ; procedure
     
    Erik Wanta, Aug 4, 2003
    #7
  8. Hi Erik,

    After calling hiSetCallbackStatus(form t) you can use hiFormUnmap(form) to
    remove the form from the screen (you'll see from the docs that this is
    what this function is for).

    Regards,

    Andrew.
     
    Andrew Beckett, Aug 7, 2003
    #8
  9. Erik Wanta

    Erik Wanta Guest

    Andrew:
    Yeah, I tried hiFormUnmap(form) awhile back but it doesn't work. If I
    run the following and first enable bad input and hit OK and then
    disable bad input and hit OK. The form still sticks around for 10
    seconds.

    printf("ft()\n")

    procedure(ft()
    let((form)

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    ?unmapAfterCB t
    )

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB(form)
    prog(()

    if(!form->bb->value then
    printf("valid")
    hiFormUnmap(form)
    hiSetCallbackStatus(form t)
    system("sleep 10")
    else
    printf("invalid")
    hiSetCallbackStatus(form nil)
    )

    return(t)

    ) ; prog
    ) ; procedure
     
    Erik Wanta, Aug 7, 2003
    #9
  10. Erik,

    In general the hiFlush isn't needed (I didn't need it when I tried), but I think
    that doing the system() completely blocks DFII (including the event loop) so
    it's a little artificial, and probably doesn't represent normal behaviour if you
    have code that operates slowly. I would however put the hiFormUnmap _after_ the
    hiSetCallbackStatus as Pete suggested - rather than before as you
    had done.

    My silly example. Just invoke (abDooDah)

    I implemented the slow code in the function abBeSlow, which does some
    rather inefficient list access!

    (procedure (abBuildSlowForm)
    (let (doodah)
    (setq doodah (hiCreateStringField ?name 'doodah))
    (hiCreateAppForm
    ?name 'abSlowForm
    ?fields (list doodah)
    ?callback 'abDooDahDeh
    ?unmapAfterCB t
    )
    )
    )

    (procedure (abDooDah)
    (unless (boundp 'abSlowForm)
    (abBuildSlowForm))
    (hiDisplayForm abSlowForm)
    )

    (procedure (abDooDahDeh form)
    (if (equal (getq (getq form doodah) value) "stuff")
    (progn
    (hiSetCallbackStatus form t)
    (hiFormUnmap form)
    (abBeSlow)
    )
    (progn
    (hiSetCallbackStatus form nil)
    (printf "Put 'stuff' in the field\n")
    )
    )
    )


    (procedure (abBeSlow)
    (let (lst)
    (for i 0 100000 (setq lst (cons i lst)))
    (for i 0 5000 (last lst))
    ))


    Regards,

    Andrew.
     
    Andrew Beckett, Aug 8, 2003
    #10
  11. Erik Wanta

    Erik Wanta Guest

    Andrew:
    I have found that just redisplaying the form on invalid input works
    better (see below). That is, the form goes away as soon as I hit OK.
    It is more intuitive than unmapAfterCB, hiSetCallbackStatus,
    hiFormUnmap, etc.

    printf("ft()\n")

    procedure(ft()
    let((form)

    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    ) ; list

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    )

    hiDisplayForm(form)

    ) ; let
    ) ; procedure

    procedure(ftCB(form)
    prog(()

    if(!form->bb->value then
    printf("valid")
    system("sleep 10")
    else
    printf("invalid")
    ;redisplay form
    hiDisplayForm(form)
    ) ; if

    return(t)

    ) ; prog
    ) ; procedure
     
    Erik Wanta, Aug 8, 2003
    #11
  12. Erik,

    I think that the (or one) downside of this is that if you subsequently
    decide to cancel the form after filling in the values wrongly, it won't discard
    the values except for any changes made since the last hiDisplayForm - I think
    that the unmapAfterCB approach will though.

    Also, the call stack might start getting fairly nested - which you could
    solve by using ?dontBlock t, I suppose. However, you're unlikely to
    run out of stack space.

    I'm sure Pete will be able to point out if there are any other more glaring
    problems.

    Andrew.
     
    Andrew Beckett, Aug 8, 2003
    #12
  13. Another approach would be to invoke the form from within a loop. The
    loop is controlled by a global variable that the callback uses to
    indicate the form should be redisplayed. It does not solve the issue of
    the Cancel button leaving the fields in the state they were in at the
    end of the previous Okay, but it does prevent the stack from growing. It
    may also be possible to use an invisible field on the form instead of a
    global variable.

    procedure(ft() let((form)
    ff=list(
    hiCreateBooleanButton(
    ?name 'bb
    ?buttonText "bad input"
    )
    )

    ;create form
    hiCreateAppForm(
    ?name 'form
    ?formTitle "Form Issue"
    ?fields ff
    ?callback list("ftCB(form)")
    )

    ; display the form until it has valid data
    formStatus = t
    while(formStatus
    formStatus = nil
    hiDisplayForm(form)
    )

    ;you should destroy the form here since you recreate it every time
    ))

    procedure(ftCB(form) prog(()
    if(!form->bb->value
    then
    printf("valid")
    ;do the work
    system("sleep 10")
    else
    printf("invalid")
    ;redisplay form
    formStatus = t
    )
    return(t)
    ))
     
    Edward J Kalenda, Aug 8, 2003
    #13
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.