我正在使用 beamer 包创建演示文稿。此外,我还想制作一份包含更多信息的讲义(因为演示文稿幻灯片不应包含太多文本)。为此,我使用文章模式。
为了让我的听众在讲义上做笔记,在讲义上标注帧编号会很有帮助。我使用以下代码实现了这一点:
\mode<article>{
\renewcommand{\frametitle}[1]{\subsubsection*{#1 [Slide \insertframenumber]}}
}
除非您使用以下方式插入节起始帧,否则此方法非常有效
\AtBeginSection[] % nothing for \section*{}
{
\begin{frame}
\begin{center}
\structure{\Huge \insertsection}
\end{center}
\end{frame}
}
问题是,\AtBeginSection
在文章模式下,该功能不起作用。附加帧未插入,因此帧编号错误。
因此我做了以下操作来解决这个问题:
\mode<article>{ % repair frame numbers in article mode as there are no section start frames
\newcommand*\oldsectionmacro{}%
\let\oldsectionmacro\section%
\renewcommand*\section{%
\addtocounter{framenumber}{1}\oldsectionmacro}%
}
除非有,否则此方法有效\section*
。在这种情况下,帧号会增加,但不应该增加,因为没有节起始帧。我可以避免使用,\section*
但也有一些隐含的(目录、参考书目等)。
目前我手动更正了这个问题(见下文),目前它能正常工作,但我不喜欢它。有没有更好的方法?我可以重写\section*
或使用\AtBeginSection
文章模式或以不同的方式插入帧编号吗?
这是一个可以尝试的小例子:
\documentclass[a4paper]{scrartcl} % problem doesn't change if I use article instead
\usepackage{beamerarticle}
%\documentclass{beamer}
\usepackage[utf8]{inputenc}
\setbeamertemplate{footline}[frame number]
\mode<article>{
% frame number in frametitle
\renewcommand{\frametitle}[1]{\subsubsection*{#1 [Slide \insertframenumber]}}
}
% section start frame
% this has no effect in article mode
\AtBeginSection[] % nothing for \section*{}
{
\begin{frame}
\begin{center}
\structure{\Huge \insertsection}
\end{center}
\end{frame}
}
\mode<article>{ % repair frame numbers in article mode as there are no section start frames
\newcommand*\oldsectionmacro{}%
\let\oldsectionmacro\section%
\renewcommand*\section{%
\addtocounter{framenumber}{1}\oldsectionmacro}%
%
% \newcommand*\oldtocmacro{}%
% \let\oldtocmacro\tableofcontents%
% \renewcommand*\tableofcontents{%
% \addtocounter{framenumber}{-1}\oldtocmacro}
}
\begin{document}
\begin{frame}
\tableofcontents
\end{frame}
\section{Section 1}
\begin{frame}
\frametitle{Frame A}
Frame A
\end{frame}
\section{Section 2}
%\section*{Section Star}
\begin{frame}
\frametitle{Frame B}
Frame B
\end{frame}
\end{document}
答案1
我认为,这里最简洁的方法是使它\AtBeginSection
在 中工作beamerarticle
。之所以不行,是因为\AtBeginSection
宏通过定义在这些部分开头执行的钩子来工作。然而,在文章模式下,\section
使用文档类定义的宏,因此这些钩子永远不会执行。
为了克服这个问题,需要重新定义\section
宏。这有点复杂,因为它\@startsection
在内部调用,所以简单地将钩子添加到宏的末尾是行不通的。相反,需要一个围绕原始命令的完整“包装器”:
\mode<article>
\usepackage{xparse}
\makeatletter
\expandafter\let\expandafter\originalsection\expandafter=\csname @orig\string\section\endcsname
\RenewDocumentCommand{\section}{ D<>{} s o m }
{
\alt<#1>
{
\IfBooleanTF {#2}
{
\originalsection*{#4}
%\beamer@atbeginsections % breaks because section* is also used e.g. in the TOC
}
{
\IfNoValueTF {#3} { \originalsection{#4} } { \originalsection[#3]{#4} }
\beamer@atbeginsection
}
}
{
\beamer@secgobble
}
}
\makeatother
\mode<all>
将此代码插入到文档的前言中,后加载后beamerarticle
。它所做的是将存储在宏中的宏beamer
的原始、无含义的宏保存为具有“奇怪”名称的宏。之后,重新定义为执行原始的分段命令和随后的钩子。由于有带星号和不带星号的版本、可选参数和(可选)覆盖规范,我使用了\section
@orig\section
\originalsection
\section
\beamer@atbeginsection
\section
xparse
这使得您可以以非常方便的方式定义此类宏。
现在您可以\AtBeginSection
像往常一样使用 来插入章节开始帧。由于您可能不希望它们在文章模式中实际显示,\begin{frame}<article:0>
因此您应该使用 (帧号仍然递增)。此外,您需要这样做,\def\insertsection{}
因为此命令是未知的beamerarticle
,否则会导致错误。
请注意,使用可选参数来\AtBeginSection
定义带星号部分的钩子不起作用(上面的代码中注释掉了执行该操作的行)。原因是该操作\section*
也用于目录等,在这些地方插入该操作会导致错误消息。
使用上述代码输出 MWE
在演示模式下(单击图像可查看完整尺寸):
在文章模式下:
为了完整起见,可以找到产生上述结果的完整来源在 pastebin.com 上。
编辑:这xparse
我以前重新定义的包\section
依赖于实验性的 LaTeX3 内核。如果没有,你可以使用这个简单的 LaTeX2e 解决方案:
\mode<article>
\makeatletter
\expandafter\let\expandafter\originalsection\expandafter=\csname @orig\string\section\endcsname
\def\sectionwithhook{\@ifstar\@sectionwithhook\@@sectionwithhook}
\newcommand{\@sectionwithhook}[1]{\originalsection*{#1}}
\newcommand{\@@sectionwithhook}[2][]{\beamer@ifempty{#1}{\originalsection{#2}}{\originalsection[#1]{#2}}\beamer@atbeginsection}
\renewcommand<>{\section}{\alt#1{\sectionwithhook}{\beamer@secgobble}}
\makeatother
\mode<all>
\RenewDocumentCommand
这将替换上面给出的整个代码,实现与一些辅助宏相同的功能。