9

With Dynamic and gui-constructs like Popup I always have a problem: when an expression takes a while to evaluate the Dynamic parts look bad and usually breaks. For example, imagine a PopupMenu showing choices whose data has yet to be downloaded. I tried using things like PrintTemporary but they didn't achieve the in-place effect I'm looking for.

So, for an arbitrarily long running dynamic, inserting Activity Indicators (looped animations) seamlessly is what I'm after.

Here's my first attempt:

enter image description here

and the code:

assnMenu[f_,a_Association, title_:"Choose"] := Module[
        {am,b,r,g},
        blup=Style[Pane[Magnify[ProgressIndicator[Appearance->"Percolate"],2]
            ,Alignment->Center],Background->Transparent];
        r=blup;
        g:=(r=blup;r=f[#])&;
        onValueChange[b, g];
        am = Table[With[{i=i}, a[i]:>(b=i)], {i, Keys@a}];
        b = First @ Keys[a];
        Panel @ Grid[
            {{ActionMenu[title, am, Method->"Queued"], 
                Dynamic[Style[a[b],FontFamily->"Arial Black",FontSize->14],UpdateInterval->1]},
            {Dynamic[r, TrackedSymbols:>{r}],SpanFromLeft}},
            Alignment->{Center,Center}
        ]
    ]

onValueChange[a_,f_] := Module[{},
        a/:Set[a,x_]:=((OwnValues[a]={HoldPattern[a]:>x}; f[x]);a)
    ]

This almost achieves what I want, but has a few glitches:

  • This seems too complicated to be the right way to do this.
  • In the current form assnMenu[slowFunc, <|10 -> "A", 5 -> "B"|>] takes 10 seconds to evaluate, so there is leakage.
  • I couldn't get it to work with a DynamicModule, (which has the nice option DynamicEvaluationTimeouts), which would help a lot.
  • I probably overlooked some part of the docs, I feel like there should already be high level functionalities handling this sort of stuff.
Karsten7
  • 27,448
  • 5
  • 73
  • 134
M.R.
  • 31,425
  • 8
  • 90
  • 281

1 Answers1

11

An adaption of this answer for an ActionMenu and to your styling:

assnMenuK[slowF_, a_Association, title_: "Choose"] := 
 DynamicModule[{done = False, lastSelection = ""},
  Grid[{{
     ActionMenu[title,
      KeyValueMap[#2 :> (lastSelection = #2; done = "working"; 
          slowF[#1]; done = True) &, a], Method -> "Queued"],
     Dynamic@Style[lastSelection, FontFamily -> "Arial Black", FontSize -> 14]},
    {Dynamic@Switch[done, False, "",
       True, "done", 
       "working", ProgressIndicator[Appearance -> "Percolate"]], 
     SpanFromLeft}}]]

Example:

assnMenuK[Pause, <|1 -> "A", 2 -> "B"|>]

example


The "in-place effect" can be improved even further, e.g., by using Invisible["A"] instead of "" and PaneSelector instead of Switch.

assnMenuK2[slowF_, a_Association, title_: "Choose"] := DynamicModule[
  {done = False, lastSelection = Invisible["A"]},
  Panel@Grid[{
     {ActionMenu[title,
       KeyValueMap[#2 :> (lastSelection = #2; done = "working";
           slowF[#1]; done = True) &, a]
       , Method -> "Queued"], 
      Dynamic@Style[lastSelection, FontFamily -> "Arial Black", FontSize -> 14]}, 
     {PaneSelector[
        {False -> "",
         True -> "done",
         "working" -> ProgressIndicator[Appearance -> "Percolate"]},
        Dynamic@Setting@done
        , Alignment -> Center],
      SpanFromLeft}}]]

assnMenuK2[Pause, <|1 -> "A", 2 -> "B"|>]

example2

Karsten7
  • 27,448
  • 5
  • 73
  • 134