Wrapping EventHandler by Table
There are several issues here. You need to "inject" the symbol name into the expression using With
(or similar) to prevent trying to make an assignment to ToExpression["col" <> ToString[i]]
. Further, you've got spurious Background ->
expressions which do not belong. (I also use Symbol
in place of ToExpression
.) That gives us:
DynamicModule[{col1 = Gray, col2 = Gray, col3 = Gray},
Table[
With[{bg = Symbol["col" <> ToString[i]]},
EventHandler[Dynamic@Style["x", 50, Background -> bg],
{"MouseClicked" :> (bg = bg /. {Gray -> Green, Green -> Gray})}]
],
{i, 1, 3}
] // Row
]
There is a problem with this however, because the symbols you create inside Table
, whether you use ToExpression or Symbol, are not localized as you expect. If you set col1 = "Fail!"
outside of the module you will see this problem.
Probably a better method is to use indexed objects as follows:
DynamicModule[{col},
col[_] = Gray;
Table[
With[{i = ii},
EventHandler[Dynamic@Style["x", 50, Background -> col[i]],
{"MouseClicked" :> (col[i] = col[i] /. {Gray -> Green, Green -> Gray})}]
],
{ii, 1, 7}
] // Row
]
A bit more concisely with Function
, Array
, and TimesBy
:
DynamicModule[{col},
col[_] = 1;
EventHandler[
Style["x", 50, Background -> Dynamic @ {Gray, Green}[[col@#]] ]
, {"MouseClicked" :> (col[#] *= -1)}
] & ~Array~ 7 // Row
]
Changing the position of Dynamic
also changes the behavior of the output when the kernel is terminated; the line resets but the X's can still be clicked to toggle.
When handling symbols like you do, I find it best to avoid converting from and to strings. This is typically needed in other languages to do meta-programming, however due to Mathematicas philosophy being that everything is an expression, meta-programming can be accomplished simply by holding evaluation order. Here is a simple implementation of your functionality:
SetAttributes[ClickAbleField, HoldAll]
ClickAbleField[var_] :=
EventHandler[
Dynamic@Style[x, Background ->var]
,{"MouseClicked" :> (var = var /. {Gray -> Green, Green -> Gray})}
]
DynamicModule[{col1 = Gray, col2 = Gray, col3 = Gray},
Row[{Hold[col1], Hold[col2], Hold[col3]}] /. Hold -> ClickAbleField
]
Note that I use hold to prevent imidiate evaluation of the col
variables, but also tell ClickAbleField
to hold it's input arguments using the attribute HoldAll
, such that the mentions inside it's definition will reference the unevaluted variable, and not it's current value.
If you have long lists of variables, you can also just pass them around in Hold
and map functions over them like you would ususally do, then release the hold afterwards:
DynamicModule[{col1 = Gray, col2 = Gray, col3 = Gray},
Row[List @@ (ClickAbleField /@ Hold[col1, col2, col3])]
]
If you want to generate something based on arbitrary lists of variables, you could use Unique
to generate the variables:
vars = Table[Unique["col"], {5}];
Hold[DynamicModule[initvars, body]] /. {
initvars -> Replace[Hold @@ vars, a_ :> (a = Gray), 1],
body -> Row[ClickAbleField /@ vars]
} /. Hold -> List // First
You can also use FlipView
Row[Table[FlipView[Style["x", 50, Background -> #] & /@ {Gray, Green, Red}], {5}]]