Context Added to End
In a previous question, I was looking for a way for an InputField
to maintain the input structure of expressions so as to allow the user's input (say, in scientific notation) to be maintained. Here is the code I developed to solve that problem:
HoldBoxesInputField[Dynamic[var_], Dynamic[boxes_]] :=
DynamicModule[{},
If[boxes == Null, boxes = ToBoxes[var]];
InputField[Dynamic[boxes, {Temporary,
Function[result, boxes = result;
var = ToExpression[boxes]]}],
Boxes]];
Then in calling this function, I pass both the variable and the boxes as dynamic. This works well except in cases where I need have an intermediate value of the boxes that is not able to be interpreted as an expression. For example, I have the user inputting the names of various symbols, which I then add to a dynamically modified palette of PasteButton
structures. So if, in one of these InputField
boxes, I click one PasteButton
, type +, and then try to click another PasteButton
, because the expression is not complete and yet with the click I have navigated away from the InputField
, ToExpression
executes and returns an error. Here is an example with some context:
DynamicModule[{equations, eqboxes, constants, constboxes, numeq, numconst},
constants[_] = c;
equations[_] = left == right;
eqboxes[_] = Null;
constboxes[_] = Null;
numeq = 1;
numconst = 1;
Column[{
Panel[Column[Join[
{Style["Constants", Bold]},
{Dynamic[Grid[{"Constant " <> ToString[#] <> ": ",
HoldBoxesInputField[Dynamic[constants[#]],
Dynamic[constboxes[#]]]} & /@ Range[numconst]]]},
{Button["Add Constant", ++numconst]}]]],
Panel[Column[Join[
{Style["Equations", Bold]},
{Dynamic[Grid[{"Equation " <> ToString[#] <> ": ",
HoldBoxesInputField[Dynamic[equations[#]],
Dynamic[eqboxes[#]]]} & /@ Range[numeq]]]},
{Button["Add Equation", ++numeq]}]]],
Panel[Dynamic[Column[Join[
{Style["Pasting Palette", Bold]},
Dynamic@PasteButton[ToString[constants[#]], constants[#]] & /@
Range[numconst]]]]]}]]
So the fix, it seemed to me, was to use Check. Here is what I tried:
HoldBoxesInputField2[Dynamic[var_], Dynamic[boxes_]] :=
DynamicModule[{oldval},
If[boxes == Null, boxes = ToBoxes[var]];
oldval = var;
InputField[Dynamic[boxes, {Temporary, Function[result, boxes = result;
var = Quiet@Check[ToExpression[boxes], oldval];
If[var != oldval, oldval = var]]}],
Boxes]];
The idea is to hold on to the old value, and use that if converting to an expression fails, but then update the old value whenever the conversion to an expression succeeds. And that part seems to work. But in the process it broke two other things. Test code is the same as for the first case, just with HoldBoxesInputField2
in place of HoldBoxesInputField
. In the first version, I could Tab from InputField
to InputField
. In the second version, if the palette of PasteButton
structures changes, the Tab now fails. In addition, when I paste into an equation on the right-hand-side, the first paste moves the cursor to the beginning of the notebook and pastes there instead of into the field. Animation showing this behavior is below. So my questions: why does the new code change those behaviors, and what can I do about it? Thanks!
Edited to Add
A commenter asked for context. Here you go.
I am developing a package for chemists to use to do chemical kinetics. Most chemists are not particularly proficient in Mathematica, so I am developing a dynamic interface that lets them do the work without having to dive too deeply into the language. Some underpinnings of the project can be found on my website (http://kevinausman.net).
Regardless, here is the interface I am working on. Using other routines (from the website), they can enter chemical mechanisms in standard chemistry notation. On one tab they can select the elements of the mechanism they want to include in the kinetic modeling:
The system automatically turns the mechanism into a set of differential rate equations. But the measurable quantities are often not directly implied by these equations. So on the next tab I allow them to enter other time-dependent equations and parameters, including specifying whether parameters are fixed, variable, or calculated from other quantities, as shown here:
That is the screen that is causing me headaches. Following this tab, the user can then interactively adjust the model compared to experimental data, do fitting, and extract statistics from it. For example:
And:
So that is my context. It is a relatively massive interactive interface that needs to seamlessly handle input by someone who is only somewhat familiar with Mathematica, but who wants to take advantage of the incredible calculation capabilities of the package. I am organizing the package in a way that gives the user access to the features that are relevant to solving the particular types of problems that chemists need, but am hiding from them most of the coding.
The problem is arising in cases where the user is entering equations in the second tab that are not yet complete. I need Mathematica to interpret the results as soon as another tab is selected, because the equations are used in multiple places, but I also need them to be able to click on dynamically-generated paste buttons to enter their custom-defined symbols into the equations. In my example, if they have abs60[t]+ entered in the abs[t] field, and then click on abs70[t], an error is thrown, because by navigating away from the field to click on the paste button, Mathematica tries to interpret the contents of the field (which is incomplete). And yet if I try to catch the error using Check, the behavior goes really wonky, as I described in my original question, with pasting happening at the top of the notebook instead of in the field.
I hope that context helps.
ToExpression
unless you really want to use that expression. Don't do that in your controllers. Just keep your variables and equations in box form and convert them when you need them. You can Paste/NotebookWrite boxes anyway. p.s. feedback on my answer to your last question is appreciated: 204157 $\endgroup$