This is the method I have worked out after a lot of trial and error, but I would appreciate any suggestions for improvements to it.
I use a function with the HoldAll
attribute to input the names of symbols from my package that contain all the content that the interface notebook needs to load. At run time I use the Initialization
option of DynamicModule
to load the package and set the notebook content.
If the DockedCells
option is not specified in the notebook at build time then it doesn't display when I specify it with SetOptions
(it will display if the user moves the window), so I specify a blank Cell
at build time.
To prevent evaluating the Initialization
option when CreateDocument
builds the notebook, I first set the $FrontEnd
option DynamicUpdating
to False
, save and close the notebook, and then reset it to Automatic
.
The code for a minimal package that implements this is:
(* ::Package:: *)
BeginPackage["RunTimeGUIMinimal`"]
RunTimeGUIMinimal::usage = "RunTimeGUIMinimal[packages_List, titleFunction_Symbol, contentFunction_Symbol, tabFunction_Symbol] "
GUITitle::usage = "GUITitle "
GUIContent::usage = "GUIContent "
GUIDockedCell::usage = "GUITabList "
Begin["`Private`"]
(* Implementation of the package *)
SetAttributes[RunTimeGUIMinimal, HoldAll]
RunTimeGUIMinimal[packages_List, titleFunction_Symbol, contentFunction_Symbol, dockedCellFunction_Symbol] :=
CreateDocument[{
DynamicModule[{content},
Dynamic[content[]],
Initialization:>(
Map[Needs, packages];
(* set the WindowTitle *)
SetOptions[EvaluationNotebook[], WindowTitle -> First@Flatten@{titleFunction}];
(* set the DockedCells to their normal state *)
SetOptions[EvaluationNotebook[], DockedCells -> dockedCellFunction];
(* set the content *)
content[] = contentFunction;
),
UnsavedVariables:>{content}
]
},
(* set DockedCells to a blank Cell which will be replaced with SetOptions runs in Initialization. If this is not present, the DockedCells don't display until the user moves the window. *)
DockedCells -> {Cell[BoxData[ToBoxes[""]], "DockedCell"]},
Saveable -> False,
Selectable -> False,
ScreenStyleEnvironment -> "Working",
(* set the WindowTitle to the value of titleFunction at build time. This will be overwritten by the current package value at run time in the Initialization *)
WindowTitle -> First@Flatten@{titleFunction},
WindowElements -> {
"VerticalScrollBar",
"HorizontalScrollBar",
"StatusArea"
},
CellContext->Notebook
]
GUITitle = "My Program"
GUIContent = TextCell["Some Dynamic content","Text"]
GUIDockedCell = Cell["A Docked Cell","Text"]
End[]
EndPackage[]
The commands to build the notebook are:
Needs["RunTimeGUIMinimal`"]
SetOptions[$FrontEnd, DynamicUpdating -> False]
nb = RunTimeGUIMinimal[{"RunTimeGUIMinimal`"}, GUITitle, GUIContent,
GUIDockedCell];
NotebookSave[nb,
FileNameJoin[{NotebookDirectory[], "RunTimeGUIMinimal"}]]
NotebookClose[nb]
SetOptions[$FrontEnd, DynamicUpdating -> Automatic]
NotebookOpen[
FileNameJoin[{NotebookDirectory[], "RunTimeGUIMinimal.nb"}]];
Inspecting the notebook code shows that the functions remain unevaluated. The package functions GUITitle
, GUIContent
and GUIDockedCell
can be modified and when the notebook is opened again (after a quit) it reflects the changes.
Dynamic[ui]
with/wo WRI versioning style. $\endgroup$ – Kuba♦ Aug 24 '16 at 17:10