4
$\begingroup$

I wrote some code to monitor the tasks that I'm doing - looks like this:

enter image description here

Now it works just fine, but as soon as I wrap it up in palette it dies:

enter image description here

Nothing updates.... I know there must be an easy way to fix this - I'm probably something wrong with the namespace of the dynamic parts... but I'm blanking on it.

The reason I'd like to use a palette here because it's detachable and looks like it's own app. Here's the code:

    taskQueue[input:{{title_String, mins_},__}] := Module[
        {getTime, remaining = <||>, taskQueue = <||>, row, grid={}, currtitle, st},

        Do[
            taskQueue[i[[1]]] = i[[2]]*60;
            , {i, input}
        ];

        remaining = taskQueue;
        getTime[t_] := Lookup[remaining, input[[t,1]], 0];

        Do[ 
            row = {}; 
            AppendTo[row, 
                Item[Style[input[[i,1]], FontFamily->"Constantia", FontSlant->Italic, 
                    FontWeight->Bold, FontSize->16], Alignment->Left]
            ];

            AppendTo[row, 
                    With[{i=i},
                        Dynamic[formatSeconds@getTime[i], UpdateInterval->1]
                    ]
            ];
            AppendTo[grid, row];

            , {i, 1, Length@remaining}
        ];

        st=CreateScheduledTask[
            If[Length@remaining==0, 
                RemoveScheduledTask[ScheduledTasks[]],
                If[remaining[[1]]<=0, 
                    remaining= Rest@remaining;
                ];
                remaining[[1]]=remaining[[1]]-1
            ]
        ,1];

        AppendTo[grid,{startStopButton[StartScheduledTask[st], StopScheduledTask[st]],
            Dynamic[formatSeconds[Total@remaining], UpdateInterval->1, TrackedSymbols:>{remaining}]
        }];

        Framed[
            Grid[grid,
                Alignment -> {Left, Center}, 
                Dividers -> {None, {All,-1->False}},
                Spacings -> {1,2},
                Background -> {None, {Min[Length[taskQueue], 
                        Dynamic[Length[taskQueue]-Length[remaining]+1,UpdateInterval->1]]->LightBlue}},
                BaselinePosition -> Center
            ],
            FrameMargins->10,
            FrameStyle -> GrayLevel[0.64],
            RoundingRadius -> 5
        ]
    ]

(*Additional definitions needed*)

$playView=ToExpression@GraphicsBox[
                TagBox[{
                  {GrayLevel[0.9], RectangleBox[{5, -158}, {29, -135}]}, 
                  {RGBColor[0.26,0.68,0.46], 
                   PolygonBox[NCache[{{13, -153}, {13, -140}, {21, Rational[-293, 2]}, {13, -153}}, {{13, -153}, {13, -140}, {21, -146.5}, {13, -153}}]]}, 
                  {GrayLevel[0.5], 
                   StyleBox[LineBox[{{5, -158}, {5, -135}, {29, -135}, {29, -158}, {5, -158}}],
                    Antialiasing->False]}},
                 Null],
                ImageSize->{29.4921875, Automatic}];

    $stopView=ToExpression@GraphicsBox[
                 TagBox[{
                   {GrayLevel[0.9], RectangleBox[{34, -158}, {58, -135}]}, 
                   {RGBColor[0.81,0.33,0.26], RectangleBox[{42, -150}, {50, -143}]}, 
                   {GrayLevel[0.5], 
                    StyleBox[LineBox[{{34, -158}, {34, -135}, {58, -135}, {58, -158}, {34, -158}}],
                     Antialiasing->False]}},
                  Null]];

    Attributes[cycleState]={HoldFirst};
    cycleState[s_/;s>0,len_:2] := s = If[s>=len,1,s+1]

    SetAttributes[startStopButton,HoldAllComplete];
    startStopButton[startAction_, stopAction_] := DynamicModule[
         {views={$playView, $stopView},state=1},
                Button[Dynamic[views[[state]]], Switch[state,1,startAction,2,stopAction];state=cycleState[state];,Appearance->"Frameless"]
            ]

    Options[formatSeconds] = {"FixedWidth"->True};
    formatSeconds[secconds_, opts:OptionsPattern[]] := Module[
            {timeUnits = UnitConvert[Quantity[secconds, "Seconds"], MixedRadix["Hours", "Minutes", "Seconds"]],
            hours,mins,secs},

            hours = timeUnits[[1,1]];
            mins = timeUnits[[1,2]];
            secs = Round@timeUnits[[1,3]];

            Return @ iFormatSeconds[hours, mins, secs]
        ]

    Options[iFormatSeconds] = Options[formatSeconds];
    iFormatSeconds[hours_, mins_, secs_, OptionsPattern[]] := Module[
            {hf,mf,sf},

            hf = IntegerString[hours, 10, 2];
            mf = IntegerString[mins, 10, 2];
            sf = IntegerString[secs, 10, 2];

            Return @ Style[StringRiffle[{hf, mf, sf},":"], FontFamily->"Digital-7", FontSize->24]
    ]
$\endgroup$
  • $\begingroup$ I tried all the usual tricks with dynamicmodule and stuff, and still cannot get the clock to tick down when in a palette. Also, it's a tad on the slow side I'm realizing now... any ideas to speed it up would be great :) $\endgroup$ – M.R. Sep 25 '15 at 3:19
  • $\begingroup$ Your function taskQueue is dependent on a function you call getTime. Are you sure that the palette code has access to that function? $\endgroup$ – m_goldberg Sep 25 '15 at 5:37
  • $\begingroup$ Doesn't it? Since getTime is inside the module? $\endgroup$ – M.R. Sep 26 '15 at 15:54
  • 1
    $\begingroup$ Could you not reduce the problem to a more manageable minimal example? There is a lot of formatting work in your code: could you strip layer by layer to pinpoint the point of failure? If you run taskQueue as a palette, an error is reported in the messages window saying: StartScheduledTask::timnf: Specified task st$159915 is not found. As you say, this seems an indication of a scoping problem. Have you tried to isolate the problem yourself though? $\endgroup$ – MarcoB Sep 30 '15 at 14:25
  • 1
    $\begingroup$ It's nonsensical to post such a large piece of code unrelated to the problem and expect someone to read and understand it all. $\endgroup$ – Dr. belisarius Sep 30 '15 at 16:40
2
+50
$\begingroup$

Based on the error message the ScheduledTask seems to cause the problems. Therefore here is a way how to make a palette with a clock that can be started, stopped and continued by clicking a button without using a ScheduledTask.

CreatePalette@
 DynamicModule[{startStop = False, last = 0, refTime = AbsoluteTime[]}, 
  Grid[{{Dynamic[
      Refresh[If[startStop, Round[last = AbsoluteTime[] - refTime], 
        Round[last]], UpdateInterval -> 1]]},
    {Button[Dynamic@If[startStop, $stopView, $playView], 
      If[startStop, startStop = ! startStop, startStop = ! startStop; 
       refTime = AbsoluteTime[] - last]]}}, 
   Alignment -> {Left, Center}, 
   Dividers -> {None, {All, -1 -> False}}, Spacings -> {1, 2}, 
   BaselinePosition -> Center]]

StopWatchPalette

The reasons why the ScheduledTask causes problems and how these can be resolved can be found in this Q&A.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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