4
$\begingroup$

I am building a "batch photo cropper" UI.

I have a list of images to crop, and I can use Manipulate to make a nice cropping UI for each one:

Table[
 With[{im = im},
  Manipulate[
   HighlightImage[im, BoundingRegion@{p1, p2}, ImageSize -> 100],
   {p1, Locator},
   {p2, Locator},
   Button["Crop", Export["foo.jpg", ImageTrim[im, {p1, p2}]]]
   ]
  ]
  ,
  {im, ExampleData /@ ExampleData["TestImage"][[1 ;; 4]]}
]

batch-photo-crop

Now I would like to add a Crop All button, which would crop and save each image.

But I'm not sure how to pass each inner Manipulate's controls to an outer Button.

Here is a baby example of the behavior I'm looking for:

Manipulate[
 Row@{
   Manipulate[a, {a, 0, 1}],
   Manipulate[b, {b, 0, 1}]
   }
 ,
 Button["print", Print[a, b]]
 ]

The problem is that the print button prints ab, not the numeric values from the inner Manipulates. I would like to "bubble" those out, but I'm not sure how.

Is there a simple way to do this? Thanks!

$\endgroup$

1 Answer 1

5
$\begingroup$

You can use the LocalizeVariables option of Manipulate.

Manipulate[
 Row[{
   Manipulate[a, {a, 0, 1}, LocalizeVariables -> False]
   , Manipulate[b, {b, 0, 1}, LocalizeVariables -> False]
   }]
 , Button["print", Print[{a, b}]]
 ]

If you do not want the variable definitions to spill out of the outer Manipulate then wrap in DynamicModule.

Remove[a, b];
DynamicModule[
 {a, b}
 , Manipulate[
  ...
  ]
 ]

Your "TestImage" example uses a list instead of individual variables. The TrackingFunction on each of the Manipulate controls can be used to update the list without creating variable for each value.

DynamicModule[{c = Range[.2, .8, .2]}
 , Column[{
   Button["Print", Print[c], ImageSize -> Large]
   , Multicolumn[
    Manipulate[
       a
       , {
        {a, c[[#]], Subscript["c", #]}, 0, 1
        , TrackingFunction -> {None, Automatic, 
          Function[{v, e}, c[[#]] = v; e = v;, HoldRest]}
        }
       ] & /@ Range[Length@c]
    ]
   }]
 ]

enter image description here

Hope this helps.

$\endgroup$
6
  • $\begingroup$ This helps, thank you! One last question: how would you tweak your example to use indexed variables like a[[1]] and a[[2]], instead of a and b, so that I could work with a list? $\endgroup$ Apr 19, 2023 at 13:11
  • $\begingroup$ @ConvexMartian See update. $\endgroup$
    – Edmund
    Apr 20, 2023 at 19:14
  • $\begingroup$ WOW, thank you! I didn't know about TrackingFunction. This is great! $\endgroup$ Apr 21, 2023 at 12:59
  • $\begingroup$ Can I ask why the HoldRest is needed in the "updater" function? It still works without it. $\endgroup$ Apr 21, 2023 at 13:25
  • 1
    $\begingroup$ Ah, without HoldRest, the Messages window complains: Set::setraw: Cannot assign to raw object 0.645. Thank you! $\endgroup$ Apr 21, 2023 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.