Re: Nested DynamicModule and EventHandler
- To: mathgroup at smc.vnet.net
- Subject: [mg92437] Re: [mg92399] Nested DynamicModule and EventHandler
- From: John Fultz <jfultz at wolfram.com>
- Date: Tue, 30 Sep 2008 21:52:45 -0400 (EDT)
- Reply-to: jfultz at wolfram.com
There are two fundamentally different ways of doing scoping which you'remixing up here. Lexical scoping literally searches the right-hand side for a symbol and replaces it before evaluation. Dynamic scoping temporarily substitutes a new value for the existing variable in the global namespace (in a sense, generating a completely new environment where that variable now has the new value). Paste tutorial/BlocksComparedWithModules into the help viewer input field to see a better explanation of this. DynamicModule uses lexical scoping, but your buttonD implementation suggests that you're hoping for dynamic scoping. There is no such thing as DynamicBlock because we really couldn't do things any other way without Dynamics contaminating the global namespace in the kernel, potentially causing bad interactions between multiple Dynamics or a Dynamic and a Shift+Enter evaluation one might otherwise expect to be independent. Here's some changes to your code which make things work as you expect... SetAttributes[buttonD, HoldAll] buttonD[b_, c_] := Button["button D", active := fd[b, c], ImageSize -> Automatic] SetAttributes[fd, HoldAll] fd[b_, c_] := Column[{EventHandler[ Dynamic[Graphics[{Circle[c, 0.1], b}, PlotRange -> {{-1, 1}, {-1, 1}}, Frame -> True]], "MouseDown" :> (c = MousePosition["Graphics", {}]; AppendTo[b, Point[c]])], Row[{"b ", InputField[Dynamic[b]]}]}] Then change the call to buttonD in the parent evaluation to take the arguments b and c (i.e. the DynamicModule variables). So, a couple more explanations here... * The DynamicModule wrappers you had were superfluous, so I removed them. * The HoldAll setting is necessary because you have functions like Dynamic and AppendTo that really want access to the original DynamicModule variables. Typically, Mathematica evaluation order would cause the arguments of buttonD and fd to be fully evaluated before the function ever saw them. I.e., it would be equivalent to calling buttonD[{Green, Point[{-.25,-.25}]}, {0,0}]. By declaring the functions HoldAll, I'm instructing Mathematica to not do such a substitution, and instead pass the DynamicModule variables into the function body unevaluated. That's quite a crash course in evaluation ordering and scoping. I hope you found my explanation helpful. Sincerely, John Fultz jfultz at wolfram.com User Interface Group Wolfram Research, Inc. On Tue, 30 Sep 2008 07:37:31 -0400 (EDT), Hugh Goyder wrote: > I use modules to localise variables and to simplify code. In > attempting to understand the additional complications of using > DynamicModule in version 6 I am trying to sort out how to work with > buttons, modules and EventHandlers. > > Below three of my buttons, with increasing complexity, work but the > fourth, buttonD, fails. I can click points onto the graphic with the > set-up of buttonC but not with buttonD. I am trying to get > communication between the parent and child modules where points are > introduced into the child module using the EventHandler. Thus with > buttonD pressed clicking on the graphic should produce an additional > primitive in the list maintained by the parent module. What is the > correct way to do this? > > Thanks Hugh Goyder > > > ClearAll[buttonA, buttonB, buttonC, buttonD]; > buttonA[] := DynamicModule[{}, Button["button A", active := fa[], > ImageSize -> Automatic]]; > buttonB[] := DynamicModule[{}, Button["button B", active := fb[], > ImageSize -> Automatic]]; > buttonC[] := DynamicModule[{}, Button["button C", active := fc[], > ImageSize -> Automatic]]; > buttonD[] := DynamicModule[{}, Button["button D", active := fd[], > ImageSize -> Automatic]]; > > ClearAll[fa, fb, fc, fd]; > fa[] := DynamicModule[{}, Plot[x^2, {x, -2, 2}]]; > fb[] := DynamicModule[{a = 5}, Column[{Slider[Dynamic[a], {0, 10}], > Dynamic[Plot[Sin[a*x], {x, 0, 2*Pi}]]}]]; > fc[] := DynamicModule[{b = {}, c = {0.5, 0.5}}, > Column[{EventHandler[Dynamic[Graphics[{Line[{{0, 0}, c}], b}, > PlotRange -> {{0, 1}, {0, 1}}, Frame -> True]], > > "MouseDown" :> (c = MousePosition["Graphics", {}]; > AppendTo[b, Point[c]])], > Row[{"b ", InputField[Dynamic[b]]}]}]]; > fd[] := DynamicModule[{}, > Column[{EventHandler[Dynamic[Graphics[{Circle[c, 0.1], b}, > PlotRange -> {{-1, 1}, {-1, 1}}, Frame -> True]], > > "MouseDown" :> (c = MousePosition["Graphics", {}]; > AppendTo[b, Point[c]])], > Row[{"b ", InputField[Dynamic[b]]}]}]] > > DynamicModule[{active = Graphics[{}], a, g, > b = {Green, Point[{-0.25, -0.25}]}, > c = {0, 0}}, > Column[{Row[{buttonA[], buttonB[], buttonC[], buttonD[]}], > Dynamic[active], Row[{"b (outer)", InputField[Dynamic[b]]}], > Row[{"c ", InputField[Dynamic[c]]}], > Row[{"active ", InputField[Dynamic[active]]}]}]]