22

I have a dialog, which, when pops up, requests input from the user. How can I set the window up that the focus is on the InputField of the new window (i.e. the caret stands in the InputField), so that when the user starts typing, it is immediately registered by the field? At the moment, I have to click inside the field first to make it the active control on screen.

DialogInput[{InputField["", String], Button["Ok", DialogReturn[]]}]
István Zachar
  • 47,032
  • 20
  • 143
  • 291

3 Answers3

14

Since Input is a DialogInput, it seemed reasonable to peek into Input's structure to understand how the focus is set. After removing the ReadProtected attribute I've realized that there is no neat way to do it, as WRI itself has done the reposition of the focus via successive SelectionMove calls.

This example below is not the original but a modified version, as the original Input definition only includes one InputField but no other expressions (like a Button). Note that it is not documented that you can use Initialization in dialogs, moreover it is colored red by the syntax highlighter to suggest an invalid option.

DialogInput[{InputField["", String], Button["Ok", DialogReturn[]]},
 Initialization :> (FrontEndExecute[{
      FrontEnd`SelectionMove[#1, Before, Notebook, 
       AutoScroll -> False],
      FrontEnd`SelectionMove[#1, Next, Cell, 2, AutoScroll -> False],
      FrontEnd`SelectionMove[#1, Previous, CellContents, 
       AutoScroll -> False],
      FrontEnd`FrontEndToken[#1, "MovePreviousPlaceHolder"]
      }] &), ShowCellBracket -> True, Selectable -> True]
István Zachar
  • 47,032
  • 20
  • 143
  • 291
  • +1. I used similar code for my syntax highlighter generator, but wasn't succesful in trying to adopt it here. Good that you managed - another good example of how this is done. – Leonid Shifrin Feb 08 '12 at 09:22
  • 2
    @Mr.Wizard Leonid and Istvan, you all may be interested in fact that WRI changed approach and use now FrontEnd`ReferenceBoxFind which is quite handy and more general. – Kuba Apr 02 '15 at 07:38
  • @Kuba This seems interesting, but do you possess any further information about where, how, and who uses ReferenceBox* and BoxReference* functions? It is hard to experiment with them without any pointer on what they do. – István Zachar Apr 10 '15 at 16:23
  • Only from my own tests, and not much. E.g you can put BoxID almost everythere and it can be simple string. – Kuba Apr 10 '15 at 18:36
12

After István Zachar's points, I was investigating Input definitions to learn more. It seams that 2 years later WRI changed approach from SelectionMove based to more automatic BoxReferenceFind.

usage

So what we only have to do is to set BoxID option for fields of interest and find those references when we want, with:

MathLink`CallFrontEnd[
 FrontEnd`BoxReferenceFind[ 
   FE`BoxReference[
     _NotebookObject, {{ID_String}}, 
     FE`BoxOffset -> {FE`BoxChild[1]},   
     FE`SearchStart -> "StartFromBeginning"
   ]
 ]
]

This is a way more flexible approach, e.g. you can easily put InputField somewhere else and you don't have to change SelectionMove steps to get there.

example

DynamicModule[{name = "", surname = "", setFocus}
  , Column[{
        InputField[Dynamic@name, String, BoxID -> "name"]
      , InputField[Dynamic@surname, String, BoxID -> "surname"]
      , Button["setFocusToFirst", setFocus[EvaluationNotebook[], "name"]]
    }]
  , SynchronousInitialization -> False
  , Initialization :> (
        setFocus[nb_, ID_] :=  MathLink`CallFrontEnd[
            FrontEnd`BoxReferenceFind[ FE`BoxReference[
                nb
              , {{ID}}
              , FE`BoxOffset -> {FE`BoxChild[1]}
              , FE`SearchStart -> "StartFromBeginning"
            ]]
        ]
      ; setFocus[EvaluationNotebook[], "surname"]
    )
]
Kuba
  • 136,707
  • 13
  • 279
  • 740
  • 7
    It is great that this can be done. It is a travesty that users have to poke around in the internals of Mathematica to accomplish a simple task like this. – John McGee May 01 '15 at 10:21
  • Now it's only missing the tab key jump order control ! – P. Fonseca May 04 '15 at 11:48
  • @P.Fonseca On Windows it switches InputFields with Tab quite well. – Kuba May 04 '15 at 11:55
  • Right. But through which order? Can you change the default order? In most visual languages, you can easily change the order of these jumps... – P. Fonseca May 04 '15 at 12:33
  • @P.Fonseca what do you mean by order in case of nonregular layout full of InputFields? You want to be able to provide list of tags (here BoxID) to go through when pressing Tab? – Kuba May 04 '15 at 12:39
  • If I'm not mistaken, most languages just use a kind of sequence ID parameter (it just searches for the next element, following a canonical order of the ID parameter or of an orderID parameter). This allows for old methods: name the objects 10, 20, 30, etc, so that you still have room in between, just in case something is missing during design phase. Having a list of BoxID also seems a good possibility (more clean; although I'm not sure if easier or more complex when working with dynamically generated interfaces; I have a lot of them... kind of objects that the user adds in between others...) – P. Fonseca May 04 '15 at 13:22
  • @P.Fonseca I see, going through explicit list should be doable with EventHandler, don't know if BoxRefferenceFind can handle patterns or find all indexed Boxes in given Cell for more automatic approach. – Kuba May 04 '15 at 13:43
  • I think this deserves to be the definitive answer. Thanks for the research! – István Zachar Mar 23 '16 at 16:28
  • @IstvánZachar Thanks for the accept :) – Kuba Mar 31 '16 at 08:11
  • @Kuba Thanks for figuring this out; it's helped a lot. But I've noticed a bug in the first method (at least in version 11.1.1 for Microsoft Windows (64-bit) (April 18, 2017)) -- editing the cell in which the GUI has been evaluated (e.g., delete the trailing ]) shifts the focus to the originally focused inputfield, and any attempt to move the cursor is unsuccessful -- the notebook becomes unusable. This is not an issue with the second method. – jjc385 May 28 '17 at 18:18
  • @Kuba (continued) Could the problem be that setFocus appears in the argument of Composition outside of the DynamicModule? – jjc385 May 28 '17 at 18:20
  • 1
    @jjc385 It really breaks, it seems that CellDynamicExpression wasn't fully fixed: https://mathematica.stackexchange.com/q/126655/5478. I will delete this example as this is a long term problem and I don't believe it will be fixed anytime soon. Thanks for a feedback. – Kuba May 29 '17 at 11:13
4

What's wrong with Input[""]?

DavidC
  • 16,724
  • 1
  • 42
  • 94
  • I must assume it is not general enough, that he is building an entire dialog and that example given is quite reduced. – Mr.Wizard Feb 07 '12 at 22:51
  • Nothing is wrong with Input but as Spartacus has pointed out, it is not general enough. Nevertheless, this pointed me to the right direction, so thanks David! – István Zachar Feb 07 '12 at 23:29
  • Spartacus is right. My suggestion was really aimed at quick fix. By the way, István, how did you manage to peek into Input's structure? – DavidC Feb 08 '12 at 00:04
  • 3
    @David: The usual way: by removing all attributes (Attributes[Input] = {}) and then querying the definition as ??Input. This trick could give useful insight only if the symbol is ReadProtected (meaning that most of its definition is written in Mathematica instead of C or whatnot), or not even then. – István Zachar Feb 08 '12 at 00:13