3
$\begingroup$

Consider the following code, where I have a list of variables, each with different specified units. In my real case, these lists are not fixed, hence the surrounding Dynamic and the general definition for selected. I have checkboxes associated with each, but I only want to allow checkboxes to be simultaneously selected if the variables have the same units. So if, for example, I have "a" selected, but then select "b", that is allowed. But if I have "a" and/or "b" selected, and try to select "c", I want "a" and "b" to become deselected in the process. How can I accomplish this?

Module[{vars = {a, b, c, d}, 
        varunits = {"Molar", "Molar", "Seconds", "DimensionlessUnit"}, 
        selected}, 
  selected[index_] = False; 
  Deploy[Dynamic[Column[
    Row[{vars[[#]], " ", 
         Checkbox[Dynamic[selected[#]]], " ", 
         varunits[[#]]}] & /@ Range[Length[vars]]]]]]

enter image description here

Edited to add: It looks like I can do this using the second parameter of “Dynamic.” But that raises a secondary question: suppose this checkbox is already part of a pure function with slots. The second parameter of Dynamic needs to also be a pure function. And I would like to pass it parameters from the outer slots. Can that be done?

$\endgroup$

3 Answers 3

2
$\begingroup$
 DynamicModule[{vars = {a, b, c, d}, 
   varunits = {"Molar", "Molar", "Seconds", "DimensionlessUnit"}},
  Deploy[Dynamic[Column[Function[u, Row[{vars[[u]], 
   Checkbox[Dynamic[selected[u], (selected[u] = #; (selected[#] = False) & /@ 
     notselected[u]) &]], varunits[[u]]}, Spacer[10]] ] /@ Range[Length[vars]]]]], 
  Initialization :> {selected[_] := False, 
   notselected = Association[Join @@ Values @ 
     Map[Function[x, # -> Complement[Range@Length@vars, x] & /@ x]]@
       PositionIndex[varunits]]}]

enter image description here

$\endgroup$
1
$\begingroup$

Ok, looks like I have found a solution:

DynamicModule[{vars = {a, b, c, d}, 
               varunits = {"Molar", "Molar", "Seconds", "DimensionlessUnit"}, 
               selected}, selected[index_] = False; 
  Deploy[Dynamic[Column[
    Row[{vars[[#]], " ", 
      Checkbox[Dynamic[selected[#], 
                       Function[checked, selected[#] = checked; 
                       If[checked, Do[If[varunits[[i]] != varunits[[#]], 
                                         selected[i] = False], 
                                      {i, Length[vars]}]]]]], 
      " ", varunits[[#]]}] & /@ Range[Length[vars]]]]]]

I'm sure there's a better way than the Do loop to handle the resets, but at least this gives the idea.

$\endgroup$
1
$\begingroup$

Inspired by the implementation of CheckboxBar:

checkboxes[Dynamic[sels_], list : {(_ -> _) ...}] := 
 DynamicModule[{unit},
  DynamicWrapper[Column[
    Labeled[Checkbox[Dynamic[MemberQ[sels, #],
         Function[arg,
          Which[MemberQ[sels, #], sels = DeleteCases[sels, #],
           unit === None || Last@# === unit, AppendTo[sels, #],
           True, sels = {#}]]]],
       List @@ #, {Left, Right}] & /@ list],
   If[! ListQ[sels], sels = {}];
   unit = First[Values@sels, None];
   ]
  ]

and use it like:

DynamicModule[{sels,
  vlist = {a -> "Molar", b -> "Molar", c -> "Seconds", d -> "DimensionlessUnit"}},
 checkboxes[Dynamic[sels], vlist]
]
$\endgroup$

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.