5
$\begingroup$

Consider the following code

Manipulate[a,
 Dynamic@Grid[{
    {"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
    {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}
    }, Alignment -> {{Right, Left}, Automatic}],
 Delimiter,
 Button["Button 1"],
 Button["Button 2"],
 ControlPlacement -> Left]

which gives

enter image description here

Now, if we were to include an If statement for one of the buttons, we would need to use Dynamic. For example, we could use

Manipulate[a,
 Dynamic@Grid[{
    {"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
    {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}
    }, Alignment -> {{Right, Left}, Automatic}],
 Delimiter,
 Button["Button 1"],
 Dynamic[If[a == 0, Button["Button 2"], Button["Button 3"]]],
 ControlPlacement -> Left]

which yields

enter image description here

As one can see, the button alignment changes when I do this. I want to fix this, to keep the same appearance as in the first example. One attempt at trying to solve this was to consider a Dynamic@Grid. That is,

Manipulate[a,
 Dynamic@Grid[{
    {"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
    {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}
    }, Alignment -> {{Right, Left}, Automatic}],
 Delimiter,
 Dynamic@Grid[{
    {Button["Button 1"]},
    If[a == 0, {Button["Button 2"]}, {Button["Button 3"]}]
    }],
 ControlPlacement -> Left]

This, however, makes it a bit worse:

enter image description here

I could change the ItemSize within the Grid to get something similar to what I want, but I would have to do it manually. For instance,

Manipulate[a,
 Dynamic@Grid[{
    {"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
    {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}
    }, Alignment -> {{Right, Left}, Automatic}],
 Delimiter,
 Dynamic@Grid[{
    {Button["Button 1"]},
    If[a == 0, {Button["Button 2"]}, {Button["Button 3"]}]
    }, ItemSize -> 30],
 ControlPlacement -> Left]

leads to

enter image description here

Still, the alignment with the slider is not perfect, and I'd have to manually adjust it. I wonder if it's possible to do this in a more "automatic" way, without relying on manually fixing the ItemSize. I could include all controls in a Grid, but the problem with that is that the Delimiter doesn't seem to format if I use a Grid, and I want to keep it in my Manipulate. Any ideas how to solve this?

Furthermore, how would I deal with the case

Manipulate[a,
 Dynamic@Grid[{
    {"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
    {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}
    }, Alignment -> {{Right, Left}, Automatic}],
 Delimiter,
 Dynamic@Column[{
    {Button["Button 1"], Button["Button 2"]} // Row,
    {Button["Button 3"], Button["Button 4"]} // Row
    }, ItemSize -> 15],
 ControlPlacement -> Left]

that is,

enter image description here

Any suggestions are appreciated.

$\endgroup$

1 Answer 1

6
$\begingroup$

How about putting everything in the grid? Like so:

Manipulate[a,
  Dynamic @
    Grid[
      {{"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
       {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]},
       {Button["Button 1"], SpanFromLeft},
       {If[a == 0, Button["Button 2"], Button["Button 3"]], SpanFromLeft}},
      Dividers -> {False, {3 -> True}},
      Alignment -> {{Right, Left}, Automatic}],
  ControlPlacement -> Left]

The result looks like this:

Slider at zero

at_zero

Slider moved off zero.

off_zero

Update 1

For your array of four buttons, will this work?

Manipulate[a,
  Grid[
    {{"Slider", Control[{{a, 0, ""}, 0, 1, .1}]},
     {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}},
    Alignment -> {{Right, Left}, Automatic}],
  Delimiter,
  Grid[
    {{Button["Button 1"], Button["Button 2"]},
     {Button["Button 3"], Button["Button 4"]}},
    ItemSize -> {Scaled[.2], Automatic}],
 ControlPlacement -> Left]

four_buttons

Update 2

You apparently don't like my first attempt at solving your four button array problem because buttons are elastic and change width as adjustments are made to notebook window, while manipulators are rigid and ignore such changes. The only solution I can think of is to make everything rigid. This means that you will have to specify the control sizes in your code and your users will be stuck with what you specify.

Manipulate[a,
  Grid[
    {{Item["Slider", ItemSize -> 100/CurrentValue["FontMWidth"]], 
      Control[{{a, 0, ""}, 0, 1, .1, ImageSize -> 300}]},
     {"Checkbox", Control[{{b, 1, ""}, {1, 0}}]}},
    Alignment -> {{Right, Left}, Automatic}],
  Delimiter,
  Grid[
    {{Button["Button 1", ImageSize -> 180], Button["Button 2", ImageSize -> 180]},
    {Button["Button 3"], Button["Button 4"]}}],
  ControlPlacement -> Left]

four_buttons

Notes

  • My target width for the controls array is 400 points. The buttons are set to 190 points to allow for the spacing between them. The manipulator is set to 290 points for a similar reason.

  • The target for the labels is 100 points. However, ItemSize works in printer's ems (as redefined by WRI). That is reason for dividing by CurrentValue["FontMWidth"].

  • Width specifications need only be set for the top row of a grid. Succeeding rows will follow what was set for the top.

$\endgroup$
9
  • $\begingroup$ Thank you. This should work! Also, there is a natural spacing using the Delimiter, which I don't get using Dividers. This is but a minor detail. Any ideas to improve this? Maybe just use Spacer? $\endgroup$
    – sam wolfe
    Dec 17, 2019 at 15:56
  • 1
    $\begingroup$ @samwolfe. Adding the option Spacings -> {Automatic, {3 -> 2}} to Grid looks good to me. Also, I posted an update with a possible answer to four button problem. $\endgroup$
    – m_goldberg
    Dec 17, 2019 at 16:40
  • $\begingroup$ It seems the case of the four buttons doesn't really solve it. They go beyond the slider size, instead of aligning with it. $\endgroup$
    – sam wolfe
    Dec 17, 2019 at 19:41
  • $\begingroup$ Also, the problem with using Dividers is that if I dynamically hide certain Controls, the horizontal line is not correctly updated, unlike the Delimiter, which is always in the correct position. Maybe I could use something like {Graphics[Line[...]],SpanFromLeft}? What do you think? $\endgroup$
    – sam wolfe
    Dec 17, 2019 at 20:12
  • 1
    $\begingroup$ Using the two Grid options Spacings -> {Automatic, {3 -> 2}} and Dividers -> {3 -> Manipulate`Dump`$delimitercolor} (where Manipulate`Dump`$delimitercolor is GrayLevel[0, 0.2] on Windows 10) we get the default delimiter. (+1) $\endgroup$
    – kglr
    Dec 18, 2019 at 5:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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