9
$\begingroup$

Background: consider the following code-snippet.

  Dynamic@Grid[
    Table[Setter[Dynamic[idx, (idx = #1) &],
      i*6 + j, 
    Graphics[{Blue, Disk[]}, ImageSize -> 20]], 
    {i, 0, 1}, {j, 6}]]

This code creates two rows of clickable disk images. So if idx=10 is run, the 10th disk looks pressed. I want to make this control multi-selectable. So if idx={1,12} run, the first and last disks look pressed. ( In my application the disks may have different colors, edge properties and opacity. ) - See also: What is an efficient way of selecting multiple colors via Manipulate?

Question: How to create "a multi-selectable setterbar with colored buttons" ? ( preferably based on the snippet above, but not necessarily ).

$\endgroup$

3 Answers 3

7
$\begingroup$

Does this provide the functionality you are looking for? Note that a multi-selectable SetterBar is a TogglerBar. The only problem with the latter is that it cannot be partitioned into a multi-row grid. For your particular problem, I would rather use Button instead of Setter:

list = {};
Dynamic@list

Grid[Table[
   DynamicModule[{pressed = False}, With[{idx = i*6 + j},
     Button[Graphics[{Blue, Disk[]}, ImageSize -> 20], 
      pressed = ! pressed; 
      list = If[pressed, Append[list, idx], DeleteCases[list, idx]], 
      Appearance -> Dynamic@If[pressed, "Pressed", Automatic]]]],
   {i, 0, 1}, {j, 6}]]

Mathematica graphics

A somewhat different approach is to concatenate multiple TogglerBars: this has some drawbacks, as the output is always sorted (if not then output order depends on the order of clicks and the order of TogglerBar rows).

TogglerGrid::usage = 
  "TogglerGrid[x, {val.1, val.2, ...}, n] represents a \
TogglerBar-like control (with setting x and with toggler buttons for \
values val.i to include in the list x), but with togglers arranged in \
a grid, with a maximal n elements per row.";

TogglerGrid[var_, ref_] := TogglerGrid[var, ref, Length@ref];
TogglerGrid[Dynamic[var_], list_List, n_] := Module[
   {set, ref = Evaluate@list, temp},
   temp = {} & /@ ref;
   set = TogglerBar[
       Dynamic[temp[[#]], 
        Function[{$x}, temp[[#]] = $x; 
         var = Sort@(Join @@ temp)]], {ref[[#]]}] & /@ 
     Range@Length@ref;
   Grid[
    Partition[set, n, n, {1, 1}, {}],
    Alignment -> {Center, Center},
    Spacings -> {0, 0}]
   ];
TogglerGrid[var_, arg___] := 
  Module[{dummy = var}, TogglerGrid[Dynamic@dummy, arg]];

Test the function:

x = {};
Dynamic@x
TogglerGrid[Dynamic[x], 
 Table[Graphics[{Hue@RandomReal[], Disk[]}, ImageSize -> 20], {10}],
  5]

Mathematica graphics

$\endgroup$
9
  • $\begingroup$ I think so, will try it now. $\endgroup$ Commented Jun 28, 2012 at 10:02
  • $\begingroup$ In your example I would like to have {5,7,9} as a result. $\endgroup$ Commented Jun 28, 2012 at 10:06
  • $\begingroup$ @ndroock1: Please see edit. It is more along the lines of your posted code. $\endgroup$ Commented Jun 28, 2012 at 10:10
  • $\begingroup$ That does it, although your previous answer had some nice features regarding building the grid. $\endgroup$ Commented Jun 28, 2012 at 10:19
  • $\begingroup$ @ndroock1: I re-added TogglerGrid. I only removed it previously because I realized it is not exactly an answer to your question. Hope it can be of any use. $\endgroup$ Commented Jun 28, 2012 at 12:00
2
$\begingroup$

Starting at least in M9, TogglerBar supports an Appearance option that produces a grid:

DynamicModule[{idx = {}},
    {
    TogglerBar[
        Dynamic[idx],
        Table[i -> Graphics[{Blue, Disk[]}, ImageSize->20], {i, 12}],
        Appearance -> "Horizontal" -> {2, Automatic}
    ],
    Dynamic[idx]
    }
]

enter image description here

where I show an image after clicking a few times.

$\endgroup$
0
$\begingroup$

In the following, I tried to start with the complete list, with sorting, and deleting duplicates. It works except that you have to click twice the first time on each number. Can this be fixed? It would also be nice if the button changed color to red when off. I tried, but couldn't get it to work. And if each circle had its number in it.

n = 12;
list = Range[n];
Dynamic@list

gOn = Show[Graphics[{Blue, Disk[]}], ImageSize -> 20];
gOff = Show[Graphics[{Red, Disk[]}], ImageSize -> 20];
this = {gOn, gOff};

tb01 = 
 Table[Show[gOn   , 
   Graphics[{Text[Style[ToString[k], White, Bold]]}]], {k, 1, 12}]
    tb02 = 
 Table[Show[gOff, 
  Graphics[{Text[Style[ToString[k], White, Bold]]}]], {k, 1, 12}]

flags = ConstantArray[1, n];

Grid[Table[DynamicModule[{pressed = False, hold = i*6 + j, that},
   With[{idx = hold},
    If[flags[[hold]] == 1, that = tb01[[hold]], 
 that = tb02[[hold]]];
    Button[that, pressed = ! pressed;
     list = 
  DeleteDuplicates[
   Sort[If[pressed, Append[list, idx], DeleteCases[list, idx]]]],
     Appearance -> 
  Dynamic@If[pressed, "Pressed", Automatic]]]], {i, 0, 1}, {j, 6}]]
$\endgroup$

Your Answer

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

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