3
$\begingroup$

In a dynamic interface, I am using a custom replacement for InputField that tracks two things separately:

  1. The value of the variable that is input.
  2. The boxes that comprise the user-entered expression.

This way, the user-entered formatting is kept (e.g., scientific notation), incomplete entry is handled smoothly, and the boxes can be initialized to a given number of digits.

Here is a pared-down version:

holdIF[Dynamic[var_], Dynamic[boxes_]] := 
  DynamicModule[{updateFunction}, 
    If[boxes == Null, 
       boxes = ToBoxes[SetPrecision[var, 5]]]; 
    InputField[Dynamic[boxes, {Temporary, updateFunction}], Boxes], 
      Initialization :> (SetAttributes[updateFunction, HoldRest]; 
        updateFunction[new_, boxVar_] := 
          With[{expr = Quiet@ToExpression@new}, boxes = new; 
            If[expr =!= $Failed, var = expr]
          ]
       )
  ]

And here is some test code showing it at work.

testvar = 1.23456789;
testboxes = Null;
holdIF[Dynamic[testvar], Dynamic[testboxes]]
Dynamic[{NumberForm[testvar, \[Infinity]], testboxes}]

enter image description here

However, the value of the variable can be modified elsewhere in the dynamic interface. The idea is that the variable are estimates for parameters in nonlinear model fitting; the user enters values and looks at the result in a dynamically-updating plot, and when a suitable starting-point has been found, the user clicks a Button to initiate an automatic search for a better fit. I therefore want the values displayed in the InputField boxes to update based on changes to the variable parameters. What would be really nice is if I could signal that the holdIF function should update its box representation by simply setting the boxes variable to Null.

This works if I wrap the holdIF call in a Dynamic wrapper, because that then regenerates the DynamicModule when testboxes changes.

testvar = 1.23456789;
testboxes = Null;
Dynamic[holdIF[Dynamic[testvar], Dynamic[testboxes]]]
Dynamic[{NumberForm[testvar, \[Infinity]], testboxes}]

enter image description here

But it really seems that this shouldn't be necessary. Both var and boxes are Dynamic in the call, so shouldn't there be a way within the holdIF function to notice that boxes has been set to Null and as a result reinitialize var without having to redraw the InputBox? Thoughts?

$\endgroup$
3
$\begingroup$

Pardon me if I miss the point, as this looks rather complicated but I'm only giving it a quick look-over. Does it work to move your first If expression inside the Dynamic as follows?

holdIF[Dynamic[var_], Dynamic[boxes_]] := DynamicModule[{updateFunction},
  InputField[
   Dynamic[If[boxes === Null, boxes = ToBoxes[SetPrecision[var, 5]]]; 
    boxes, {Temporary, updateFunction}], Boxes], 
  Initialization :> (SetAttributes[updateFunction, HoldRest];
    updateFunction[new_, boxVar_] := 
     With[{expr = Quiet@ToExpression@new}, boxes = new;
      If[expr =!= $Failed, var = expr]])]
$\endgroup$
  • $\begingroup$ Wonderful! Works perfectly! I figured it would have something to do with putting the If statement in a Dynamic, but I was intimidated by it being inside the InputField, and so didn't know how to try it. Thank you! $\endgroup$ – Kevin Ausman Nov 6 '19 at 21:43
  • $\begingroup$ @Kevin Glad I could help. :-) $\endgroup$ – Mr.Wizard Nov 6 '19 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.