Re: Locators disappearing in LocatorPane (although working)
- To: mathgroup at smc.vnet.net
- Subject: [mg124550] Re: Locators disappearing in LocatorPane (although working)
- From: John Fultz <jfultz at wolfram.com>
- Date: Tue, 24 Jan 2012 05:08:27 -0500 (EST)
- Delivered-to: l-mathgroup@mail-archive0.wolfram.com
- Reply-to: jfultz at wolfram.com
I wasn't able to immediately reproduce this, but I suspect I know what's causing
it anyway. The Dynamic around the LocatorPane is causing the LocatorPane to be
reconstructed underneath you while you're dragging. Generally, you should
construct controls so that they're not inside Dynamics that will trigger while
you're interacting with those controls, since this can create instability and
may even be completely impossible for a human, yet alone an algorithm, to figure
out how you intend to deal with selections, drags, etc.
Normally, the Dynamic wouldn't retrigger and would just be so much code fluff if
you had properly scoped all of the contents in Dynamic. But in this case, you
have (elided for emphasis):
Dynamic[LocatorPane[..., ...[BezierCurve[Dynamic[P], SplineDegree->Length[P]]]]
Nowhere is Length[P] wrapped in a Dynamic below the scope of the top-level
Dynamic, so every time P changes, the entire LocatorPane reconstructs, and you
risk losing track of which Locator you're currently dragging.
It's tempting to just populate Dynamics everywhere until things appear to work,
but it really helps to stop and think about how Dynamic works. Doing so will
help you to make sure that you not only avoid this kind of situation, but
improve efficiency of the resulting interface as well. For this example, I
recommend wrapping a Dynamic around BezierCurve and removing all other Dynamics
associated with the LocatorPane.
Additionally, you have a huge unnecessary inefficiency. The Dynamic wrapping
the 3D graphic also encompasses a second global variable. When this global
variable changes, it triggers to cause the Dynamic to trigger again. So this
Dynamic is triggering twice as often as it needs to. There are various ways to
work around this...the one I'll show below uses the TrackedSymbols option to
only track the variables you want.
DynamicModule[{P = 1/2 {{1, 1}, {-1, 1}, {1, -1}}, \[ScriptCapitalP]},
GraphicsRow[{LocatorPane[Dynamic[P],
Framed@Graphics[
Dynamic[BezierCurve[P, SplineDegree -> Length[P]]],
Axes -> True, PlotRange -> {{-1, 1}, {-1, 1}}],
LocatorAutoCreate -> True],
Dynamic[\[ScriptCapitalP] = Append[#, 0] & /@ P;
Graphics3D[{Sphere[\[ScriptCapitalP], 0.05], {Gray, Opacity[0.5],
Tube[Line[\[ScriptCapitalP]], 0.015]},
Tube[BezierCurve[\[ScriptCapitalP],
SplineDegree -> Length[\[ScriptCapitalP]]], .03]},
Axes -> True, PlotRange -> 1], TrackedSymbols :> {P}]}]]
Sincerely,
John Fultz
jfultz at wolfram.com
User Interface Group
Wolfram Research, Inc.
On Sat, 21 Jan 2012 05:13:29 -0500 (EST), Chris Young wrote:
> The Locators are vanishing from sight before they reach the edge of the
> Locator pane, although they are still working.
>
> DynamicModule[
> {P = 1/2 {{1, 1}, {-1, 1}, {1, -1}},
> \[ScriptCapitalP]},
>
> GraphicsRow [
> {
> Dynamic[
> LocatorPane[
> Dynamic[P],
> Framed @ Graphics[
> BezierCurve[Dynamic[P], SplineDegree -> Length[P]],
> Axes -> True,
> PlotRange -> {{-1, 1}, {-1, 1}}
> ],
> LocatorAutoCreate -> True
> ]
> ],
>
> Dynamic[
> \[ScriptCapitalP] = Append[#, 0] & /@ P;
> Graphics3D[
> {
> Sphere[\[ScriptCapitalP], 0.05],
> {Gray, Opacity[0.5], Tube[Line[\[ScriptCapitalP]], 0.015]},
> Tube[
> BezierCurve[\[ScriptCapitalP],
> SplineDegree -> Length[\[ScriptCapitalP]]], .03]
> },
> Axes -> True,
> PlotRange -> 1
> ]
> ]
> }
> ]
> ]