Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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:

Mathematica graphics

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).

Mathematica graphics

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?

share|improve this question
    
This is at least the second time I've read a question without noting the author, and thought "This is probably one for Szabolcs to answer." afterward to see you're asking. –  Mr.Wizard May 30 '12 at 7:44
    
@Mr.Wizard I thought the same thing. –  Heike May 30 '12 at 7:52
    
@Heike :-) -- can you think of any native object that has the behavior Szabolcs describes? I'm drawing a blank. –  Mr.Wizard May 30 '12 at 7:56
    
@Mr.Wizard Yes, there is one, and I should have mentioned it! It is the image cropping GUI. I'm not sure if it's available in 7. Paste an image into the notebook, right click, and select Crop Image. You can adjust the crop boundaries, and double-clicking it will replace the control with the cropped image. If I remember right, last time I checked this was implemented in terms of an undocumented native control that does almost everything alone, and not in terms of low-level Dynamic constructs. –  Szabolcs May 30 '12 at 7:59
    
Nope, not in v7. –  Mr.Wizard May 30 '12 at 8:00

1 Answer 1

up vote 13 down vote accepted

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.

share|improve this answer
    
Quite clever! +1 –  Mr.Wizard May 30 '12 at 8:01
    
Thanks. I can't say I like it, it just feels dangerous to be re-writing an entire cell when there's no undo, unless of course the contents aren't important or can be regenerated quickly. –  jVincent May 30 '12 at 8:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.