question on initialization of Manipulate, Dynamic, Refresh
I use the following pattern in Manipulate
Dynamic[Refresh[....logic to handle v changes...., TrackedSymbols->{v}]]
in setting up the logic.
I use the above to represent an 'event handler', where '开发者_运维百科v' is the control variable that the user changes. So, When a specific control variable changes, there is specific code to take care of the logic needed to handle this one variable being changed. This simulates 'callback' in other GUI programming systems.
This works very well. Except at initialization time, since Manipulate will 'fire' these refreshes when Manipulate first come up on the screen, even without me changing the slides.
Also, the order in which it decides to 'fire' the refresh can not be depended on. This makes it hard to initialize the state of the program.
Here is an example
Manipulate[
Row[{
Dynamic[Refresh[Print["x changed"]; {x, y, z}, TrackedSymbols -> {x}]],
Dynamic[Refresh[Print["y changed"]; "", TrackedSymbols -> {y}]],
Dynamic[Refresh[Print["z changed"]; "", TrackedSymbols -> {z}]]
}
]
,
{{x, 1, "x"}, 0, 10},
{{y, 1, "y"}, 0, 10},
{{z, 1, "z"}, 0, 10}
]
If you run the above, you'll notice the 3 print messages come up, without touching the controls.
My question: is there a way to prevent this initial refresh? I want the refresh code to run when I actually change the variable using the slider.
You might say, what is the big deal, let it refresh initially and run the logic as if the variables did change by the user.
Yes, I do that now. but I am trying to make it more efficient by reducing unnecessary work. Since the code will run some long computation each time a control variable changes, and this makes the Manipulate take more time than needed when it first come up, since the computation in each control variable has to run once.
I can introduce an extra 'state variable' to control this, and check that all events has 'fired' once, by counting, before starting the real work. Once all events fire once, I can set this variable to True, and only run the real code when the event fires and this state variable is true as well.
But I thought to ask if there might be a build-in way or smarter way to handle this without introducing more complicated logic in the code as I could not find an option or a setting to handle this.
Thanks,
So, this is not really general and not pretty and just a workaround, but it does what you want:
Manipulate[Module[{refx, refy, refz},
If[{x,y,z} == {1,1,1}, {x, y, z},
Row[{Dynamic[Refresh[
Print["x changed"];
{x, y, z}, TrackedSymbols ->
{x}]], Dynamic[Refresh[
Print["y changed"]; "",
TrackedSymbols -> {y}]],
Dynamic[Refresh[
Print["z changed"]; "",
TrackedSymbols -> {z}]]}]]],
{{x, 1, "x"}, 0, 10},
{{y, 1, "y"}, 0, 10},
{{z, 1, "z"}, 0, 10}]
精彩评论