我想我所处的配置会让很多人感到熟悉:在一个运行多年的项目中,我开发了一个非常大的 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,每个人都可以改进它(而且有很大的空间)。
它提供了一个简单的用户界面,目的是
- 为区分版本创建标签;
- 决定输出哪个版本。
第一个任务由钥匙提供
create new version
create multiple versions
名称非常清晰。要决定输出哪些帧,请利用:
compile version
compile frames
选择一个版本内的框架子集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
我会创建一组条件,每个条件对应于您想要给出的每种演示类型。我们将这些类型称为“版本”。因此,也许有VersionA
,VersionB
和VersionC
。
对于每个版本,创建一个条件使用\newif
(默认情况下设置为 false):
\newif\VersionA
\newif\VersionB
\newif\VersionC
然后,将与特定版本关联的幻灯片包装起来frame
。例如,VersionA
幻灯片将类似于
\ifVersionA
\begin{frame}
...
\end{frame}
\fi
如果你有一张应该与VersionB
OR关联的幻灯片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
一个概念(唯一)标签。