Re: Radio buttons panel

*To*: mathgroup at smc.vnet.net*Subject*: [mg102403] Re: [mg102361] Radio buttons panel*From*: Leonid Shifrin <lshifr at gmail.com>*Date*: Sat, 8 Aug 2009 04:37:45 -0400 (EDT)*References*: <h4m4ca$ecg$1@smc.vnet.net> <h4p3g1$itm$1@smc.vnet.net>

Hi, a good question (IMO anyway)! The first part is easy: Panel[Grid[#]] &@ Map[{RadioButtonBar[Dynamic[#], {"X", "34", "36", "56"}]} &, Table[Unique[], {3}]] will do. If you want to disable radio-buttons conditionally, my understanding is that RadioButtonBar wouldn't do - I could not find a syntax (in documentation) that allows to disable individual buttons in a bar. Here is my attempt: Clear[radioButtonBar]; radioButtonBar[bt_, state : {(_ | {_, True | False}) ..}] := With[{separ = " "}, Row@Replace[ Replace[state, x_?(Not[MatchQ[#, {_, True | False}]] &) :> {x}, 1], {val_, enabled : (True | False) : True} :> Sequence[RadioButton[bt, val, Enabled -> enabled], separ, val, separ], 1]]; radioButtonBar[bt_, state : {(_ | {_, True | False}) ..}, changeAt : {(_Integer :> (True | False )) ...}, flag : "Position"] := Module[{newstate = state}, newstate[[changeAt[[All, 1]]]] = MapThread[ Replace[##, {0}] &, {newstate[[changeAt[[All, 1]]]], {{x_, val : (True | False)} :> {x, #}, x_ :> {x, #}} & /@ changeAt[[All, 2]]}]; radioButtonBar[bt, newstate]]; radioButtonBar[bt_, state : {(_ | {_, True | False}) ..}, changeAtValue : {(_ :> (True | False )) ...}, flag : "Value"] := radioButtonBar[bt, state, RuleDelayed @@@ Flatten[Map[Thread[{Flatten[Position[state, #[[1]]]], #[[2]] }] &, changeAtValue], 1], "Position"]; Examples of use: In[1]:= radioButtonBar[Dynamic[x],{"X",{"34",False},{"36",False},"56"}] In[2]:= radioButtonBar[Dynamic[x],{"X","34","36","56"},{1:> False,2:> False},"Position"] In[3]:= radioButtonBar[Dynamic[x],{"X","34","36","56"},{"34":> False,"56":> False},"Value"] As can be seen, this allows to disable readio buttons according to their positions or value. This will make a panel then: Clear[makePanel]; makePanel[nrows_Integer?Positive, vars : Hold[__Symbol], values_List, activeRules : {({_Integer, _} :> (True | False)) ...}, flag : ("Position" | "Value")] := Dynamic[Panel[Grid[#]] &@ Apply[List, MapIndexed[ Function[Null, { radioButtonBar[Dynamic[#], values, Cases[ activeRules, ((x : ({row_, col_} :> enable_)) /; row === First@#2) :> ( col :> enable)], flag]}, HoldFirst], vars]]]; makePanel[nrows_Integer?Positive, values_List, activeRules : {({_Integer, _} :> (True | False)) ...}, flag : ("Position" | "Value")] := makePanel[nrows, panelVariables[] = Hold @@ Evaluate[Table[Unique[], {nrows}]], values, activeRules, flag]; makePanel[nrows_Integer?Positive, values_List, activeF : (_Function | _Symbol)] := With[{vars = panelVariables[] = Hold @@ Evaluate[Table[Unique[], {nrows}]]}, makePanel[nrows, vars, values, activeF @@ vars, "Value"]]; It is somewhat awkward, but I don't have time to improve at the moment. It has a syntax that allows to disable buttons at specific positions: makePanel[3, {"X", "34", "36", "56"}, {{1, 3} :> False, {2, 4} :> False}, "Position"] or specific values of the variables: makePanel[3, {"X", "34", "36", "56"}, {{1, "34"} :> False, {2, "56"} :> False}, "Value"] additionally, it is possible to implement constraints like the one you mentioned, but it is not very pretty at the moment. You have to define a function that will take variable values and generate the list of button-disabling rules as in the last example above. For example, this will not allow two buttons to be filled at the same column: Clear[activeFn]; activeFn[vars__] := Thread[Flatten[ MapIndexed[ Thread[{Complement[Range[Length[{vars}]], #2], #1}] &, {vars}], 1] :> False]; for example: In[] = activeFn[a, b, c] Out[] = {{2,a}:>False,{3,a}:>False,{1,b}:>False,{3,b}:>False,{1,c}:>False,{2,c}:>False} Then you call makePanel: makePanel[4, {"X", "34", "36", "56", "72"}, activeFn] I also made the values of variables available through global "function" panelVariables[], which returns the held list of variable names. By subscripting it as panelVariables[][[1]] , panelVariables[][[2]], etc, you get the values of individual variables. The drawback is that you can not use it if you have several panels active at the same time - it will only give you the variables of the most recently defined one. This can be fixed. There are also other flaws, of course. Perhaps others will give more elegant and compact solutions, but anyway. Regards, Leonid On Fri, Aug 7, 2009 at 1:27 PM, King, Peter R <peter.king at imperial.ac.uk>wrote: > I want to create an input panel using radio buttons. I can easily do this > with > > Panel[Grid[{{RadioButtonBar[ > Dynamic[x], {"X", "34", "36", "56"}]}, {RadioButtonBar[ > Dynamic[y], {"X", "34", "36", "56"}]}, {RadioButtonBar[ > Dynamic[z], {"X", "34", "36", "56"}]}}]] > > Except I want the different variables x, y, z etc to be members of an > arrayx[[i]] > > x = Table["X", {4}];Panel[Grid[ > Table[{RadioButtonBar[Dynamic[x], {"X", "34", "36", "56"}]}, {i, 1, > 4}]]] > > Doesn't work as it treats x as a scalar not a list. > > Panel[Grid[ > Table[{RadioButtonBar[Dynamic[x[[i]]], {"X", "34", "36", "56"}]}, {i, 1, > 4}]]] > > Gives nonsense. > > Is there a neat way to do this? (I could easily use the top version then > set x[[1]] to x, x[[2]] to y etc (actually I can't use x in two different > ways but I'm sure you know what I mean). > > Furthermore I want the choice selection in one row to influence what > options are available in the next row. Think of the rows as time going > downwards. I have free choice of which option I can use in row 1. In the > next row then not all options are available. The easiest is that I cannot > repeat a selection. So I cannot have X in row 1 followed by X in row 2, so I > would like that button blanked out (or greyed in or some such). Perhaps what > I want this to look like is initially the panel has all the buttons greyed > and unusable except for the first row. Having chosen say 34 from the first > row, the second row buttos are "ungreyed" except for 34 (there are some > other rules such as 34 cannot be followed by 36 or 56 followed by 36 but I > can probably sort that out later). > > Finally I want the length of the list (set as 4 above) to be dependent on > the result of a drop down menu at the top of the panel - not shown. > > I know this is 3 questions not 1 but they are linked. > > Thanks in advance. > >