框架和逐項一起列出

框架和逐項一起列出

我想重新定義frameframe + itemize.到目前為止我已經嘗試過這個 -

\documentclass{beamer}
\newenvironment{myframe}{\begin{frame}\begin{itemize}}{\end{itemize}\end{frame}}

\begin{document}
\begin{myframe}
\item
\end{myframe}
\end{document}

這到底有什麼問題,然後要如何正確地重新定義它?

答案1

環境使用以下技術收集其主體:它讀取並儲存以下標記,而不擴展它們beamer,除非在一種情況下(見下文),但只有當它看到與此收集過程中的(它不會嘗試匹配它們)。這就是in from的用途。frame\begin{frame}\end{frame}\end{frame}\begin{...}\end{...}\beamer@begin@stack\beamer@collect@@bodybeamerbaseframe.sty

如果堆疊為空(即,它已經看到了\end{...}\begin{...}after一樣多的值\begin{frame})並且後面的\end{...}不是 an \end{frame},它會擴展它\end,希望這會\end{frame}出現。1但是這個僅有的在我給出的條件下發生(\end{...}\begin{...}最初\begin{frame}必須被看到之後一樣多)。

在您的範例中,\begin{itemize}將一個b(即打開一層)推送到\beamer@begin@stack堆疊。讀取b時會彈出此資訊。\end{myframe}至此,\beamer@collect@@body知道它已經看到\begin{...}那麼\end{...}多了\begin{frame}。這是事實,但具有誤導性,因為如果\end{myframe}擴展,它將產生兩個彈出視窗。因此,\beamer@begin@stack認為下一個\end{...}必須提供\end{frame},可能是在擴展\end...令牌之後(參見註腳 1)。唉,這是不正確的。接下來\end{...}\end{document}.\enddocument因此展開,然後\beamer@collect@@body繼續查找,\end{frame}但當然找不到它,到達文件末尾,這會觸發錯誤:

Runaway argument?
\let \AtEndDocument \@firstofone \@enddocumenthook \@checkend {docume\ETC.
! File ended while scanning use of \beamer@collect@@body.
<inserted text> 
                \par 

所以,基本上,問題是\beamer@collect@@body無法保持正確的計數,\end{...}因為您\end{myframe}隱藏了其中兩個 ( \end{itemize}\end{frame}) 並且\beamer@collect@@body不會通過擴展發現它們,\endmyframe儘管存在\end{myframe},因為它看到的比它看到的點\begin{...}要(由於的原因,非空堆疊)。\end{...}\end{myframe}\begin{itemize}

此解決方案要求您不要隱藏在不會擴展的\end{...}巨集中。\beamer@collect@@body一種是使用environ包,如下所示費拉菲扎的回答,另一個是使用\itemizeand\enditemize如下(它們都不影響\beamer@begin@stack堆疊,因此當\beamer@collect@@bodysee時\end{myframe},堆疊為空,因此\endmyframe擴展一次,這使得\end{frame}環境主體掃描過程可見):

\documentclass{beamer}

\newenvironment*{myframe}[1]
  {\begin{frame}{#1}%
   \begingroup\itemize}
  {\enditemize\endgroup
   \end{frame}}

\begin{document}

\begin{myframe}{Frame title}
\item An item
\item Another item
\end{myframe}

\end{document}

螢幕截圖


註腳

  1. 更準確地說,發生的情況如下(中beamer 2018/12/02 v3.55)。如果:

    • 堆疊\beamer@begin@stack為空(與正在收集其主體後所看到的\end{...}一樣多)並且\begin{...}\begin{frame}
    • 下一個\end{...}不是一個\end{frame}——假設它是一個\end{foobar}

    然後用收集到的材料中\beamer@collect@@body的第一級擴展來代替。這類似於擴展會產生的結果,儘管後者會做更多的事情(請參閱第 272 頁):\endfoobar\endgroup\end{foobar}\end{foobar}source2e.pdf

    • \@currenvir檢查is的替換文字foobar(這在beamer frame我們正在討論的正文收集過程中會失敗,如\@currenviris frame);
    • 遵循先前的\@endparenv命令(用於在某些段落製作環境之後抑製文字開頭的段落縮進,除非所述文字前面有空行或\par);
    • 遵循上一個\ignorespacesafterend命令(用於使下一個命令\end{...}忽略可能跟隨它的空格)。

答案2

使用包environ

\documentclass{beamer}
\usepackage{environ}

\NewEnviron{myframe}[1][]{%
\begin{frame}{#1}
\begin{itemize}
\BODY
\end{itemize}
\end{frame}
}

\begin{document}
\begin{myframe}
\item First
\item Second
\end{myframe}
\end{document}

在此輸入影像描述

相關內容