8

Occasionally it would be preferable to have some initialization code for palettes (of buttons). For example, it could define some functions that are used by palette buttons.

What is the easiest and preferable way to define/run initialization code for a palette?

  • The initialization can run either when the palette is loaded or when any button is pressed for the first time (possible issue: what if the kernel is restarted after the palette was loaded?)
  • The definitions should be somehow localized (i.e. in their own context -- do unique notebook contexts help here?)
  • If possible, I'd prefer a minimal effort solution (i.e. extra code at the fewest possible places, self contained palette file with no extra package files, palette creation using the existing convenience tools of palettes menu or CreatePalette, etc.)
  • (You can assume that the initialization code runs fast, e.g. it consists of definitions only)
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
Szabolcs
  • 24,728
  • 9
  • 85
  • 174
  • @Mr.Wizard Despite some issues it might have (e.g. double or delayed initialization), it appears to have worked for the somewhat restricted use case I have. – Szabolcs Oct 31 '11 at 15:25
  • @Mr.Wizard See here for a possible problem: https://groups.google.com/d/topic/comp.soft-sys.math.mathematica/n-lh8sc83Qs/discussion – Szabolcs Oct 31 '11 at 15:27

2 Answers2

10

You're right to be concerned about the visibility of the Dynamic being an issue. The way to absolutely guarantee a Dynamic expression to be evaluated regardless of the visibility of any of the individual cells is to use NotebookDynamicExpression. Here's an example that illustrates NotebookDynamicExpression working while a Dynamic fails because it's hidden within a closed cell group:

cell1 = First @ MakeBoxes[
    TextCell["Click to open", "Title", 
        CellMargins -> 0, System`WholeCellGroupOpener -> True],
    StandardForm];
cell2 = First @ MakeBoxes[
    ExpressionCell[DynamicWrapper["hidden cell", Print["DynamicWrapper"]]], 
    StandardForm];
CreatePalette[
    Notebook[{Cell[CellGroupData[{cell1, cell2}, Closed]]}, 
        NotebookDynamicExpression :>
            Dynamic[Refresh[Print["NotebookDynamicExpression"], None]]]]

When you evaluate this, note that the Dynamic in NotebookDynamicExpression evaluates immediately. The DynamicWrapper never evaluates until you open the cell group, which you can do by clicking on the "Click to open" text.

In this example, incidentally, notice that I wrapped the NotebookDynamicExpression with Refresh. The function Refresh[#, None]& will make sure that the code evaluates only once -- when the notebook is first opened. Otherwise, the code would obey the standard properties of Dynamic and evaluate whenever any of the dependencies change.

NotebookDynamicExpression has been around since v6, but was only documented in v8. Also documented are its related cousins, CellDynamicExpression and FrontEndDynamicExpression.

John Fultz
  • 776
  • 5
  • 11
  • 1
    Welcome (back) to StackOverflow, and thank you for the asnwer! It's good to finally see you here. If you have time, perhaps you can also take a look at this front-end-related question: http://stackoverflow.com/questions/8353838/controlling-the-rasterize-width-for-notebook-related-expression – Szabolcs Dec 02 '11 at 08:54
  • What will evaluate first, *DynamicExpression or visible dynamic? Or is this a rat race? – Kuba Mar 30 '15 at 07:38
4

A DynamicBox with Initialization is capable of the basic function. You can size the palette such that the object is not visible, and it will still operate.

Here is code for a small sample palette. It sets a value for var. The active code is offset with whitespace.

(* Beginning of Notebook Content *)
Notebook[{
Cell[BoxData[{
 TagBox[GridBox[{
    {
     ButtonBox["\<\"TSV\"\>",
      Appearance->Automatic,
      ButtonFunction:>None,
      Evaluator->Automatic,
      Method->"Preemptive"]},
    {
     ButtonBox["\<\"CSV\"\>",
      Appearance->Automatic,
      ButtonFunction:>None,
      Evaluator->Automatic,
      Method->"Preemptive"]},
    {
     ButtonBox["\<\"Table\"\>",
      Appearance->Automatic,
      ButtonFunction:>None,
      Evaluator->Automatic,
      Method->"Preemptive"]}
   },
   GridBoxAlignment->{"Columns" -> {{Left}}},
   GridBoxItemSize->{"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}],
  "Column"], "\[IndentingNewLine]", 

DynamicBox[Null,
   Initialization :> ($CellContext`var = "It is done, Master.")
]

}], NotebookDefault,
 CellMargins->{{0, 0}, {0, 0}},
 CellBracketOptions->{"Color"->RGBColor[0.269993, 0.308507, 0.6]},
 CellHorizontalScrolling->True,
 PageBreakAbove->True,
 PageBreakWithin->False,
 ShowAutoStyles->True,
 LineSpacing->{1.25, 0},
 AutoItalicWords->{},
 ScriptMinSize->9,
 ShowStringCharacters->False,
 FontFamily:>CurrentValue["PanelFontFamily"],
 FontSize:>CurrentValue["PanelFontSize"]]
},
WindowSize->{55, 105},
WindowMargins->{{Automatic, 583}, {Automatic, 292}},
WindowFrame->"Palette",
WindowElements->{},
WindowFrameElements->{"CloseBox", "MinimizeBox"},
StyleDefinitions->"Palette.nb"
]
(* End of Notebook Content *)
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • Hey, what palette is that? :D My question is: are you sure that the initialization code will get executed *even if the `DynamicBox` is not visible*? This doesn't seem to be the case here. (But that is not a big issue, I think I can still use this approach.) – Szabolcs Oct 28 '11 at 12:33
  • I made a notebook with a DynamicBox at the end (non-visible when opening the notebook). After restarting Mathematica and re-opening the notebook, the initialization was not executed. (It *was* executed later after I scrolled to the end.) Just pointing this out. Otherwise I can use the approach, and this is not an issue for me in practice. – Szabolcs Oct 28 '11 at 12:35
  • @Szabolcs (#1) I am very fond of that palette. :-) (#2) Strange, I checked that specifically, knowing that dynamic objects are inactive when hidden, and I found that it worked. Perhaps because on my system, with the sample notebook, it is only *just* out of frame? – Mr.Wizard Oct 28 '11 at 13:39