标题为 sec 的部分:\thepart 部分最后一页错误

标题为 sec 的部分:\thepart 部分最后一页错误

当使用该titlesec包定制部分标题时,计数器\thepart会以某种方式递增,然后才能将其值用于例如运行标题:

\documentclass[oneside]{book}
\usepackage{titlesec}

% If you do not issue the \titleformat command, everything is fine
\titleformat{\part}[display]
            {\bfseries\huge\filcenter}
            {\partname\ \thepart%
             % A working hack: set the mark here instead, expanding \thepart
             % (note the lack of \protect)
             %\markright{Part \thepart, page \protect\thepage} 
            }
            {20pt}
            {\Huge}
\titlespacing*{\part}{0pt}{*36}{*1}

\begin{document}
\part{Intro}
\pagestyle{myheadings}

% Remove this to see the hack work.
\markright{Part \protect\thepart, page \protect\thepage}

This page should have ``\textsl{Part \thepart, page \thepage}'' at the top.
\newpage
This page should have ``\textsl{Part \thepart, page \thepage}'' at the top.
\part{A Problem}                % This command does the incrementing
\end{document}

第 3 页(第一部分的最后一页)是问题所在:

第 3 页上的 \thepart 计数器错误的演示

不知何故,第二个\part{A Problem}是在计数器用于标题之前推进计数器。

问题到底是什么?建议的解决方法是什么?可以像所示的那样破解解决方案,\thepart在排版部分时保存计数器的值,但这不是一个令人满意的解决方案,因为我希望用户能够在自定义标题等中使用计数器。

手册titlesec指出,有些部分是独特的和非标准的,但在我看来这似乎是一个错误。

更新

针对@hugovdberg 的回答,我可以将问题追溯到以下定义titlesec.sty

\makeatletter\def\ttl@page@i#1[#2]#3{%
  \gdef\ttl@savemark{\csname#1mark\endcsname{#3}}%
  \def\ttl@savewrite{\ttl@write{#1}{#3}}%  A default value. Not #2!
  \def\ttl@savetitle{#3}%
  \ttl@labelling{#1}{#2}%
  \ttl@startargs\ttl@page@ii{#1}{#3}}

\clearpage导致处理标题的命令位于调用内部, 而\ttl@startargs\ttl@page@ii{#1}{#3}部分计数器在前一个调用中增加\ttl@labelling{#1}{#2}。切换这些命令的顺序可以解决问题,但我不知道是否还有其他后果。对我来说这似乎是一个错误。

第二次更新

关于为什么我需要这样做,有一些疑问\protect\thepage:这是因为\markright扩展了它的参数,但由于标准类每次重置标题的方式,这迫使我\markright在每个部分之后调用,因此使用扩展(不受保护)\thepart似乎可以解决问题。这是第二个,而不是退出的 MWE,它用来fancyhdr证明确实存在问题,并且它与保护无关:

\documentclass[oneside]{book}
\usepackage{titlesec}
\usepackage{fancyhdr}

% Now I can do this once and for all: no protection needed.
\chead{Part \thepart, page \thepage}

% If you do not issue the \titleformat command, everything is fine
\titleformat{\part}[display]
            {\bfseries\huge\filcenter}
            {\partname\ \thepart%
             % A working hack: set the mark here instead, expanding \thepart
             % (note the lack of \protect)
             %\markright{Part \thepart, page \protect\thepage} 
            }
            {20pt}
            {\Huge}
\titlespacing*{\part}{0pt}{*36}{*1}

\begin{document}
\pagestyle{fancy}
\part{Intro}

This page should have ``\textsl{Part \thepart, page \thepage}'' at the top.
\newpage
This page should have ``\textsl{Part \thepart, page \thepage}'' at the top.
\part{A Problem}                % This command does the incrementing

A new page
\end{document}

fancyhdr 和无保护问题演示

有关的

答案1

问题是,\part{A Problem}在第一部分的最后一页上执行,并且的值\thepart结尾当前页。由于您从该页开始新的部分,因此即使部分标题打印在下一页,您的部分计数器也会增加。解决方案是手动输入一个\newpage前页\part。这不会创建多余的空白页,因为\part只会插入空白页以到达右页。

编辑要自动插入每个部分接受的答案这个问题可用于。

\documentclass[oneside]{book}
\usepackage{titlesec}

% If you do not issue the \titleformat command, everything is fine
\titleformat{\part}[display]
            {\bfseries\huge\filcenter}
            {\partname\ \thepart%
             % A working hack: set the mark here instead, expanding \thepart
             % (note the lack of \protect)
             %\markright{Part \thepart, page \protect\thepage} 
            }
            {20pt}
            {\Huge}
\titlespacing*{\part}{0pt}{*36}{*1}

\let\oldpart\part
\renewcommand{\part}{\clearpage\oldpart}

\begin{document}
\part{Intro}
\pagestyle{myheadings}

% Remove this to see the hack work.
\markright{Part \protect\thepart, page \protect\thepage}

This page should have ``\textsl{Part \thepart, page \thepage}'' at the top.
\newpage
This page should have ``\textsl{Part \thepart, page \thepage}'' at the top.
\part{A Problem}                % This command does the incrementing
\end{document}

答案2

删除\protect之前的\thepart。标记机制依赖于标记时的扩展排放而不是在排版时。您正在保护它\thepart,因此它会在标题中展开,但此时值可能是错误的。另一方面,\thepage必须受到保护,因为它应该在排版标题时打印值,而不是在发出标记时打印值。

编辑出于同样的原因,\thepart不能直接在标题/页脚中使用(当然,如果您使用titleps,则可以,这会“隐藏”标记机制)。只需使用标记,这是将信息传递给标题的正确机制。请参阅下面的评论。

相关内容