\sbox 的奇怪行为

\sbox 的奇怪行为

这个问题由两个相关的部分组成。我已经解决了原始问题,但仍然不明白它从何而来,也不明白解决方案为何有效。

我使用subcaption包,这样我就可以把两个子表并排放置。每个子表都需要预期的宽度,因此我另外使用一个savebox来首先创建表,然后测量框的宽度以获得最佳子表宽度,最后但并非最不重要的是打印框的内容。

\newsavebox{\tablebox}
\sbox{\tablebox}{
  \begin{tabular}{ccc}
      1st & 2nd & 3rd \\
      1   & 2   & 3   \\
      4   & 5   & 6   \\
      7   & 8   & 9   \\
  \end{tabular}
}
% create fitting subtable
\begin{subtable}{\wd\tablebox}
  \usebox{\tablebox}
  \caption{Subable}
\end{subtable}

然而,pdflatex开始给我以下警告

段落第 24-25 行的 \hbox 未满(badness 10000)

其中 24 是所在的线\usebox

这毫无意义,因为子表应该具有完全正确的宽度。通过反复试验,我发现警告仅在以下情况下发生:全部以下三个条件之一成立:

  1. 给定的构造用于附录中(即之后\appendix)。
  2. 程序cleveref包已加载。
  3. %行尾没有\usebox

我不明白为什么这些会产生影响......

我在尝试找出错误时出现了第二个问题。我用\rule相同大小的表格替换了第二个表格,或者至少这是我试图实现的。虽然宽度 ( {\wd\tablebox}) 对我来说看起来不错,但替换的高度 ( {\ht\tablebox}) 是错误的。它太窄了。为什么?

最后,一个 MWE 演示了所有描述的效果。请注意,由于实际表格没有警告,但对于具有相同宽度的%替换有一个警告:\rule

\documentclass[english]{scrreprt}
\usepackage{babel}
\usepackage{subcaption}
\usepackage{cleveref}

\begin{document}
\appendix

\newsavebox{\tablebox}
\begin{table}
  % prepare table
  \sbox{\tablebox}{
    \begin{tabular}{ccc}
        1st & 2nd & 3rd \\
        1   & 2   & 3   \\
        4   & 5   & 6   \\
        7   & 8   & 9   \\
    \end{tabular}
  }
  % create fitting subtable
  \begin{subtable}{\wd\tablebox}
    \usebox{\tablebox}% no warning for this table
    \caption{Left Table}
  \end{subtable}
  %
  \hspace{2ex}
  %
  % create fitting subtable
  \begin{subtable}{\wd\tablebox}
    \rule{\wd\tablebox}{\ht\tablebox}
    \caption{Right Table}
  \end{subtable}

  \caption{Two Tables}
\end{table}

\end{document}

答案1

\hbox 未满

问题是cleveref设置了不需要的空格的包。该行以填充整行的对象开头。通常,以下\caption调用\par会结束上一段并删除进程中的最新空格。但是,如果\caption某些代码中有一个空格\cleveref中有一个空格,则只有段落末尾的空格会被删除。另一个空格会导致换行,并在新行的开头删除。但新行已经开始,而且很空,因此 LaTeX 会报错Underfull \hbox

普通 TeX 模型的示例:

\showboxdepth=1000
\showboxbreadth=1000
\tracingonline=1
\setbox0=\vbox{%
  \noindent
  \vrule height 1pt width \hsize\relax
  \space\space
}
\showbox0
\csname @@end\endcsname\end

TeX 打印警告:

Underfull \hbox (badness 10000) in paragraph at lines 5--8

\hbox(0.0+0.0)x469.75499
.\glue(\rightskip) 0.0

框 0 包含:

> \box0=
\vbox(13.0+0.0)x469.75499
.\hbox(1.0+0.0)x469.75499
..\rule(1.0+*)x469.75499
..\glue(\rightskip) 0.0
.\penalty 300
.\glue(\baselineskip) 12.0
.\hbox(0.0+0.0)x469.75499
..\glue(\rightskip) 0.0

! OK.
l.9 \showbox0

在垂直框 ( \vbox)内\noindent开始一个不带缩进的新段落。在框的末尾,TeX 结束段落(隐式\par)。然后 TeX 删除最后一个空格(隐式\unskip)以删除最后一个空格。在本例中是第二个空格\space,并改为添加空格\parfillskip。然后,拆分前的段落包含:

<\vrule ...> <\space> <\hskip\parfillskip>

该规则填充整行,因此 TeX 会在规则之后的空格之前断开行。新行开头的空格会被删除,因此 和 都会 <\space><\hskip\parfillskip>删除。该行仅包含自动插入的\rightskip,不包含可拉伸组件,请参见警告框:

\hbox(0.0+0.0)x469.75499
.\glue(\rightskip) 0.0

因此,盒子里不包含任何可以填充该线的东西,该线是未满

解决方法:

  • 注释行尾(您已经找到它)。
  • \par在最后,后续空格在垂直模式下将被忽略。
  • 加载cleveref方式:

    \edef\RestoreEndlinechar{\endlinechar=\the\endlinechar\relax}
    \endlinechar=-1 %
    \usepackage{cleveref}
    \RestoreEndlinechar
    

    (警告信息中的空格可能缺失。)

2013/03/22 v0.18.9的不需要的行结尾cleveref.sty位于 的定义中\refstepcounter@noargs,第 196 行和 242 行。

不完整规则

您只是忘记了,一个框可以有深度。 的默认行为tabular是中间的基线。 但是,如果最后一个元素是普通行而不是,[b]您也可以使用选项获得通常较小的深度。\hline

\raisebox有助于创造深度:

    \raisebox{-\dp\tablebox}{%
      \rule{\wd\tablebox}{\dimexpr\ht\tablebox+\dp\tablebox\relax}%
    }%

相关内容