LaTeX教程(014)- LaTeX \LaTeX LATEX文档结构(14)
2.3.3 multitoc
- 将目录设置为多栏
multitoc
包的使用方法相当简单,只需要调用这个包,并将要设置为多栏(默认是双栏)的目录指定到包选项中即可。如\usepackage[toc]{multitoc}
,设置的就是目录列表,除此之外还可以指定lof
和lot
(图形列表和表格列表)。我们用一个例子演示一下:
\documentclass{article}
\usepackage{geometry}
\usepackage[toc]{multitoc} %将目录设置为双栏
\begin{document}
\tableofcontents
\section{section one}
\subsection{subsection one}
\section{section two}
\subsection{subsection two}
\subsection{subsection three}
\subsection{subsection four}
\end{document}
编译(只截取目录):
很用有使用超过双栏的时候,但是在必要的时候,你可以重定义\multicolumntoc
、\multicolumnlof
或者\multicolumnlot
,将它们重定义为你想要的数字(栏数)。如上面的例子中放置一行\renewcommand{\multicolumntoc}{3}
,可将目录设置为3栏:
2.3.4 LaTeX \LaTeX LATEX的底层接口
我们前面讲了如何通过一些包定制目录,在这一节的最后一个小节中,我们介绍一下
LaTeX
\LaTeX
LATEX为目录提供的底层接口,其中有一些命令是我们之前用过的。实际上titletoc
包也在底层调用了这些接口。
将信息写入目录文件
有两个命令用来将数据写入目录文件: \addcontentsline
和\addtocontents
。它们自动被标题命令和图表的标签命令调用,当然,如果有必要的话,我们是可以直接手动调用它们的。
\addcontentsline{ext}{type}{text}
\addcontentsline
命令将text
参数中的内容,连同一些附带的信息,比如当前的页码等,一起放入后缀为ext
的文件中(这里是指ext
参数中填的内容,通常是lof
,toc
或者lot
,分别对应我们已经熟悉的三种列表文件)。最好用\protect
将text
内容保护起来。type
参数中填写当前条目的类型,对于.toc
文件来说,通常就是标题的类型,如chapter
,section
等(不带反斜线),对于.lof
和.lot
文件来说,通常分别是figure
或者table
。
\allcontentsline
命令会在使用章节划分命令(如\chapter
,\section
等),或者浮动体环境中的\caption
命令时自动调用。然而,该命令没有为条目的编号单独分配一个参数,而是关于标题的一切文本内容,只留了一个text
参数,那么我们如何通过该命令让
LaTeX
\LaTeX
LATEX知道当前条目有没有编号,以及编号是什么呢?我们可以在text
参数中使用\numberline
命令:
\protect\numberline{number}heading
heading就是我们的标题文本,number
是我们要填的标题编号。例如,在一个插图环境(figure
)中使用\caption
命令,
LaTeX
\LaTeX
LATEX就会调用命令:
\addcontentsline{lof}{figure}{\protect\numberline{\thefigure}caption text}
\numberline
会直接被写入文件中,而\thefigure
会被替换成一个编号(当前图片的编号),被写入lof
文件中。
在排版目录列表期间,一个合适的\numberline
的定义会被用来以一种特定的方式排版条目的编号,如插入一段额外的距离,或者变一种不同的字体等。不足之处是,这种方式不具有更好的通用性,它没有为编号单独划分一个参数,你不能轻易地对编号进行任意的改变,并且它需要一个好的\numberline
定义,这并不是那么容易提供的。
\addtocontents{ext}{test}
\addtocontents
命令没有type
参数,它被用来插入特殊格式的条目,和任何其他的目录行都不直接相关。例如,标准类的\chapter
命令会调用以下命令:
\addtocontents{lof}{\protect\addvspace{10pt}}
\addtocontents{lot}{\protect\addvspace{10pt}}
在.lof
和.lot
文件中额外放置一段空白,来将不同章的图表条目分开。使用\addvspace
(只能在垂直模式下使用)在不同的章之间至多插入10pt的距离,如果一章中没有图表,也不会产生奇怪的缺口。这是\addvspace
的特殊之处,如果某处插入多个\addvspace
命令,那么只有参数最大的会生效。例如
abc...
\addvspace{10pt} %
\addvspace{20pt}
\addvspace{10pt}
def...
只会在abc…和def…之间插入一段20pt的垂直距离。然而,\addcontentsline
、\addtocontents
和\addvspace
在作为用户层命令使用时,很容易出现奇怪的错误,尤其是\addvspace
,它只能在垂直模式下使用,这就意味着,\addcontentsline
设置的条目必须以垂直模式结束。因此你需要了解这样的条目是如何被处理的,以至于能够在其中进行任意的格式化操作。而这正是下一节的任务。
如果文档使用了\include
声明,那么\addcontentsline
和\addtocontents
命令的使用就有一个局限,它们都不能和\include
命令在同一层级下使用。例如:
\addtocontents{toc}{\protect\setcounter{tocdepth}{1}}
\include{sect1}
其中sect1.tex
文件中含有\section
命令,这样就会得到一个意料之外的结果,.toc
文件中会有以下内容:
\contentsline {section}{\numberline {1}Section from sect1}{2}{}%
\setcounter{tocdepth}{1}
可以看到这两行命令的顺序颠倒了,\section
条目本应在\setcounter{tocdepth}{1}
命令的后面,现在跑到前面去了。解决方法就是避免使用\include
,或者把\addtocontents
或\addcontentsline
命令放在\include
所包含的文件里面。
排版一个目录列表
在上一篇中,我们做了一个演示,我们手动创建了一个.toc
文件,并且还手动修改过里面的内容,然后使用\input
命令将.toc
文件插入到了文档中。我们知道,对于文档中的条目,真正起作用的是.toc
、.lof
或.lof
文件中的那些内容。
而从上面的内容中,我们又知道了,目录条目的产生都缘于\addcontentsline
和\addtocontents
命令或隐示或显示的调用,那么在这两个命令被执行之后,接下来发生了什么?它们是如何对.toc
、.lof
或.lof
文件产生影响的?
实际上, LaTeX \LaTeX LATEX执行命令
\addcontentsline{ext}{type}{text}
时,就会在后缀名为ext
(这取决于我们在这个参数里填的是什么)的文件中放置一行(连同注释符%一起):
\contentsline{type}{text}{page}{anchor-name}%
其中page
是当前\addcontentsline
放置的位置在文档中的页码。anchor-name
默认是空的,除非加载了hyperref
包。这种情况下该参数内会被填入一个超链接的锚点名(anchor name)。
\addtocontents{ext}{text}
则更简单,它仅仅是将text
参数的内容复制到后缀名为ext
的文件中,不会写入其他更多的信息。因此,一个典型的目录列表文件包含一些\contentsline
命令,可能还包含一些由\addtocontents
命令写入的特殊格式的文本。我们做个演示:
\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\begin{document}
\tableofcontents
\section{section one}
\subsection{subsection one}
\stepcounter{subsection}
\addcontentsline{toc}{subsection}%
{\protect{\numberline{\thesubsection}}this is a test of add contentsline}
\section{section two}
\addtocontents{toc}{the is a test of addtocontents}
\end{document}
编译:
我们使用\addcontentsline
添加了一个subsection
的条目,并且将编号\thesubsection
也放置了进去,由于我们没有使用\subsection
命令,所以subsection
的计数器不会自动递增,我们要使用命令\stepcounter
使subsection
加1。
\addtocontents
命令没有type
参数,但是我们从格式上可以看出,添加的文本的默认层级等同于subsection
。
打开.toc
文件,可以看到以下内容:
\contentsline {section}{\numberline {1}section one}{1}{}%
\contentsline {subsection}{\numberline {1.1}subsection one}{1}{}%
\contentsline {subsection}{{\hbox to\@tempdima {1.2\hfil }}this is a test of add contentsline}{1}{}%
\contentsline {section}{\numberline {2}section two}{1}{}%
the is a test of addtocontents
当然,既然最终起作用的命令是\contentsline
,那么我们也可以在文档中直接使用\contentsline
命令来创建一个目录。
下面展示一个典型的例子。注意大多数(并非全部)标题编号都是作为\numberline
的参数输入的,以便能有统一的、合适的缩进。出于历史的原因,
LaTeX
\LaTeX
LATEX在这一点上并不一致,标准类的\part
命令的编号并没有使用\nunmberline
命令,而是直接为其指定了一种特殊的格式。
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\setcounter{tocdepth}{3}
\begin{document}
\tableofcontents
\contentsline {part}{I\hspace{1em}Part}{2}{}%
\contentsline{chapter}{\numberline{1}A-Head}{2}{}%
\contentsline{section}{\numberline{1.1}B-Head}{3}{}%
\contentsline{subsection}%
{\numberline{1.1.1}C-Head}{4}{}%
\contentsline{subsection}%
{\numberline{}With Empty Number}{5}{}%
\contentsline{subsection}{Unnumbered C-Head}{6}{}%
\contentsline{subsection}%
{\numberline{1.1.2}Another C-Head}{8}{}%
\contentsline{section}%
{\numberline{1.2}Another B-Head}{10}{}%
\end{document}
编译:
\contentsline
命令执行后,又会根据type
参数的不同,调用\l@type
命令。每一种\l@type
命令都有一个定义,例如,在report
类中你可以看到以下定义:
\newcommand\l@section {\@dottedtocline{1}{1.5em}{2.3em}}
\newcommand\l@subsection {\@dottedtocline{2}{3.8em}{3.2em}}
\newcommand\l@subsubsection{\@dottedtocline{3}{7.0em}{4.1em}}
\newcommand\l@paragraph {\@dottedtocline{4}{10em}{5em}}
\newcommand\l@subparagraph {\@dottedtocline{5}{12em}{6em}}
\newcommand\l@figure {\@dottedtocline{1}{1.5em}{2.3em}}
\newcommand\l@table {\l@figure}
根据定义,\l@type
实际上是被指定了3个参数的命令\@dottedtocline
(它实际上有5个参数),被指定了的参数分别是level
-条目层级、indent
-缩进和numwidth
-编号宽度,剩下两个保留参数分别是text
和page
,它会自动从\contentsline
命令中接收到。我们知道其实还有一个anchor-name
参数,这个参数大多数时候是空的,而如果指定了hyperref
包,这些定义就会改变,同时最后一个参数也会被接收到。
注意,有一些标题以一种更复杂的方式建立它们的目录条目,这就使得标准类中的\l@part
和\l@chapter
(包括article
类中的\l@section
)并不是使用\@dottedtocline
定义的。通常它们用一些特殊的格式命令,可能会省略引导线或者用更大的字体排版等。
所以要定义这些条目列表的布局,就必须声明合适的\l@type
命令(这些正是titletoc
包的\dottedcontents
和\titlecontents
所做的事)。下面我们展示一种不通过宏包来使用\@dottedtocline
的简单方法。这个命令的形式如下:
\@dottedtocline{level}{indent}{numwidth}{text}{page}
最后两个命令和\contentsline
的第二和第三个命令保持一致,\@dottedtocline
通常会被\contentsline
所调用。其他的命令如下:
level
: 条目的层级。indent
: 从左边距开始的缩进。numwidth
: 用来放置条目编号的盒子的宽度(如果使用了\numberline
的话),对于多行的标题文本,这些缩进对所有行都有效。
另外,还使用了以下这些全局格式参数,它们对所有出现的条目生效。这些参数都是长度数值。要改变它们,必须使用\renewcommand
重定义。
\@pnumwidth
: 放置页码的盒子的宽度\@tocrmarg
: 条目文本的右侧缩进,对于多行文本来说,它是除最后一行的所有行的缩进。可以是一个弹性长度。\@dotsep
: (引导线中)两个点之间的间隔,单位是mu
(18mu-1em),这里填入一个数字(如1.7,或2),单位不用写。你可以通过将数字设置的足够大来让这些点显示不出来。
我们用一张图表示这些参数的作用位置:
numwidth
参数中的编号靠左对齐(如果有编号的话)。我们可以通过改变indent
和numwidth
的设置来为嵌套的条目实现合适的缩进。
有时候对它们进行调整是必须的,如果你使用的是标谁类,比如article
,而文档的篇幅又很长,那么就可能会出现11.12
这样的编号(第11节第12小节),此时原本的放置编号的空间可能就不太够用了,编号和文本会离得很近,甚至重叠。我们作个演示:
\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\setcounter{tocdepth}{3}
\begin{document}
\contentsline{section}{\numberline{11}A-Head}{3}{}%
\contentsline{subsection}{\numberline{11.1}B-Head}{3}{}%
\ldots %
\contentsline{subsection}{\numberline{11.12}B-Head}{7}{}%
\end{document}
编译:
这种情况下,可以重定义\@subsection
为编号保留更多的空间(调整\@dottedtocline
的第三个参数),我们作个演示:
\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\setcounter{tocdepth}{3}
\makeatletter
\renewcommand\l@subsection{\@dottedtocline{2}{1.5em}{3em}}
\makeatother
\begin{document}
\contentsline{section}{\numberline{11}A-Head}{3}{}%
\contentsline{subsection}{\numberline{11.1}B-Head}{3}{}%
\ldots %
\contentsline{subsection}{\numberline{11.12}B-Head}{7}{}%
\end{document}
编译:
这里要注意,
LaTeX
\LaTeX
LATEX的内部命令(就是带@符号的命令)在文档中使用时要用\makeatletter
和\makeatother
将其包含其中。其他类似的命令的重定义方式也和\@subsection
一样,我们不再一一演示。
少数时候我们可能需要扩展放置页码的盒子的宽度,例如,如果页码是根据part
设置的,如"A-78"、"B-328"等,那么默认的空间可能就不够了,然后弹出一个Overfull hbox
的警告(盒子溢出)。一种解决方法就是重定义\@pnumwidth
的值,使其至少能够放置最宽的页码:
\makeatletter
\renewcommand\@pnumwidth{2cm}
\makeatother
\@pnumwidth
一经调整,通常\@tocrmarg
也要跟着调整,以保证其布局的一致性。
这些例子能让我们看出titletoc
提供的高级接口的优势,使用像\contentspush
这样的命令显然是一种更简单的解决方法。
添加其他的目录文件
有些时候你可能会想要标记一些其他的数据,并将其做成列表。这样你就需要创建一个新的目录文件。
例如,假设你想要在一个article
中收集所有对艺术家的注释,那么你需要定义两个命令。第一个是\artist
,用来排版艺术家的姓名,并且将这两个参数联结起来,同时将当前命令在文档中所处的位置写为当前的页码记录到文件中。第二个是\listofartistnotes
,用来读取文件中的内容,并且将这些内容布局在文档中插入该文件的地方。
要实现这一点,\listofartistnotes
命令要调用\@starttoc{ext}
,它会读取后缀为ext
的文件(这里指我们在ext
处填的参数),这个命令也会被\tableofcontents
,\listoffigures
和\listoftables
调用。这个文件的后缀是自定义的,可以是任意没有用过的字符串,如.rec
。我们可以单独创建一章,如\chapter*{Notes on artists}
,用来放置这个列表(只需要将命令\listofartistnotes
放置在这一章中),如果想要的话,也可以使用\addcontentsline
将这一章的标题放置在目录文件中(.toc
)。
而真正控制.rec
文件中的条目排版的命令是\l@note
,这是一个需要我们定义的命令。在下面的例子中,这些注释都分别作为一个段落排版,并且后面紧跟着一个斜体的页码。如果不想直接定义页码的样式命令,也可以使用titletoc's
接口,如\titlecontents{note}...
。
\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\newcommand\artist[2]{#1\addcontentsline{rec}{note}{#1: #2}}
\makeatletter
\newcommand\listofartistnotes%
{\section*{Notes on artists}\@starttoc{rec}}%
\newcommand\l@note[2]{\par\noindent#1,~\textit{#2}\par}
\makeatother
\begin{document}
The version of Ravel's Boléro by \artist{Jacques Loussier Trio}{A strange experience} is rather unusual. Quite interesting is Davis' Blue in Green
by \artist{Cassandra Wilson}{A wonderful version}.
\listofartistnotes
\end{document}
编译:
关注【年轻人 你渴望力量么】