A recent SO question让我想起了我曾经写过的一些代码。目的是创建一个CircularSlider[]
对象,可用于动态对象中的类角度变量。
我的解决方案框架(如下)来自Advanced Manipulate Functionality教程中定义的ValueThumbSlider[]
。主要区别在于ValueThumbSlider[]
滑块的值和LocatorPlane[]
的位置是相同的,而在CircularSlider[]
中它们不是 - 这会导致问题。< / p>
第一个问题是移动Locator
不会改变滑块值。通过使用Dynamic
:(x = #/Abs[Complex @@ #]) &
中的第二个参数来解决此问题。
这又会导致如果您从外部设置滑块(t
)的外部值,它将立即恢复到之前的值。通过保留旧值(t0
)并与t
进行比较来解决此问题。如果它们不匹配,则假设t已更改,因此Locator
位置x
将更新为新位置。
CircularSlider[t_] := CircularSlider[t, {0, 1}];
CircularSlider[Dynamic[t_], {min_, max_}] /; max > min :=
With[{d = (max - min)/(2. Pi)},
DynamicModule[{td = t/d, x, t0}, x = {Cos[td], Sin[td]};
LocatorPane[
Dynamic[If[!NumberQ[t], t = min; x = {Cos[td], Sin[td]}];
If[t != t0, t0 = t; x = {Cos[td], Sin[td]}];
t = Mod[Arg[Complex @@ x] d, max, min]; t0 = t;
x, (x = #/Abs[Complex @@ #]) &],
Graphics[{AbsoluteThickness[1.5], Circle[],
Dynamic[{Text[NumberForm[t, {3, 2}], {0, 0}]}]}],
ImageSize -> Small]]]
所以我的问题是:有人可以用上面的kludges来完成这项工作吗?
答案 0 :(得分:5)
对于问题#1,我不会考虑将Dynamic
的第二个参数用作kludge - 这就是第二个参数的用途。因此,我没有替代解决方案。
如果您不在t
的第一个参数中分配Dynamic
,则可以避免问题#2。
考虑到这一点,这是另一个实现:
CircularSlider2[Dynamic[t_], r:{min_, max_}:{0, 1}] :=
DynamicModule[{scale, toXY, fromXY},
scale = (max - min) / (2. Pi);
toXY[a_?NumberQ] := Through@{Cos, Sin}[a / scale];
toXY[a_] := {1, 0};
fromXY[{x_, y_}] := Mod[Arg[x + I y] scale, max, min];
LocatorPane[
Dynamic[toXY[t], (t = fromXY[#])&],
Graphics[{
AbsoluteThickness[1.5], Circle[],
Dynamic[{Text[NumberForm[t, {3,2}], {0, 0}]}]
}],
ImageSize -> Small
]
]
此版本与原始版本之间唯一的重要区别是Dynamic
的第一个参数是一个没有副作用的表达。
我在Mathematica 8中偶然发现了这个未记录的实验性功能:
DynamicModule[{x = RandomReal[{0, 50}]},
{Experimental`AngularSlider[Dynamic@x], Dynamic@x}
]