Странное поведение \sbox

Странное поведение \sbox

Этот вопрос состоит из двух связанных частей. Я уже решил исходную задачу, но все еще не понимаю, откуда она взялась или почему решение работает.

Я использую subcaptionпакет, чтобы разместить две подтаблицы рядом друг с другом. Каждая подтаблица требует предполагаемой ширины, поэтому я дополнительно использую a, 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начал давать мне следующее предупреждение

Недозаполнение \hbox (плохость 10000) в абзаце на строках 24--25

где 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
    

    (В предупреждающих сообщениях могут отсутствовать пробелы.)

Нежелательное окончание строки cleveref.sty2013/03/22 v0.18.9 находится в определении \refstepcounter@noargs, строки 196 и 242.

Неполное правило

Вы просто забыли, что у блока может быть глубина. Поведение по умолчанию a tabular— базовая линия посередине. Но также с опцией [b]вы можете иметь обычно небольшую глубину, если последний элемент — обычная строка, а не \hline.

\raiseboxможет помочь создать глубину:

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

Связанный контент