根据标签动态隐藏 LaTeX 投影仪框架

根据标签动态隐藏 LaTeX 投影仪框架

我想我所处的配置会让很多人感到熟悉:在一个运行多年的项目中,我开发了一个非常大的 Beamer 演示文稿,其中包含很多幻灯片。LaTeX 源被分成许多文件,由于我必须经常重做项目的演示文稿,因此我根据时间/受众将这些文件包含(或不包含)在主文档中。

现在我想通过控制我希望包含的框架来自动生成演示文稿。使用<handout:0|beamer:0>框架定义时的参数似乎可以静态实现:

\begin{frame}
Hello.
\end{frame}

% this frame won't be included
\begin{frame}<handout:0|beamer:0>
  Hidden
\end{frame}

我希望让这种方法更加通用。因此,我在考虑

  • 根据框架定义关联一组标签
  • 稍后(以某种方式)决定在编译演示文稿时要使用的标签集,以便只考虑具有此标签的帧(因此隐藏其他帧)。

有人知道怎样做吗?

答案1

这真是一个好问题!

这是一个解决方案的开始,受到以下因素的启发:沃纳的评论并且几乎没有限制。这些限制是由于解决方案基于 Beamer。出于这个原因,我将其标记为社区 wiki,每个人都可以改进它(而且有很大的空间)。

它提供了一个简单的用户界面,目的是

  • 为区分版本创建标签;
  • 决定输出哪个版本。

第一个任务由钥匙提供

  1. create new version
  2. create multiple versions

名称非常清晰。要决定输出哪些帧,请利用:

  1. compile version
  2. compile frames选择一个版本内的框架子集
  3. compile generic frames从不同版本中选择框架。

如上所述,该机制在 Werner 的评论中描述得非常清楚:创建新版本只是意味着每次以这种方式标记帧时,都会实例化并更新一个(或更多)新计数器。编译版本是在后台进行的,通过创建传递给 的列表\includeonlyframes。到目前为止一切顺利。

现在让我们看看这种方法的局限性和弱点。以上述方式标记帧而不真正深入 Beamer 需要一点技巧,即一个新的环境。为此,sebframe已定义了一个环境,它接受具有以下语法的可选参数

<tag>-<list of beamer options>

字符-用于将标签与其他 Beamer 选项分开;顺便说一句,这与 不符fragile

mwe。它被评论并作为概念证明:正如评论所指出的那样,有几件事可以改进。

\documentclass{beamer}
\usepackage{lmodern} % https://tex.stackexchange.com/a/58088/13304
\usepackage{mwe} % for dummy image

\newcommand{\enlarge}{\centering\scalebox{13}}% Just for this example

% = = = = = = = = = = = = = = = = = = = = = = = =
% core of the solution

\usepackage{pgffor,pgfkeys,xstring}

\newcommand{\deflistframes}[1]{
\gdef\listframes{}% global list
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\foreach \x[count=\xi] in {#1}{
 \ifnum\xi=\maxitems
   \xdef\listframes{\listframes \vers\x}
 \else
   \xdef\listframes{\listframes \vers\x,}
 \fi
}
}

\newcommand{\defcustomlistframes}[1]{
\gdef\listframes{}% global list
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\foreach \x[count=\xi] in {#1}{
 \ifnum\xi=\maxitems
   \xdef\listframes{\listframes \x}
 \else
   \xdef\listframes{\listframes \x,}
 \fi
}
}

\makeatletter
% https://tex.stackexchange.com/a/74890/13304
\newcommand{\defversion}[1]{\@namedef{vers#1}{}}
\makeatother

% test for multiple versions compilation
\newif\ifmultipleversion
\multipleversionfalse


\pgfkeys{/seb-beamer/.cd,
  create new version/.code={\gdef\vers{#1}\newcounter{#1}},
  create multiple versions/.code={%
    \gdef\listofversions{}
    \foreach \v in {#1}{%
      \defversion{\v}
      \newcounter{\v}
      \xdef\listofversions{\listofversions \v,}
    }%
    \multipleversiontrue
  },
  compile version/.code={% version-based: need to store in .aux a
    % "total frame" counter per version (incremented in custom enviroment)
    % and use it as final value (hard-coded here for simplicity)
    \deflistframes{1,...,1000}
    % list of frames in output
    \expandafter\includeonlyframes\expandafter{\listframes}%
  }, 
  compile frames/.code={% this should be version-based -> second argument (TBA)
    \deflistframes{#1}
    % for the list
    \expandafter\includeonlyframes\expandafter{\listframes}%
  }, 
  compile generic frames/.code={% generic for multi version compilations
   \defcustomlistframes{#1}
   % list of frames in output
   \expandafter\includeonlyframes\expandafter{\listframes}%
  }, 
}

\makeatletter

% see: https://tex.stackexchange.com/a/132411/13304
\newenvironment{sebframe}[1][]{
% cut the string to separate version from other options
\StrCut{#1}{-}\compvers\opt
\edef\seboptions{\opt}
\def\mylabel{}
\ifmultipleversion
  \@ifundefined{c@\compvers}{}{% test if the counter is undefined
    \stepcounter{\compvers}
    % increment here the counter total frames per version
    \edef\mylabel{label=\compvers\the\value{\compvers}}
    }
\else
 \IfStrEq{\vers}{\compvers}{% true
  \stepcounter{\compvers}
  % increment here the counter total frames per version
  \edef\mylabel{label=\compvers\the\value{\compvers}}
 }{% false
  \edef\mylabel{}
 }
\fi
\begingroup\edef\x{\endgroup\noexpand\begin{frame}[\mylabel,\seboptions]}\x}{\end{frame}}

\makeatother

\newcommand{\SebCompileOptions}[1]{%
 \pgfkeys{/seb-beamer/.cd,#1}
}

% = = = = = = = = = = = = = = = = = = = = = = = =
% user interface

%\SebCompileOptions{create new version=A, compile version=A}
%\SebCompileOptions{%
% create multiple versions={A,B}, 
% compile generic frames={A1,A3,B1,B2,C3}
%}
\SebCompileOptions{create new version=C, compile frames={1,3}}


\begin{document}

\begin{sebframe}[A-t,allowframebreaks]
  \frametitle{Version A}
  \enlarge{A1}
\end{sebframe}

\begin{sebframe}[B]
  \frametitle{Version B}
  \enlarge{B1}
\end{sebframe}

\begin{sebframe}[C]
  \frametitle{Version C}
  \enlarge{C1}
\end{sebframe}

\begin{sebframe}[A]
  \frametitle{Version A}
  \enlarge{A2}
\end{sebframe}

\begin{sebframe}[B]
  \frametitle{Version B}
  \enlarge{B2}
\end{sebframe}

\begin{sebframe}[C]
  \frametitle{Version C}
  \enlarge{C2}
\end{sebframe}

\begin{frame}
  \frametitle{Version B or C}
  \enlarge{BC}
\end{frame}

\begin{sebframe}[A-t,b,containsverbatim]% just to point out that passing multiple beamer options works (unless fragile)
  \frametitle{Version A}
  \enlarge{A3}
\end{sebframe}

\begin{sebframe}[C]
  \frametitle{Version C}
  \enlarge{C3}
  \vskip1ex
  \includegraphics<2>[scale=0.5]{example-image}
\end{sebframe}

\begin{sebframe}[A]
  \frametitle{Version A}
  \enlarge{A4}
\end{sebframe}

\begin{frame}[fragile,label=A5]% add manually a label: displayed only in A version though
  \frametitle{Version A \& B \& C}
  \enlarge{ABC}
\end{frame}


\end{document}

正如我们所选择的:

\SebCompileOptions{create new version=A, compile version=A}

输出为:

在此处输入图片描述

通过选择

\SebCompileOptions{create new version=C, compile frames={1,3}}

在此处输入图片描述

请注意,overleyed-aware 命令仍然有效,并且不显示帧 C2。让我们尝试

\SebCompileOptions{%
 create multiple versions={A,B}, 
 compile generic frames={A1,A3,B1,B2,C3}
}

生成结果:

在此处输入图片描述

正如预期的那样,由于未定义版本 C,因此不显示框架 C3。提供列表的顺序不会影响 PDF 中的显示顺序:只有页码才算数。

答案2

我会创建一组条件,每个条件对应于您想要给出的每种演示类型。我们将这些类型称为“版本”。因此,也许有VersionAVersionBVersionC

对于每个版本,创建一个条件使用\newif(默认情况下设置为 false):

\newif\VersionA
\newif\VersionB
\newif\VersionC

然后,将与特定版本关联的幻灯片包装起来frame。例如,VersionA幻灯片将类似于

\ifVersionA
\begin{frame}
  ...
\end{frame}
\fi

如果你有一张应该与VersionBOR关联的幻灯片VersionC,那么你可以这样做

\makeatletter
\let\ifCombined\ifVersionB
\ifVersionC
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi
  {\let\ifCombined\iftrue}{}
\makeatother

\ifCombined% Version B or C
\begin{frame}
  ..
\end{frame}
\fi

所有版本中可见的幻灯片不需要任何条件包装。以下是设置的简单示例:

在此处输入图片描述

\documentclass{beamer}% http://ctan.org/pkg/beamer
\let\Tiny=\tiny% http://tex.stackexchange.com/q/58087/5764
\newcommand{\enlarge}{\centering\scalebox{13}}% Just for this example

\newif\ifVersionA
\newif\ifVersionB
\newif\ifVersionC


%\VersionAtrue% Show Version A
\VersionBtrue% Show Version B
%\VersionCtrue% Show Version C

\begin{document}

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A1}
\end{frame}
\fi

\ifVersionB
\begin{frame}
  \frametitle{Version B}
  \enlarge{B1}
\end{frame}
\fi

\ifVersionC
\begin{frame}
  \frametitle{Version C}
  \enlarge{C1}
\end{frame}
\fi

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A2}
\end{frame}
\fi

\ifVersionB
\begin{frame}
  \frametitle{Version B}
  \enlarge{B2}
\end{frame}
\fi

\makeatletter
\let\ifCombined\ifVersionB
\ifVersionC
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi
  {\let\ifCombined\iftrue}{}
\makeatother

\ifCombined% Version B or C
\begin{frame}
  \frametitle{Version B or C}
  \enlarge{BC}
\end{frame}
\fi

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A3}
\end{frame}
\fi

\ifVersionC
\begin{frame}
  \frametitle{Version C}
  \enlarge{C3}
\end{frame}
\fi

\ifVersionA
\begin{frame}
  \frametitle{Version A}
  \enlarge{A4}
\end{frame}
\fi

\begin{frame}
  \frametitle{Version A \& B \& C}
  \enlarge{ABC}
\end{frame}

\end{document}

您可以使用comment包裹。但是,合并条件并不那么容易。当然,一种解决方法是复制包含多个版本信息的幻灯片。

另一个可行的选择是label为每个frame使用创建一个

\begin{frame}[label=ConceptX]
  ...
\end{frame}

或使用\frame命令。然后添加ConceptX您感兴趣的版本,包括使用

\includeonlyframes{...,ConceptX,...}% Version A

但这要求您为每个提供frame一个概念(唯一)标签。

相关内容