如何在Manipulate控件的定义中使用宏内部的宏?

时间:2011-12-10 09:40:55

标签: wolfram-mathematica

我正在使用Leonid的宏方法(see here)来帮助我管理Manipulate的控制变量布局。

但我发现在宏中,我无法使用其他地方定义的另一个宏。所以我想知道是否有办法在另一个宏中使用宏?

为了解释这个问题,我将首先使用一个级别的宏显示一个非常简单的Manipulate,然后我将通过尝试使用另一个宏来显示问题。

Manipulate[Text["ok"],

 Evaluate@With[{

    x = Function[{},  (*----> macro x *)
      TabView[{
        "x" -> "working on x"
        }], HoldAll
      ],

    y = Function[{}, (*----> macro y *)
      TabView[{
        "y" -> "working on y"
        }], HoldAll
      ]
    },(*WITH*)

   (* now use the above macros *)
   Grid[{
     {SetterBar[Dynamic[choice], {1, 2}]},
     {Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
     }]

   ],
 {{choice, 1}, None},
 ContentSize -> 300

 ]

enter image description here

现在为复选框添加一个宏,然后尝试在上面的'x'宏中使用它:

操纵[文字[ “OK”],

 Evaluate@With[{

    checkBox = Function[{}, Checkbox[Dynamic[c]], HoldAll],

    x = Function[{},
      TabView[{
        "x" -> checkBox[] (*=====> DOES NOT WORK, did not bind *)
        }], HoldAll
      ],

    y = Function[{},
      TabView[{
        "y" -> "working on y"
        }], HoldAll
      ]
    },(*WITH*)

   Grid[{
     {SetterBar[Dynamic[choice], {1, 2}]},
     {Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
     }]

   ],
 {{choice, 1}, None},
 {{c, True}, None},
 ContentSize -> 300

 ]

我们认为它不起作用。 'x'宏没有'看到'复选框宏。

enter image description here

但是如果我直接在'x'宏中添加复选框的代码,它当然会起作用:

Manipulate[Text["ok"],

 Evaluate@With[{

    x = Function[{},
      TabView[{
        "x" -> Checkbox[Dynamic[c]]  (* add the definition directly *)
        }], HoldAll
      ],

    y = Function[{},
      TabView[{
        "y" -> "working on y"
        }], HoldAll
      ]
    },(*WITH*)

   Grid[{
     {SetterBar[Dynamic[choice], {1, 2}]},
     {Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
     }]

   ],
 {{choice, 1}, None},
 {{c, True}, None},
 ContentSize -> 300

 ]

enter image description here

所以,问题是:是否可以在'x'宏中使用上面的复选框宏?

为了使它更容易,我不会将任何参数传递给宏。我只是使用一个宏作为一个较大的代码片段(控制变量定义)的“简写”名称,如上所示。

这只是为了让我更容易通过仅移动宏名称来布局UI,而不是移动宏定义的更大的代码片段。由于Manipulate没有GUI构建器,因此当需要管理大量控件时,此方法会有所帮助。

2 个答案:

答案 0 :(得分:7)

这是因为在这种情况下你需要一个嵌套的With。您不能在With的同一声明列表中使用另一个变量的声明。以下是您问题的简化版本:

In[3]:= With[{a=b,c=f[a]},g[c]]
Out[3]= g[f[a]]

这就是你需要的:

In[5]:= 
With[{a=b},
  With[{c=f[a]},g[c]]]

Out[5]= g[f[b]]

在您的情况下,checkBox扮演a角色,x扮演c角色。

关于如何制作允许这种连续绑定的With版本的主题,在Mathgroup和SO上已多次讨论过。这是我的implementation这样的结构:

ClearAll[LetL];
SetAttributes[LetL, HoldAll];
LetL /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[LetL[{__}, _]]] :=
   Block[{With}, Attributes[With] = {HoldAll};
     lhs := Evaluate[rhs]];
LetL[{}, expr_] := expr;
LetL[{head_}, expr_] := With[{head}, expr];
LetL[{head_, tail__}, expr_] := 
  Block[{With}, Attributes[With] = {HoldAll};
     With[{head}, Evaluate[LetL[{tail}, expr]]]];

如果您愿意使用它,您只需在代码中将With更改为LetL

答案 1 :(得分:1)

我是这个网站的新手,所以你想要做的事情可能会有不同的目标,但有什么理由不能直接对此进行编码吗?

DynamicModule[{choice = 1, c = False},

 Grid[{
   {SetterBar[Dynamic[choice], {1, 2}]},
   {Dynamic[
     Which[choice == 1, TabView[{"x" -> Checkbox[Dynamic[c]]}], 
      choice == 2, TabView[{"y" -> "working on y"}]]]},
   {Dynamic[choice], Dynamic[c]}
   }]
 ]