4
$\begingroup$

I find one solution to make +/- buttons near Slider Control of Manipulate. But I don't understand why it works so bad.

Manipulate[Null, 
 Grid[{{Control[{{l, 0.007, "l"}, {0.001, 0.0025, 0.005, 0.006, 0.007,
        0.008, 0.009, 0.01}, 
      Grid[{{Slider[##, ImageSize -> 100], 
          InputField[#, ImageSize -> 40], 
          Animator[##, AnimationRunning -> False, 
           AppearanceElements -> {"StepLeftButton", 
             "StepRightButton"}]}}, 
        Alignment -> {Center, Center}] &}]}, {Control[{{n, 0.005, 
       "n"}, {0.001, 0.0025, 0.005, 0.01}, 
      Grid[{{Slider[##, ImageSize -> 100], 
          InputField[#, ImageSize -> 40], 
          Animator[##, AnimationRunning -> False, 
           AppearanceElements -> {"StepLeftButton", 
             "StepRightButton"}]}}, 
        Alignment -> {Center, Center}] &}]}, {Control[{{m, 500, "m"}, 
      10, 1000, 10, 
      Grid[{{Slider[##, ImageSize -> 100], 
          InputField[#, ImageSize -> 40], 
          Animator[##, AnimationRunning -> False, 
           AppearanceElements -> {"StepLeftButton", 
             "StepRightButton"}]}}, 
        Alignment -> {Center, Center}] &}]}}]]

enter image description here

Manipulating m works fine. n +/- buttons don't work at all. l button "-" does not work, but the "+" button does.

How can I fix this?

$\endgroup$
  • $\begingroup$ Rather than trying to fix your code, what are you actually trying to accomplish with it? The answer below gives you a hint on how you could go about building such an interface. If that doesn't work for you, please explain exactly what is unsatisfactory in that approach. $\endgroup$ – MarcoB Jun 15 '16 at 20:09
6
$\begingroup$

Example

DynamicModule[
 {value = 10},
 Panel @ Row @ {
    Slider[Dynamic @ value, {1, 100, 1}, ImageSize -> Small],
    InputField[Dynamic @ value, Enabled -> False, ImageSize -> {36, 18}],
    Button["-", value--],
    Button["+", value++]
    }
 ]

Output

example

EDIT

In order to restrict Slider to a set of pre-defined values, please see implementation below.

Example

DynamicModule[
 {
  index = 1,
  options = {1, 10, 20}
  },
 Panel @ Row @ {
    Slider[Dynamic @ options[[index]], {options}, ImageSize -> Tiny],
    InputField[Dynamic @ options[[index]], Enabled -> False, 
     ImageSize -> 40],
    Button["+", If[index <  Length @ options, index++]],
    Button["-", If[index !=  1, index--]]
    }
 ]

Output

example 2

However, I would recommend to use a different control all together. I suggest SetterBar. Please see example below.

Example

DynamicModule[
 {f, arg},
 Panel @ Column[{
    SetterBar[Dynamic @ f, {Sin, Cos, Tan}],
    Dynamic @ Plot[f[arg], {arg, 0, 2 Pi}]
    },
   Alignment -> Center]
 ]

Output

enter image description here

$\endgroup$
  • $\begingroup$ 2000 reputation reached! Thank you! $\endgroup$ – e.doroskevic Jun 15 '16 at 20:14
  • 3
    $\begingroup$ Well done, congratulations! $\endgroup$ – MarcoB Jun 15 '16 at 22:12
  • $\begingroup$ @E.Doroskevic, I can use it only with expression like "m". That working fine at first message. But i can't use a list of values such in example what didn't work. So your answer is not an answer at all. $\endgroup$ – Vasily Jun 16 '16 at 6:07
5
$\begingroup$

Based on the documentation, Slider is the only control object used in your code that supports a list of expression as its settings. Here is a custom alternative.

DynamicModule[{list = {0.001, 0.0025, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01}, l},
 Row[{
   Slider[Dynamic@l, {list}],
   Spacer[5],
   InputField[Dynamic[l, If[MemberQ[list, #], l = #] &], FieldSize -> 3.5],
   Spacer[5],
   Toggler[Dynamic@l, 
    Thread[Reverse@list -> Framed[Text[Style["-", FontSize -> 14]], 
       FrameMargins -> {{3, 3}, {1, 0}}]], 
    Enabled -> Dynamic[l > Min[list]]],
   Toggler[Dynamic@l, 
    Thread[list -> Framed[Text[Style["+", FontSize -> 14]], 
       FrameMargins -> {{3, 3}, {1, 0}}]], 
    Enabled -> Dynamic[l < Max[list]]]
   }]
 ]

Out

$\endgroup$
  • $\begingroup$ One can replace Framed with Button, if that style and visual difference for the inactive Toggler is preferred. $\endgroup$ – Karsten 7. Jun 16 '16 at 1:13
4
$\begingroup$

The problem is with Animator. When it is passed a list, the +/- buttons increment the index of the setting by about 5-10%. It seems to pick a "nice" increment that is 1, 2 or 5 times a power of 10. When the length of the list is less than 10, it does not behave well. It seems that an increment of 0 is what is sometimes calculated. (Personally, I would call this a bug. A minimum increment of 1 seems entirely reasonable to me.) Further, when the length of the list is 6 to 9, a forward increment of 1 is used, but the backward increment is 0.

You can play with the following to explore:

DynamicModule[{x = 3, n = 5},
 {Manipulator[Dynamic@n, {1, 10000, 1}, Appearance -> "Labeled"], 
  Dynamic@{Dynamic@x, 
    Animator[Dynamic@x, {Range@n}, AnimationRunning -> False]}}]

This does not happen for the discrete-increment form

Animator[Dynamic[x], a, b, 1]

It seems to me the only workaround for short lists is to explicitly increase the index. Here is my take on the OP's control. (Update: Thanks to Karsten 7 for a workaround to a bug.)

ClearAll[myControl];
myControl[Dynamic[x_], arg : {list_List}, opts___] := (* special case for list of values *)
  Grid[{{Slider[Dynamic[x], arg, ImageSize -> 100], 
     InputField[Dynamic[x], ImageSize -> 40],
     DynamicModule[{i},
      Dynamic[
       i = First@Nearest[list -> Automatic, x];
       Animator[
        Dynamic[i, (i = #; x = list[[i]]) &],
        {1, Length@list, 1},
        AnimationRunning -> False, 
        AppearanceElements -> {"StepLeftButton", "StepRightButton"}]
       ]]}},
   Alignment -> {Center, Center}];
myControl[Dynamic[x_], arg : {list__?NumberQ}, opts___] :=  (* the standard iterator *)
  Grid[{{Slider[Dynamic[x], arg, ImageSize -> 100], 
     InputField[Dynamic[x], ImageSize -> 40],
     Animator[Dynamic[x], arg, AnimationRunning -> False, 
      AppearanceElements -> {"StepLeftButton", "StepRightButton"}]}},
   Alignment -> {Center, Center}];

Manipulate[Null, 
 Grid[{{Control[{{l, 0.007, "l"},
     {0.001, 0.0025, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01}, myControl[##] &}]},
   {Control[{{n, 0.005, "n"}, {0.001, 0.0025, 0.005, 0.01}, myControl[##] &}]},
   {Control[{{m, 500, "m"}, 10, 1000, 10, myControl[##] &}]}}]]

Mathematica graphics

$\endgroup$
  • $\begingroup$ @Karsten7. Thanks for looking into it so much! That feels like better code structure to me, too. $\endgroup$ – Michael E2 Jun 16 '16 at 12:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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