5

I want to run a command (writing page ranges to a file) at the end of each frame.

I can capture the page the frame started with at the beginning with \AtBeginEnvironment{frame}{\global\edef\framebeginpage{\thepage}}.

But if I try to write the page range at the end of the frame, it does not work: It seems that \AtEndEnvironment{frame}{\immediate\write\notesfile{\framebeginpage-\thepage}} doesn't get executed.

Is there anything I can do instead?

MMWE:

\documentclass{beamer}

\usepackage{etoolbox}

\newwrite\notesfile
\AtBeginEnvironment{frame}{\global\edef\framebeginpage{\thepage}}
\AtEndEnvironment{frame}{\immediate\write\notesfile{\framebeginpage-\thepage}}


\begin{document}
\immediate\openout\notesfile=frames.txt
\immediate\write\notesfile{Begin}

\begin{frame}
    \begin{itemize}[<+->]
        \item foo
        \item bar
        \item baz
    \end{itemize}
\end{frame}

\begin{frame}
    \begin{itemize}[<+->]
        \item foo
        \item bar
        \item baz
    \end{itemize}
\end{frame}

\immediate\write\notesfile{End}
\immediate\closeout\notesfile
\end{document}
moi
  • 373

2 Answers2

8

This is what the beamer base frame template - beamerbaseframe.sty - says about the frame "environment":

% Normally not executed; only in containsverbatim context:
\def\endframe{\egroup\begingroup\def\@currenvir{frame}}

So, if you try to tap into \end{frame}, it might not end up as expected. Instead, you have to dig into some of the beamer bowels to find a location where you can write content out to your file. The following patch grabs on to an appropriate location:

\documentclass{beamer}

\usepackage{etoolbox}

\newwrite\notesfile
\AtBeginEnvironment{frame}{\global\edef\framebeginpage{\arabic{page}}}
\makeatletter
\patchcmd{\beamer@doseveralframes}% <cmd>
  {\beamer@reseteecodes}% <search>
  {\beamer@reseteecodes\immediate\write\notesfile{\framebeginpage-\number\numexpr\value{page}-1\relax}}% <replace>
  {}{}% <success><failure>
\makeatother


\begin{document}
\immediate\openout\notesfile=frames.txt
\immediate\write\notesfile{Begin}

\begin{frame}
    \begin{itemize}[<+->]
        \item foo
        \item bar
        \item baz
    \end{itemize}
\end{frame}

\begin{frame}
    \begin{itemize}[<+->]
        \item foo
        \item bar
        \item baz
    \end{itemize}
\end{frame}

\immediate\write\notesfile{End}
\immediate\closeout\notesfile

\end{document}

The output file frames.txt displays

Begin
1-3
4-6
End
Werner
  • 603,163
3

You could create a wframe environment to do the writing. EDITED to correct \thepage representation by one.

\documentclass{beamer}
\usepackage{etoolbox}

\newcounter{tmpcnt}
\newwrite\notesfile
%\AtBeginEnvironment{frame}{\global\edef\framebeginpage{\thepage}}
%\AtEndEnvironment{frame}{\immediate\write\notesfile{\framebeginpage-\thepage}}
\newenvironment{wframe}{\global\edef\framebeginpage{\thepage}\begin{frame}}
    {\end{frame}\setcounter{tmpcnt}{\thepage}\addtocounter{tmpcnt}{-1}%
  \immediate\write\notesfile{\framebeginpage-\thetmpcnt}}

\begin{document}
\immediate\openout\notesfile=frames.txt
\immediate\write\notesfile{Begin}

\begin{wframe}
    \begin{itemize}[<+->]
        \item foo
        \item bar
        \item baz
    \end{itemize}
\end{wframe}

\begin{wframe}
    \begin{itemize}[<+->]
        \item foo
        \item bar
        \item baz
    \end{itemize}

\end{wframe}

\immediate\write\notesfile{End}
\immediate\closeout\notesfile
\end{document}

The contents of frames.txt that results is

Begin
1-3
4-6
End
  • Will wframe behave as frame with respect to the optional and "mandatory" arguments? – Gonzalo Medina Feb 03 '15 at 19:30
  • @GonzaloMedina I think it will, since 1) it is the last item in the \begin{wframe} definition AND 2) wframe is defined with 0 arguments. Thus, when \begin{frame} is called at the end of \begin{wframe}, I think its arguments will be waiting for it in the input stream. – Steven B. Segletes Feb 03 '15 at 19:34
  • Thanks! But I'd rather not use a different environment. – moi Feb 03 '15 at 21:39
  • @moi I understand that rationale. Hats off to Werner for decoding the problem. – Steven B. Segletes Feb 03 '15 at 21:41