Вертикальное выравнивание в таблице: m-столбец, размер строки - проблема в последнем столбце

Вертикальное выравнивание в таблице: m-столбец, размер строки - проблема в последнем столбце

К сожалению, у меня проблема сm-столбцы( arrayпакет) в таблицах сотрегулированная высота строки. Каким-то образом впоследний столбец(только там) текст естьне по центрувертикально.

Проверьте это:

введите описание изображения здесь

\documentclass{article}
\usepackage{array}

\begin{document}

\begin{tabular}{|m{0.18cm}|m{0.18cm}|m{0.18cm}|}
\hline
a & b & c  \\[2ex]
\hline
0 & 0 & 0  \\
\hline
\end{tabular}

\end{document}

решение1

По моему мнению, это ошибка, и о ней следует сообщить. Исправление для нетерпеливых: добавьте один дополнительный столбец с нулевой шириной и без отступа. Не забудьте добавить prepend \\with &в проблемных строках!

\documentclass{article}
\usepackage{array}

\begin{document}

\begin{tabular}{|m{0.18cm}|m{0.18cm}|m{0.18cm}|@{}m{0pt}@{}}
\hline
a & b & c &\\[2ex]
\hline
0 & 0 & 0 \\
\hline
\end{tabular}

\end{document}

решение2

Вопрос, а также ответ @tohecz указывают на то, что существует по крайней мере одно фундаментальное заблуждение относительно того, что делают токены преамбулы «m», «b» и т. д. и как это связано с \\их необязательным аргументом.

Маркер "m"не являетсяцентрируя материал вертикально в доступном пространстве!

Токены "c", "l" и "r" создают горизонтальные ячейки (высотой в одну строку), а их точка выравнивания по вертикали — это просто базовая линия каждой ячейки. Теперь "p", "m" и "b" создают ячейки определенной ширины и, возможно, нескольких строк. Их вертикальное выравнивание — это первая строка, середина поля и нижняя строка соответственно. Так что если мы немного изменим пример и запустим:

\begin{tabular}{|p{0.18cm}|m{0.18cm}|b{0.18cm}|l|}
\hline
a\newline a & b\newline b & c\newline c\newline c& d \\
\hline
\end{tabular}

и что мы получаем, это

введите описание изображения здесь

Итак, все это позиционируется относительно базовой линии ячейки, содержащей «d».

Теперь необязательный аргумент \\расширяет пространство только от точки выравнивания вниз, этонетрасширение размера фактических ячеек. Более того, это не фактическое добавление этого пространства, а только обеспечение того, чтобы было по крайней мере столько же места до следующей строки. Так, например, в приведенном выше случае \\[2ex]не будет никакого эффекта, потому что ячейка в первом столбце идет дальше вниз, чем эта.

Итак, возвращаясь к исходному вопросу и его вводу: поскольку каждая ячейка имеет только одну линию, они все должны выстроиться в линию, но «м» будетнетимеют эффект центрирования контента в доступном пространстве. Вместо этого дополнительное пространство, запрошенное , \\[2ex]будет идти после него (или должно идти ... это ошибка).

Давайте добавим столбец «l», чтобы избежать ошибки, и посмотрим, что произойдет:

\begin{tabular}{|m{0.18cm}|m{0.18cm}|m{0.18cm}|l|}
\hline
a & b & c & d \\[2ex]
\hline
a\newline a & b & c & d \\[2ex]
\hline
\end{tabular}

Результат есть

введите описание изображения здесь

Первая строка показывает, что «m» и «l» располагаются рядом, если внутри «m» только одна линия, а 2ex находится между базовой линией и следующей строкой.

Во второй строке есть «m» с 2 линиями внутри, и здесь вы снова видите, что 2ex идет от базовой линии строки к следующей строке, а «m» также не отцентрирован по вертикали.

Поэтому предложение использовать дополнительную (своего рода скрытую строку) вроде

\begin{tabular}{|m{0.18cm}|m{0.18cm}|m{0.18cm}|@{}m{0pt}@{}}
\hline
a & b & c &             x\\[4ex]   % x normally being a space
\hline
a\newline a & b & c &   x\\[4ex]
\hline
\end{tabular}

на самом деле использует текущую ошибку, то есть «пробел» в этом скрытом вопросе на самом деле сдвинут вверх, так что видимые строки теперь кажутся более или менее центрированными (что я сделал видимым, поставив «x» выше):

введите описание изображения здесь

Так что как только это будет исправлено, вышеуказанный трюк больше не будет работать.

Так в чем же ошибка?

Проблема очень тонкая. Чтобы заставить работать таблицу с правилами, невозможно вертикально пропустить вниз на \\[2ex], вместо этого в одной из строк размещается невидимое правило/ящик, глубина которого превышает обычную глубину на 2ex. Если этого не сделать, то любое вертикальное правило будет нарушено в местах, где вы добавляете дополнительное вертикальное пространство.

Недостатком этого является то, что если строка имеет необычную глубину, любое такое дополнительное пространство может оказаться коротким, поскольку оно измеряется по отношению к «нормальной» глубине.

В дополнение, и это "баг" в arrayразмещении этой невидимой распорки в конце материала в последней строке, просто идет не так для m-колонок, поскольку они вертикально центрированы. Таким образом, здесь вы видите, что "c" движется вверх, поскольку распорка заканчивается в чем-то вроде $\vcenter{... c \strut}$вместо $\vcenter{... c}$\strut.

Причиной этого является странное поведение базового \halignмеханизма TeX, который используется для построения таблиц: когда мы достигаем \\[2ex]LaTeX, он обработал $\vcenter{... c, но еще не увидел оставшийся материал, образующий столбец, т. е. }$.

Итак, \\[ex]вычисляем и добавляем распорку, а затем сообщаем TeX, что столбец завершен (используется \crвнутренне), и это приводит к тому, что TeX копирует оставшуюся часть шаблона столбца ( }$...плюс пробел и линейку) во входной поток, и вуаля, в итоге вы получаете распорку внутри vcenter.

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

\documentclass{article}
\usepackage{array}

\makeatletter
\def\@classz{\@classx
   \@tempcnta \count@
   \prepnext@tok
   \@addtopreamble{\ifcase \@chnum
      \hfil
      \d@llarbegin
      \insert@column
      \d@llarend\fmi@fix \hfil \or
      \hskip1sp\d@llarbegin \insert@column \d@llarend\fmi@fix \hfil \or
      \hfil\hskip1sp\d@llarbegin \insert@column \d@llarend\fmi@fix \or
   $\vcenter
   \@startpbox{\@nextchar}\insert@column \@endpbox $\fmi@fix
    \or
   \vtop \@startpbox{\@nextchar}\insert@column \@endpbox\fmi@fix \or
   \vbox \@startpbox{\@nextchar}\insert@column \@endpbox\fmi@fix
  \fi}\prepnext@tok}

\def\@mkpream#1{\gdef\@preamble{}\@lastchclass 4 \@firstamptrue
   \let\@sharp\relax \let\@startpbox\relax \let\@endpbox\relax
   \let\fmi@fix\relax
   \@temptokena{#1}\@tempswatrue
   \@whilesw\if@tempswa\fi{\@tempswafalse\the\NC@list}%
   \count@\m@ne
   \let\the@toks\relax
   \prepnext@tok
   \expandafter \@tfor \expandafter \@nextchar
    \expandafter :\expandafter =\the\@temptokena \do
   {\@testpach
   \ifcase \@chclass \@classz \or \@classi \or \@classii
     \or \save@decl \or \or \@classv \or \@classvi
     \or \@classvii \or \@classviii
     \or \@classx
     \or \@classx \fi
   \@lastchclass\@chclass}%
   \ifcase\@lastchclass
   \@acol \or
   \or
   \@acol \or
   \@preamerr \thr@@ \or
   \@preamerr \tw@ \@addtopreamble\@sharp \or
   \or
   \else  \@preamerr \@ne \fi
   \def\the@toks{\the\toks}}   


\def\@xargarraycr#1{\gdef\fmi@fix
 {\@tempdima #1\advance\@tempdima \dp\@arstrutbox
  \vrule \@depth\@tempdima \@width\z@\global\let\fmi@fix\relax}\cr}
\let\fmi@fix\relax

\makeatother

\begin{document}

\begin{tabular}{|m{0.18cm}|m{0.18cm}|}
\hline
a&c \\[2ex]
\hline
0& 0  \\
\hline
\end{tabular}

\end{document}

Как я уже сказал, это довольно деликатный вопрос, поэтому я не уверен, что безопасно вносить такие изменения, не сломав при этом много чего другого (в конце концов, arrayэто действительно старый пакет (более 25 лет), который используется довольно часто, и эта проблема присутствует с самого начала).

В любом случае, с учетом вышеуказанных изменений мы теперь получаем:

введите описание изображения здесь

это то, что нам следовало бы сделать, но, возможно, не то, на что надеялись люди, когда думали, что указывают столбец «m».

Обновлять

Начиная с версии LaTeX 2018-04 (или даже на одну версию раньше) фактическая ошибка была исправлена, как указано выше. Это означает (к сожалению), что предложенный выше трюк, отмеченный как правильный ответ, больше не работает, но, как я объяснил, он был основан на неправильном предположении о том, что такое спецификация "m".

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