我正在尝试在 Beamer 主题中实现进度条,但当我达到 45 帧时,我收到错误消息
! Arithmetic overflow.
\progressbar@progressbar ...progressbar@tmpcounta
\divide \progressbar@tmpdi...
这是我的 MWE:
\documentclass{beamer}
\usepackage{tikz}
\makeatletter
\def\progressbar@progressbar{} % the progress bar
\newcount\progressbar@tmpcounta% auxiliary counter
\newcount\progressbar@tmpcountb% auxiliary counter
\newdimen\progressbar@pbht %progressbar height
\newdimen\progressbar@pbwd %progressbar width
\newdimen\progressbar@tmpdim % auxiliary dimension
\progressbar@pbwd=\paperwidth
\progressbar@pbht=1cm
% the progress bar
\def\progressbar@progressbar{%
\progressbar@tmpcounta=\insertframenumber
\progressbar@tmpcountb=\inserttotalframenumber
\progressbar@tmpdim=\progressbar@pbwd
\multiply\progressbar@tmpdim by \progressbar@tmpcounta
\divide\progressbar@tmpdim by \progressbar@tmpcountb
\begin{tikzpicture}
\useasboundingbox (0pt, 0pt) rectangle ++ (\progressbar@pbwd, \progressbar@pbht);
\begin{scope}
\clip (\progressbar@tmpdim, 0pt) rectangle (\progressbar@pbwd, \progressbar@pbht);
\node[anchor=south west,inner sep=0pt,outer sep=0pt,minimum height=1cm,minimum width=\paperwidth,fill=green] at (0pt,0pt) {};
\end{scope}
\end{tikzpicture}%
}
\addtobeamertemplate{footline}{}{\vspace*{-1cm}\progressbar@progressbar}
\makeatother
\begin{document}
\foreach \x in {1,2,...,45} {\begin{frame}[label=test]{My frame}
Test \x
\end{frame}}
\end{document}
背后的原因是什么?我该如何避免?
答案1
TeX 有一个\maxdimen
( 16383.99999pt
),它表示维度表达式中可以使用的最大维度。请参阅\maxdimen
此网站上的讨论,包括我的答案。
什么时候\x == 45
,
\progressbar@tmpdim == 364.19536pt
和\progressbar@tmpcounta == 45
,- 它们的乘积
364.19536pt * 45 = 16,388.7912pt
略大于\maxdimen
,因此引发“算术溢出”,乘法结果被截断。
由于最终结果@tmpdim * @tmpcounta / @tmpcountb
小于\maxdimen
,我们可以先计算@tmpcounta / @tmpcountb
,然后计算@tmpdim * <ratio>
。下面是使用\pgfmathparse
from 的尝试pgfmath
,它是 的自动加载子包tikz
:
\documentclass{beamer}
\usepackage{tikz}
\makeatletter
\def\progressbar@progressbar{} % the progress bar
\newcount\progressbar@tmpcounta% auxiliary counter
\newcount\progressbar@tmpcountb% auxiliary counter
\newdimen\progressbar@pbht %progressbar height
\newdimen\progressbar@pbwd %progressbar width
\newdimen\progressbar@tmpdim % auxiliary dimension
\progressbar@pbwd=\paperwidth
\progressbar@pbht=1cm
% the progress bar
\def\progressbar@progressbar{%
\progressbar@tmpcounta=\insertframenumber
\progressbar@tmpcountb=\inserttotalframenumber
\progressbar@tmpdim=\progressbar@pbwd
% to show current values
\rlap{\the\progressbar@tmpdim, \the\progressbar@tmpcounta}%
\pgfmathparse{\progressbar@tmpcounta/\progressbar@tmpcountb}%
\progressbar@tmpdim=\pgfmathresult\progressbar@tmpdim
\begin{tikzpicture}
\useasboundingbox (0pt, 0pt) rectangle ++ (\progressbar@pbwd, \progressbar@pbht);
\begin{scope}
\clip (\progressbar@tmpdim, 0pt) rectangle (\progressbar@pbwd, \progressbar@pbht);
\node[anchor=south west,inner sep=0pt,outer sep=0pt,minimum height=1cm,minimum width=\paperwidth,fill=green] at (0pt,0pt) {};
\end{scope}
\end{tikzpicture}%
}
\addtobeamertemplate{footline}{}{\vspace*{-1cm}\progressbar@progressbar}
\makeatother
\begin{document}
\foreach \x in {1,2,...,45} {\begin{frame}[label=test]{My frame}
Test \x
\end{frame}}
\end{document}
更新
抱歉,昨天太关注“算术溢出”的错误信息了,没注意到绘制进度条的全貌。灵感来自@TobiBS 的回答,我发现实现可以进一步简化为
\documentclass{beamer}
\usepackage{tikz}
\makeatletter
\newdimen\progressbar@height
\progressbar@height=1cm
\addtobeamertemplate{footline}{}{%
\begin{tikzpicture}
\useasboundingbox (0pt, 0pt) rectangle (\paperwidth, \progressbar@height);
% you can use pgfmath expressions directly in coordinate specifications
\fill[green] (\insertframenumber/\inserttotalframenumber*\paperwidth, 0)
rectangle (\paperwidth, \progressbar@height);
\end{tikzpicture}%
}
\makeatother
\begin{document}
\foreach \x in {1,2,...,50} {
\begin{frame}{My frame}
Test \x
\end{frame}
}
\end{document}
答案2
我现在使用的更简化的方法可能更容易阅读,但当然不像以前那么灵活,但它利用了这样一个事实:对于 PGF,您不需要将宏转换为计数器,因此这可以生成高度可变且倒置的进度条。它还考虑了 muzimuzhi 关于使用的评论\pgfmathsetmacro
:
\documentclass{beamer}
\usepackage{tikz}
\makeatletter
\newdimen\progressbar@height
\newcount\progressbar@progress
\progressbar@height=1cm
\addtobeamertemplate{footline}{}{%
\begin{tikzpicture}
\useasboundingbox (0pt, 0pt) rectangle ++ (\paperwidth, \progressbar@height);
\begin{scope}
\pgfmathsetmacro\progressbar@progress{\insertframenumber/\inserttotalframenumber}
\clip (\progressbar@progress * \paperwidth, 0pt) rectangle (\paperwidth, \progressbar@height);
\node[anchor=south west,inner sep=0pt,outer sep=0pt,minimum height=1cm,minimum width=\paperwidth,fill=green] at (0pt,0pt) {};
\end{scope}
\end{tikzpicture}%
}
\makeatother
\begin{document}
\foreach \x in {1,2,...,50} {\begin{frame}{My frame}
Test \x
\end{frame}}
\end{document}