11

Using the following code I could put the ToC lines in the center in beamer:

\begin{frame}
  \begin{center}
  \tableofcontents
  \end{center}
\end{frame}

But how to make these ToC lines left aligned and still in the center?

8

A small calculation could advance the margins sufficiently to obtain the centered & left-aligned \tableofcontents display.

enter image description here

\documentclass{beamer}% http://ctan.org/pkg/beamer
\newsavebox{\longestsec}% Box to save longest sectional heading
\begin{document}

\begin{frame}
  \frametitle{Table of contents}
  \begin{lrbox}{\longestsec}Last section in the presentation\end{lrbox}% Capture longest title
  \setlength{\leftskip}{\dimexpr.5\textwidth-.5\wd\longestsec\relax}% Advance left margin accordingly
  \tableofcontents
\end{frame}

\section{First section}
​\begin{frame}
  \frametitle{First slide}
  This is a slide.
\end{frame}

\section{Last section in the presentation}% Longest sectional title
\begin{frame}
  \frametitle{Another slide}
  This is another slide
\end{frame}
\end{document}

​The reason for this round-about way is because beamer collapses the spacing when putting \tableofcontents within a minipage or varwidth (from the varwidth package).


Here is an automated way of capturing the width of the longest section:

\documentclass{beamer}% http://ctan.org/pkg/beamer
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\makeatletter
\newlength{\secnamelength}
\newsavebox{\longestsec}% Box to save longest sectional heading
\patchcmd{\beamer@section}% <cmd>
  {\beamer@savemode}% <search>
  {\begin{lrbox}{\longestsec}#1\end{lrbox}%
   \ifdim\wd\longestsec>\secnamelength\relax\setlength{\secnamelength}{\wd\longestsec}\fi%
   \beamer@savemode}% <replace>
  {}{}% <success><failure>
\AtEndDocument{% http://tex.stackexchange.com/q/137495/5764
  \immediate\write\@auxout{\global\secnamelength=\the\secnamelength}%
}
\makeatother
\begin{document}

\begin{frame}
  \frametitle{Table of contents}
  \setlength{\leftskip}{\dimexpr.5\textwidth-.5\secnamelength\relax}% Advance left margin accordingly
  \tableofcontents
\end{frame}

\section{First section}
​\begin{frame}
  \frametitle{First slide}
  This is a slide.
\end{frame}

\section{Last section in the presentation}% Longest sectional title
\begin{frame}
  \frametitle{Another slide}
  This is another slide
\end{frame}
\end{document}

The above stores the length of the longest section in \secnamelength that is written to the .aux at the end of the document. A patch of \beamer@section (with the aid of etoolbox is necessary to grab the maximum length of a section name and drop it into the .aux \AtEndDocument so it can be retrieved in a successive run.

  • 1
    Great. But is it possible to automatically find out the longest sectional title? – Z.H. Dec 16 '11 at 12:07
  • Is this still a valid solution? Doesn't work in my texlive 2012 ... – BandGap Oct 11 '13 at 16:12
  • 1
    @Z.H.: A little late, but added the automation procedure. – Werner Oct 12 '13 at 18:05
  • @BandGap: Yes, and I've just added some automation. What is the problem you're experiencing with the above MWE? – Werner Oct 12 '13 at 18:06
  • It seems like the selection of a theme for beamer overwrites the placement of the ToC... If I comment the relevant line the ToC appears centered. – BandGap Oct 14 '13 at 11:35
2

By patching \beamer@sectionintoc command, I could use varwidth inside center environment to make ToC lines left aligned and in the center.

The only limitation of this solution is, ToC lines could not be wrapped.

\documentclass{beamer}    
\usepackage{varwidth}    
\usepackage{etoolbox}
\makeatletter
%\patchcmd{\beamer@sectionintoc}{\vskip1.5em}{\vskip0.5em}{}{}
\patchcmd{\beamer@sectionintoc}{%
  \hbox{\vbox{%
    \def\beamer@breakhere{\\}%
    \beamer@tocact{\ifnum\c@section=#1\beamer@toc@cs\else\beamer@toc@os\fi}{section in toc}}}%
}{%
  \hbox{%
    \def\beamer@breakhere{}%
    \beamer@tocact{\ifnum\c@section=#1\beamer@toc@cs\else\beamer@toc@os\fi}{section in toc}}%
}{}{}
\makeatother    
\setbeamertemplate{section in toc}[sections numbered]    
\begin{document}

\begin{frame}
\frametitle{Table of contents}
\begin{center}
\begin{varwidth}{\textwidth}
\tableofcontents[sectionstyle=show,subsectionstyle=hide] 
\end{varwidth}
\end{center}
\end{frame}

\section{First section}    
​\begin{frame}
\frametitle{First slide}
This is a slide.
\end{frame}

\section{Second section in the presentation}    
\begin{frame}
\frametitle{Another slide}
This is another slide.
\end{frame}

\section{Last section}    
\begin{frame}
\frametitle{Last slide}
This is the last slide.
\end{frame}

\end{document}

enter image description here

  • Apparently in my installed version this leads to squeezed sections, i.e. there is no vertical space between them. Any idea how to get the \vfills between the sections back? For some reason they are gone after using the patch. I have tried adding it back manually by inserting it into the second clause of the patch etc. but that apparently makes either the patch not applying (is there no warning?) or it does not work. – stefanct Sep 5 '16 at 9:48
  • Whatever it is... the alternative solution proposed by @Werner works fine. – stefanct Sep 8 '16 at 12:24
2

As shown in my comment, the automatism provided by Werner can be problematic if you have short names like \section[shortName]{longName} e.g. for beamer slide headlines. It always takes the first argument, which would then be the short name.

I implemented a quick solution now (with etoolbox and ifthen), which will take the second argument if provided:

\makeatletter
\newlength{\secnamelength}
\newsavebox{\longestsec}% Box to save longest sectional heading
\patchcmd{\beamer@section}% <cmd>
{\beamer@savemode}% <search>
{
\ifstrempty{#2}{%
    \begin{lrbox}{\longestsec}#1\end{lrbox}
    \ifthenelse{
        \wd\longestsec > \secnamelength
    }{
        \setlength{\secnamelength}{\wd\longestsec}
    }{}%else
}{
    \begin{lrbox}{\longestsec}#2\end{lrbox}
    \ifthenelse{
        \wd\longestsec > \secnamelength
    }{
        \setlength{\secnamelength}{\wd\longestsec}
    }{}%else
}
\beamer@savemode
}% <replace>
{}{}% <success><failure>
\AtEndDocument{% http://tex.stackexchange.com/q/137495/5764
    \immediate\write\@auxout{\global\secnamelength=\the\secnamelength}%
}
\makeatother

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.