
Этот вопрос состоит из двух связанных частей. Я уже решил исходную задачу, но все еще не понимаю, откуда она взялась или почему решение работает.
Я использую 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
на которой находится.
Это не имеет смысла, потому что подтаблица должна иметь абсолютно правильную ширину. Методом проб и ошибок я выяснил, что предупреждение появляется только тогда, когдавсевыполняются следующие три условия:
- Данная конструкция используется в приложении (т.е. после
\appendix
). - Пакет
cleveref
загружен. %
В конце строки нет\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.sty
2013/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}%
}%