To add a Divider between rows in a Grid, one way I know how to do it is by using the Dividers
option. But this is used at the end, and one must then know the row number to which a divider needs to be below it. So, for large grid, I find myself using trial and error until I find the correct row number. Then when I change the grid later, I have to do the trial and error again to put the divider in the correct place in case it moved after my changes.
In this example, there is a grid with 3 rows and I want to add divider below say the second row, so I can do this:
Grid[{
{1},
{2},
{3}
}, Frame -> True, Dividers -> {All, 3 -> True}]
Another way, is to put False
and True
, in correct order where I want a divider, like this
Grid[{
{1},
{2},
{3}
}, Frame -> True, Dividers -> {All, {True, False, True, True}}]
It would be nice if I could do something like this (like one can do for Manipulate) (ofcourse this below does not work here)
Grid[{
{1},
{2},
Delimiter,
{3}
}, Frame -> True]
or
Grid[{
{1},
{Item[2,Dividers->True]},
{3}
}, Frame -> True]
or such thing.
It will make code maintenance easier.
I looked at using Item and such for this, but not able to figure it out.
Any one knows of a trick to do it?
edit:
btw, This trick if possible, does not only apply to Dividers. But it would be useful to be able to do many of the other Grid options, which now is done at the Grid level, be done as well at the item level. For example, if I want to add an extra space after some row, it will easier to say so right at the pace I wanted this done. Also, if I wanted to change the Item size, easier to do it at the spot, same for Spacings, etc.. So that when moving/copying code for a whole row or Item, it is self contained and copy it with all its options together.
I think now this might require a new option add to Mathematica Grid to make it work right and be consistent with the over all grid design.
This is all until a GUI builder is made for Mathematica.
I find that I spend more than 60% of my time when I write a demo getting the GUI to fit and look right. With a GUI builder, I can spend this time working on the algorithm instead. When I use Matlab GUIDE to make GUI, it takes me less than 5% of my time to make a similar GUI.
I wish that WRI would make a GUI builder for Mathematica, I think this will be the killer app for Mathematica if you ask me. But no body asked me :)
edit(2)
comment on Mr Wizard nice solution below.
I mainly wanted this feature for the Grids I use to layout controls for Manipulate
. Here is a simple example:
Manipulate[x,
Grid[{
{Control[{{x, 0, "x"}, 0, 10, 1}]},
{Control[{{y, 0, "y"}, 0, 10, 1}]}
}, Frame -> None, Dividers -> {None, {False, True, False}}
]
]
(and I have to use Grid
for setting up the controls). I can't use function calls here. I can't write, using Wizard's solution below, the following:
Manipulate[x,
myGrid[{
{Control[{{x, 0, "x"}, 0, 10, 1}]},
spec["Divider"],
{Control[{{y, 0, "y"}, 0, 10, 1}]}
}, Frame -> None
],
Initialization :>
{
specfunc["Divider", lst_] := Dividers -> {None, # -> True & /@ lst};
myGrid[dat_, opts : OptionsPattern[]] :=
Module[{x = 1},
Grid[#, opts, Sequence @@ #2] & @@
Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@
dat, _, specfunc]
]
}
]
This gives an error, since Mathematica tries to first read the body of Manipulate to parse it, BEFORE reading and processing the initialization section.
But outside Manipulate, it will ofcourse work:
myGrid[{
{Control[{{x, 0, "x"}, 0, 10, 1}]},
spec["Divider"],
{Control[{{y, 0, "y"}, 0, 10, 1}]}
}, Frame -> None
]
specfunc["Divider", lst_] := Dividers -> {None, # -> True & /@ lst};
myGrid[dat_, opts : OptionsPattern[]] :=
Module[{x = 1},
Grid[#, opts, Sequence @@ #2] & @@
Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@
dat, _, specfunc]
]
I need to spend more time on this, to see if I can get it to work inside Manipulate.
btw, getting stuff like this to work inside Manipulate is really hard. Only trick I know is using macros with the With[{},.... Grid....]
pattern I learned from Leonid.
For example of such difficulties, see this question of mine
How to define constants for use with With[] in one place and then apply them later?
edit(3) My be I doing something wrong, but I am getting some errors inside Manipulate:
first example:
Manipulate[x,
Evaluate@grid[{
{Control[{{x, 0, "x"}, 0, 10, 1}]}
}
],
Initialization :>
{
grid[tab_, opts___] :=
Module[{divlocal, divglobal, div, pos},
divglobal = (Dividers /. opts) /. Dividers -> {False, False};
If[Depth[divglobal] == 1, divglobal = {divglobal, divglobal}];
If[Length[divglobal] == 1, AppendTo[divglobal, False]];
pos = Position[tab, Dividers -> _, 1];
divlocal =
MapIndexed[# - #2[[1]] + 1 -> Dividers /. tab[[#]] &,
Flatten[pos]];
divglobal[[2]] = {divglobal[[2]], divlocal};
Grid[Delete[tab, pos], Dividers -> divglobal, opts]];
}
]
gives error:
ReplaceAll::rmix: Elements of {False,{}} are a mixture of lists and nonlists. >>
same if I replace the above with
Evaluate@grid[{
Dividers -> {Thick, Blue},
{Control[{{x, 0, "x"}, 0, 10, 1}]}
}
],
Tried Dynamic@
in place of Evaluate@
no luck. may be small fix is all what is needed? or I am not using it right?