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

上一篇: 创建新应用程序按钮不存在任何地方

下一篇: 在网格中指定本地动态