6
$\begingroup$

So, my aim is to produce a user interface with checkboxes not only returning True/False, but also the order in which they were selected. The final goal is an intuitive or comprehensive user interface (.cdf compatible) in which several parameters could be added/removed.

The expected behaviour is a ranked list of controls. If one unmarks control b, (which was initially at rank 2) then control c (previously rank 3) has to be set to rank 2. And a renewed selection of b, would set it at rank 3. That's the principle.

mockup

I actually managed to produce the desired result... but through an INSANELY COMPLICATED and LONG code!!! Please help me to get that in a few lines! :)

DynamicModule[{a, b, c, a1, b1, c1},

 Panel@Row[{Legended[
     Panel@Column@{Dynamic@
         Button[Control[{{a, True, "a"}, {True, False}}],
          {
           a = If[a, False, True],

           If[Not@a, {If[b1 == 3, b1 = 2, 
              If[And[b1 == 2, c1 =!= 1], b1 = 1]], 
             If[c1 == 3, c1 = 2, If[And[c1 == 2, b1 =!= 1], c1 = 1]]}],
           a1 = If[Not@a, 0,
             If[And[b, c], 3,
              If[Nor[b, c], 1,
               2]]]
           },
          Appearance -> "Frameless"],

        Dynamic@Button[Control[{{b, True, "b"}, {True, False}}],
          {
           b = If[b, False, True],

           If[Not@b, {If[a1 == 3, a1 = 2, 
              If[And[a1 == 2, c1 =!= 1], a1 = 1]], 
             If[c1 == 3, c1 = 2, If[And[c1 == 2, a1 =!= 1], c1 = 1]]}],
           b1 = If[Not@b, 0,
             If[And[a, c], 3,
              If[Nor[a, c], 1,
               2]]]
           },
          Appearance -> "Frameless"],

        Dynamic@Button[Control[{{c, True, "c"}, {True, False}}],
          {
           c = If[c, False, True],

           If[Not@c, {If[a1 == 3, a1 = 2, 
              If[And[a1 == 2, b1 =!= 1], a1 = 1]], 
             If[b1 == 3, b1 = 2, If[And[b1 == 2, a1 =!= 1], b1 = 1]]}],

           c1 = If[Not@c, 0,
             If[And[b, a], 3,
              If[Nor[b, a], 1,
               2]]]
           },
          Appearance -> "Frameless"]}, Placed["Controls", Above]],

    Spacer[25],

    Legended[Panel[Dynamic /@ {a1, b1, c1}], Placed["Ranks", Above]]}],

 Initialization :> {{a1, b1, c1} = {1, 2, 3}}]

For sure, Slot or SlotSequence has to be integrated, but I failed in it.

Yes, I guess that wrapping a checkbox in a button isn't that clean...

I do not need more that 3 parameters, but why not find a generalised solution for more? :-D

Thank you!!!

$\endgroup$
6
$\begingroup$

Try this:

DynamicModule[{pos = Range[3]}, 
              Panel[Row[{Column[{"Controls", 
                                 CheckboxBar[Dynamic[pos],
                                             {1 -> "a", 2 -> "b", 3 -> "c"}, 
                                             Appearance -> "Vertical"]}], 
                         Column[{"Ranks", 
                                 Dynamic[Pane[ReplacePart[{0, 0, 0}, 
                                         Thread[pos ->
                                                Range[Length[pos]]]]]]}]}]]]
$\endgroup$
  • $\begingroup$ Excellent! Very efficient, thanks a lot!!! :-) $\endgroup$ – B-Lertch Mar 17 '18 at 14:27
2
$\begingroup$
DynamicModule[{pos = Range[3]}, Panel @ Grid @ {{"Controls", "Ranks"},
    {CheckboxBar[Dynamic[pos], {1 -> "a", 2 -> "b", 3 -> "c"}, Appearance -> "Vertical"], 
     Dynamic @ Normal @ SparseArray[MapIndexed[# -> #2[[1]] &, pos], 3]}}]

Alternatively, using the second argument of Dynamic to update ranks,

DynamicModule[{pos = Range[3], ranks = Range[3]},
 Panel @ Grid @ {{"Controls", "Ranks"},
  {CheckboxBar[Dynamic[pos, 
      (pos = #; ranks = Normal@SparseArray[MapIndexed[# -> #2[[1]] &, #], 3]) &], 
     {1 -> "a", 2 -> "b", 3 -> "c"}, Appearance -> "Vertical"], Dynamic @ ranks}}]

enter image description here

$\endgroup$

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.