Specify local Dynamic in Grid
I would like to update specific parts of a Grid
dynamically in different ways. Consider the following toy example: I have two rows: one must be updated one-by-one (a, b, c), as these symbols depend on different triggers; the second row depends on one single trigger (show) that allows displaying/hiding some data.
Now I know that I can wrap the whole Grid
structure into Dynamic
, and even specify which symbols to track, thus this example does what I want:
Checkbox[Dynamic[show]]
test = {0, 0};
Dynamic[Grid[{{Dynamic@a, Dynamic@b, Dynamic@c},
If[show, Prepend[test, "test:"], {}]}, Frame -> All],
TrackedSymbols :> {show}]
Though for certain reasons I would like to have a locally specified Dynamic
, that is only applied to the second row of the Grid
.
For those who are wondering what ungodly situation would it be, just imagine the followings: show
is used in any of a
, b
or c
, and these I do NOT want to update when show
is changing, their changes depend on other triggers. Why not remove then show
from the symbols of the first row? Imagine, I can't, as show
is present in a function that is used in a
, b
or c
, and this function I cannot access easily.
Of course wrapping the first argument of If
into Dynamic
won't help here, as the Grid
itself or any of its cells won't become dynamic:
Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
If[Dynamic@show, Prepend[test, "test:"], {}]
}, Frame -> All]
Furthermore, wrapping a row into Dynamic
makes the given row invalid, as it does not have head List
anymore:
Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
Dynamic@If[show, Prepend[test, "test:"], {}]
}, Frame -> All]
Mapping Dynamic
over the row does not work either because show
is not updated dynamically:
Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
Dynamic /@ If[show, Prepend[test, "test:"], {}]
}, Frame -> All]
Also, wrapping Dynamic[If[...]]
around list members work, but now I have to evaluate If
3 times instead of just 1.
Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
Dynamic[If[show, #, ""]] & /@ Prepend[test, "test:"]
}, Frame -> All]
Would like to know if there is any solution to overcome this particular problem by locally applying a Dynamic
wrapper on a row.
Here is a solution using the Experimental ValueFunction
show = True;
test = {0, 0};
Checkbox[Dynamic[show]]
Now write your own little Dynamic update function on the side
Needs["Experimental`"];
row = {};
updateRow[x_, v_] := row = If[v, Prepend[test, "test:"], {}];
ValueFunction[show] = updateRow;
Now make the Grid, and now can use Dynamic on EACH row, not around the whole Grid, which is what you wanted:
Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
{Dynamic@row}
},
Frame -> All
]
ps. I just read a post here by telefunkenvf14 that mentions this package and this function, which I did not know about, and when I saw this function, I remembered this question, and I thought it should be possible to use that function to solve this problem.
ps. I need to work more on placing the grid row correctly....
update(1)
I can't figure how to splice the final row over the columns in the grid. Which is strange, as it has List head, yet it won't go across all the columns. It will only go in the first cell. Tried Sequence, SpanFromLeft, and such, but no luck. May be someone can figure this part out.
Here is my current trial:
Needs["Experimental`"];
row = {};
updateRow[x_, v_] := row = If[v, {"test:", 0, 0}, {}];
ValueFunction[show] = updateRow;
show = False;
Checkbox[Dynamic[show]]
f = Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
List@Dynamic[row]
},
Frame -> All
]
It seems it should be doable. I do not see what is the problem now...
update(2)
As a temporary solution, I split the second row by force before hand. This made it possible to do what I want. Not sure if this meets the OP specifications or not (my guess is that it does not), but here it is:
Needs["Experimental`"];
ra = 0;
rb = 0;
rc = 0;
updateRow[x_, v_] :=
row = If[v, ra = "test:"; rb = 0; rc = 0, ra = ""; rb = ""; rc = ""]
ValueFunction[show] = updateRow;
show = False;
Checkbox[Dynamic[show]]
f = Grid[{
{Dynamic@a, Dynamic@b, Dynamic@c},
{Dynamic@ra, Dynamic@rb, Dynamic@rc}
},
Frame -> All]
This is actually a comment on @Nasser's solution and suggested fix to avoid manual splitting of the second row, but because of space limitations in the comment area, I post it as answer. Will be happy to delete it as soon as Nasser confirms that it works and incorporates it into his answer.
The clue to a solution is found in the Possible Issues
section of Item
in the documentation:
If Item is not the top-most item in the child of a function that supports Item, it will not work.
I use this to modify @Nasser's solution in the following way. First, I need to change the definition of row
so that for both values of show
the length of row
is the same.
Needs["Experimental`"];
row = {"", "", ""};
updateRow[x_, v_] := row = If[v, Prepend[test, "test:"], {"", "", ""}];
Experimental`ValueFunction[show] = updateRow;
The second change needed is to wrap each element of Dynamic@row
with Item
:
Grid[{{Dynamic@a, Dynamic@b, Dynamic@c},
{Item[Dynamic@row[[1]]], Item[Dynamic@row[[2]]],
Item[Dynamic@row[[3]]]}}, Frame -> All]
Edit: Item
wrapper is not really needed; it works just as well without it:
Grid[{{Dynamic@a, Dynamic@b, Dynamic@c},
{Dynamic@row[[1]], Dynamic@row[[2]],
Dynamic@row[[3]]}}, Frame -> All]
链接地址: http://www.djcxy.com/p/57184.html
上一篇: 创建新应用程序按钮不存在任何地方
下一篇: 在网格中指定本地动态