I would like to create a notebook element that can replace itself.
Here's an example to illustrate:
Panel[Column[
{Style["This is a panel", Bold],
Button["Press me!",
SelectionMove[EvaluationNotebook[], All, EvaluationCell];
NotebookWrite[EvaluationNotebook[],
"\"Now I'm just a piece of static text.\""]]}]]
This code will create a little panel:
If we press the button, the panel will get replaced by a piece of static text (i.e. not a dynamic expression that's shown as text, but just plain old non-dynamic text).
Well, in this implementation actually it's not the panel that gets replaced, but the complete cell containing the panel, and that's my problem: I need only the panel to be replaced, so this will work even if the panel is just a subexpression in a larger expression.
How can we create an UI control that is able to replace itself with an arbitrary expression in the notebook?
Answer
This solution relies on putting a TagBox
with a custom tag around the part to be replaced, reading the cell and replacing the tag, then writing it back. Personally I've always felt that the need to read the entire cell and write it all again seems kind of clunky, but I don't know of a better way to do this.
MakeBoxes[replacementMarker[a_,tag_],StandardForm]^:=TagBox[MakeBoxes[a],tag]
replaceMark[rule_,nb_:EvaluationNotebook[],which_:All,cell_:EvaluationCell]:=(
SelectionMove[nb,which,cell];
NotebookWrite[EvaluationNotebook[],NotebookRead[EvaluationNotebook[]]/.rule])
Row[{"Not replaced",
replacementMarker[
Panel[Column[{Style["This is a panel",Bold],Button["Press me!",
replaceMark[TagBox[_,"replacementTag"] :> MakeBoxes["\" Now I'm just text. \""]]
]}]]
,"replacementTag"]
,"Not replaced"}]
Important note! The action cannot be undone, so if used for example to allow dynamic reformatting of data or similar, be aware that mistakes can end up deleting the old contents.
Comments
Post a Comment